vdm.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 125k
Category:

Windows Develop

Development Platform:

Visual C++

  1. /*++
  2. Copyright (c) 1990  Microsoft Corporation
  3. Module Name:
  4.     vdm.c
  5. Abstract:
  6.     This module implements Win32 APIs for VDMs
  7. Author:
  8.     Sudeepb Bharati (sudeepb) 04-Sep-1991
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "apcompat.h"
  13. #pragma hdrstop
  14. BOOL
  15. APIENTRY
  16. GetBinaryTypeA(
  17.     IN  LPCSTR   lpApplicationName,
  18.     OUT LPDWORD  lpBinaryType
  19.     )
  20. /*++
  21. Routine Description: ANSI version of GetBinaryTypeW.
  22.     This API returns the binary type of lpApplicationName.
  23. Arguments:
  24.     lpApplicationName - Full pathname of the binary
  25.     lpBinaryType - pointer where binary type will be returned.
  26. Return Value:
  27.     TRUE - if SUCCESS; lpBinaryType has following
  28.                 SCS_32BIT_BINARY    - Win32 Binary (NT or Chicago)
  29.                 SCS_DOS_BINARY      - DOS Binary
  30.                 SCS_WOW_BINARY      - Windows 3.X Binary
  31.                 SCS_PIF_BINARY      - PIF file
  32.                 SCS_POSIX_BINARY    - POSIX Binary
  33.                 SCS_OS216_BINARY    - OS/2 Binary
  34.     FALSE - if file not found or of unknown type. More info with GetLastError
  35. --*/
  36. {
  37.     NTSTATUS Status;
  38.     PUNICODE_STRING CommandLine;
  39.     ANSI_STRING AnsiString;
  40.     UNICODE_STRING DynamicCommandLine;
  41.     BOOLEAN bReturn = FALSE;
  42.     CommandLine = &NtCurrentTeb()->StaticUnicodeString;
  43.     RtlInitAnsiString(&AnsiString,lpApplicationName);
  44.     if ( (ULONG)AnsiString.Length<<1 < (ULONG)NtCurrentTeb()->StaticUnicodeString.MaximumLength ) {
  45.         DynamicCommandLine.Buffer = NULL;
  46.         Status = RtlAnsiStringToUnicodeString(CommandLine,&AnsiString,FALSE);
  47.         if ( !NT_SUCCESS(Status) ) {
  48.             BaseSetLastNTError(Status);
  49.             return FALSE;
  50.             }
  51.         }
  52.     else {
  53.         Status = RtlAnsiStringToUnicodeString(&DynamicCommandLine,&AnsiString,TRUE);
  54.         if ( !NT_SUCCESS(Status) ) {
  55.             BaseSetLastNTError(Status);
  56.             return FALSE;
  57.             }
  58.         }
  59.     bReturn = (BOOLEAN)GetBinaryTypeW(
  60.              DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer : CommandLine->Buffer,
  61.              lpBinaryType);
  62.     RtlFreeUnicodeString(&DynamicCommandLine);
  63.     return((BOOL)bReturn);
  64. }
  65. BOOL
  66. WINAPI
  67. GetBinaryTypeW(
  68.     IN  LPCWSTR  lpApplicationName,
  69.     OUT LPDWORD  lpBinaryType
  70.     )
  71. /*++
  72. Routine Description: Unicode version.
  73.     This API returns the binary type of lpApplicationName.
  74. Arguments:
  75.     lpApplicationName - Full pathname of the binary
  76.     lpBinaryType - pointer where binary type will be returned.
  77. Return Value:
  78.     TRUE - if SUCCESS; lpBinaryType has following
  79.                 SCS_32BIT_BINARY    - Win32 Binary (NT or Chicago)
  80.                 SCS_DOS_BINARY      - DOS Binary
  81.                 SCS_WOW_BINARY      - Windows 3.X Binary
  82.                 SCS_PIF_BINARY      - PIF file
  83.                 SCS_POSIX_BINARY    - POSIX Binary
  84.                 SCS_OS216_BINARY    - OS/2 Binary
  85.     FALSE - if file not found or of unknown type. More info with GetLastError
  86. --*/
  87. {
  88.     NTSTATUS Status;
  89.     UNICODE_STRING PathName;
  90.     RTL_RELATIVE_NAME RelativeName;
  91.     BOOLEAN TranslationStatus;
  92.     OBJECT_ATTRIBUTES Obja;
  93.     PVOID FreeBuffer = NULL;
  94.     HANDLE FileHandle, SectionHandle=NULL;
  95.     IO_STATUS_BLOCK IoStatusBlock;
  96.     LONG fBinaryType = SCS_32BIT_BINARY;
  97.     BOOLEAN bReturn = FALSE;
  98.     SECTION_IMAGE_INFORMATION ImageInformation;
  99.     try {
  100.         //
  101.         // Translate to an NT name.
  102.         //
  103.         TranslationStatus = RtlDosPathNameToNtPathName_U(
  104.                                 // DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer : CommandLine->Buffer,
  105.                                 lpApplicationName,
  106.                                 &PathName,
  107.                                 NULL,
  108.                                 &RelativeName
  109.                                 );
  110.         if ( !TranslationStatus ) {
  111.             BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  112.             goto GBTtryexit;
  113.             }
  114.         FreeBuffer = PathName.Buffer;
  115.         if ( RelativeName.RelativeName.Length ) {
  116.             PathName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  117.             }
  118.         else {
  119.             RelativeName.ContainingDirectory = NULL;
  120.             }
  121.         InitializeObjectAttributes(
  122.             &Obja,
  123.             &PathName,
  124.             OBJ_CASE_INSENSITIVE,
  125.             RelativeName.ContainingDirectory,
  126.             NULL
  127.             );
  128.         //
  129.         // Open the file for execute access
  130.         //
  131.         Status = NtOpenFile(
  132.                     &FileHandle,
  133.                     SYNCHRONIZE | FILE_EXECUTE,
  134.                     &Obja,
  135.                     &IoStatusBlock,
  136.                     FILE_SHARE_READ | FILE_SHARE_DELETE,
  137.                     FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  138.                     );
  139.         if (!NT_SUCCESS(Status) ) {
  140.             BaseSetLastNTError(Status);
  141.             goto GBTtryexit;
  142.             }
  143.         //
  144.         // Create a section object backed by the file
  145.         //
  146.         Status = NtCreateSection(
  147.                     &SectionHandle,
  148.                     SECTION_ALL_ACCESS,
  149.                     NULL,
  150.                     NULL,
  151.                     PAGE_EXECUTE,
  152.                     SEC_IMAGE,
  153.                     FileHandle
  154.                     );
  155.         NtClose(FileHandle);
  156.         if (!NT_SUCCESS(Status) ) {
  157.             SectionHandle = NULL;
  158.             switch (Status) {
  159.                 case STATUS_INVALID_IMAGE_NE_FORMAT:
  160. #ifdef i386
  161.                     fBinaryType = SCS_OS216_BINARY;
  162.                     break;
  163. #endif
  164.                 case STATUS_INVALID_IMAGE_PROTECT:
  165.                     fBinaryType = SCS_DOS_BINARY;
  166.                     break;
  167.                 case STATUS_INVALID_IMAGE_WIN_16:
  168.                     fBinaryType = SCS_WOW_BINARY;
  169.                     break;
  170.                 case STATUS_INVALID_IMAGE_NOT_MZ:
  171.                     fBinaryType = BaseIsDosApplication(&PathName, Status);
  172.                     if (!fBinaryType){
  173.                         BaseSetLastNTError(Status);
  174.                         goto GBTtryexit;
  175.                     }
  176.                     fBinaryType = (fBinaryType  == BINARY_TYPE_DOS_PIF) ?
  177.                                   SCS_PIF_BINARY : SCS_DOS_BINARY;
  178.                     break;
  179.                 default:
  180.                     BaseSetLastNTError(Status);
  181.                     goto GBTtryexit;
  182.                 }
  183.             }
  184.         else {
  185.             //
  186.             // Query the section
  187.             //
  188.             Status = NtQuerySection(
  189.                         SectionHandle,
  190.                         SectionImageInformation,
  191.                         &ImageInformation,
  192.                         sizeof( ImageInformation ),
  193.                         NULL
  194.                         );
  195.             if (!NT_SUCCESS( Status )) {
  196.                 BaseSetLastNTError(Status);
  197.                 goto GBTtryexit;
  198.             }
  199.             if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) {
  200.                 SetLastError(ERROR_BAD_EXE_FORMAT);
  201.                 goto GBTtryexit;
  202.             }
  203.             if (ImageInformation.Machine !=
  204.                     RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress)->FileHeader.Machine) {
  205. #ifdef MIPS
  206.                 if ( ImageInformation.Machine == IMAGE_FILE_MACHINE_R3000 ||
  207.                      ImageInformation.Machine == IMAGE_FILE_MACHINE_R4000 ) {
  208.                     ;
  209.                 }
  210.                 else {
  211.                     SetLastError(ERROR_BAD_EXE_FORMAT);
  212.                     goto GBTtryexit;
  213.                 }
  214. #else
  215.                 SetLastError(ERROR_BAD_EXE_FORMAT);
  216.                 goto GBTtryexit;
  217. #endif // MIPS
  218.             }
  219.             if ( ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI &&
  220.                 ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI ) {
  221.                 if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_POSIX_CUI ) {
  222.                     fBinaryType = SCS_POSIX_BINARY;
  223.                 }
  224.             }
  225.         }
  226.         *lpBinaryType = fBinaryType;
  227.         bReturn = TRUE;
  228. GBTtryexit:;
  229.         }
  230.     finally {
  231.         if (SectionHandle)
  232.             NtClose(SectionHandle);
  233.         if (FreeBuffer)
  234.             RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  235.     }
  236.     return bReturn;
  237. }
  238. VOID
  239. APIENTRY
  240. VDMOperationStarted
  241. (
  242.     BOOL    IsWowCaller
  243.     )
  244. /*++
  245. Routine Description:
  246.     This routine is used by MVDM to tell base that it has hooked
  247.     ctrl-c handler with console. If the cmd window is killed
  248.     before VDM could hook ctrl-c, then we wont get a chance to
  249.     cleanup our data structures. The absence of this call tells
  250.     base that it has to clean up the resources next time a
  251.     call is made to create a VDM.
  252. Arguments:
  253.     IsWowCaller - TRUE if the caller is WOWVDM
  254. Return Value:
  255.     None
  256. --*/
  257. {
  258.     BaseUpdateVDMEntry(UPDATE_VDM_HOOKED_CTRLC,
  259.                        NULL,
  260.                        0,
  261.                        IsWowCaller);
  262.     return;
  263. }
  264. BOOL
  265. APIENTRY
  266. GetNextVDMCommand(
  267.     PVDMINFO lpVDMInfo
  268.     )
  269. /*++
  270. Routine Description:
  271.     This routine is used by MVDM to get a new command to execute. The
  272.     VDM is blocked untill a DOS/WOW binary is encountered.
  273. Arguments:
  274.     lpVDMInfo - pointer to VDMINFO where new DOS command and other
  275.                 enviornment information is returned.
  276.     if lpVDMInfo is NULL, then the caller is
  277.     asking whether its the first VDM in the system.
  278. Return Value:
  279.     TRUE - The operation was successful. lpVDMInfo is filled in.
  280.     FALSE/NULL - The operation failed.
  281. --*/
  282. {
  283.     NTSTATUS Status;
  284.     BASE_API_MSG m;
  285.     PBASE_GET_NEXT_VDM_COMMAND_MSG a = (PBASE_GET_NEXT_VDM_COMMAND_MSG)&m.u.GetNextVDMCommand;
  286.     PBASE_EXIT_VDM_MSG c= (PBASE_EXIT_VDM_MSG)&m.u.ExitVDM;
  287.     PBASE_IS_FIRST_VDM_MSG d= (PBASE_IS_FIRST_VDM_MSG)&m.u.IsFirstVDM;
  288.     PBASE_SET_REENTER_COUNT_MSG e = (PBASE_SET_REENTER_COUNT_MSG)&m.u.SetReenterCount;
  289.     PCSR_CAPTURE_HEADER CaptureBuffer;
  290.     ULONG Len,nPointers;
  291.     USHORT VDMStateSave;
  292.     // Special case to query the first VDM In the system.
  293.     if(lpVDMInfo == NULL){
  294.         Status = CsrClientCallServer(
  295.                           (PCSR_API_MSG)&m,
  296.                           NULL,
  297.                           CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  298.                                               BasepIsFirstVDM
  299.                                               ),
  300.                           sizeof( *d )
  301.                           );
  302.         if (NT_SUCCESS(Status)) {
  303.             return(d->FirstVDM);
  304.             }
  305.         else {
  306.             BaseSetLastNTError(Status);
  307.             return FALSE;
  308.             }
  309.         }
  310.     // Special case to increment/decrement the re-enterancy count
  311.     if (lpVDMInfo->VDMState == INCREMENT_REENTER_COUNT ||
  312.         lpVDMInfo->VDMState == DECREMENT_REENTER_COUNT) {
  313.         e->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  314.         e->fIncDec = lpVDMInfo->VDMState;
  315.         Status = CsrClientCallServer(
  316.                         (PCSR_API_MSG)&m,
  317.                         NULL,
  318.                         CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  319.                                              BasepSetReenterCount
  320.                                            ),
  321.                         sizeof( *e )
  322.                        );
  323.         if (NT_SUCCESS(Status)) {
  324.             return TRUE;
  325.             }
  326.         else {
  327.             BaseSetLastNTError(Status);
  328.             return FALSE;
  329.             }
  330.     }
  331.     VDMStateSave = lpVDMInfo->VDMState;
  332.     // console handle is always passed on in this case
  333.     // wow is differentiated by a parameter a->VDMState
  334.     // a->VDMState & ASKING_FOR_WOW_BINARY indicates wow
  335.     a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  336.     if (lpVDMInfo->VDMState & ASKING_FOR_PIF) {
  337.        a->iTask = lpVDMInfo->iTask;
  338.     }
  339.     else {
  340.        a->iTask = 0;
  341.     }
  342.     a->AppLen = lpVDMInfo->AppLen;
  343.     a->PifLen = lpVDMInfo->PifLen;
  344.     a->CmdLen = lpVDMInfo->CmdSize;
  345.     a->EnvLen = lpVDMInfo->EnviornmentSize;
  346.     a->ExitCode = lpVDMInfo->ErrorCode;
  347.     a->VDMState = VDMStateSave;
  348.     a->WaitObjectForVDM = 0;
  349.     a->DesktopLen = lpVDMInfo->DesktopLen;
  350.     a->TitleLen = lpVDMInfo->TitleLen;
  351.     a->ReservedLen = lpVDMInfo->ReservedLen;
  352.     a->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
  353.     // Find the total space for capture buffer
  354.       // startup info
  355.     Len = ROUND_UP(sizeof(STARTUPINFOA),4);
  356.     nPointers = 1;
  357.     if (lpVDMInfo->CmdSize) {
  358.         Len += ROUND_UP(a->CmdLen,4);
  359.         nPointers++;
  360.         }
  361.     if (lpVDMInfo->AppLen) {
  362.         Len +=ROUND_UP(a->AppLen,4);
  363.         nPointers++;
  364.         }
  365.     if (lpVDMInfo->PifLen) {
  366.         Len +=ROUND_UP(a->PifLen,4);
  367.         nPointers++;
  368.         }
  369.     if (lpVDMInfo->Enviornment) {
  370.         nPointers++;
  371.         Len+= (lpVDMInfo->EnviornmentSize) ?
  372.                      ROUND_UP(lpVDMInfo->EnviornmentSize, 4) : 4;
  373.         }
  374.     if (lpVDMInfo->CurDirectoryLen == 0)
  375.         a->CurDirectory = NULL;
  376.     else{
  377.         Len += ROUND_UP(lpVDMInfo->CurDirectoryLen,4);
  378.         nPointers++;
  379.         }
  380.     if (lpVDMInfo->DesktopLen == 0)
  381.         a->Desktop = NULL;
  382.     else {
  383.         Len += ROUND_UP(lpVDMInfo->DesktopLen,4);
  384.         nPointers++;
  385.         }
  386.     if (lpVDMInfo->TitleLen == 0)
  387.         a->Title = NULL;
  388.     else {
  389.         Len += ROUND_UP(lpVDMInfo->TitleLen,4);
  390.         nPointers++;
  391.         }
  392.     if (lpVDMInfo->ReservedLen == 0)
  393.         a->Reserved = NULL;
  394.     else {
  395.         Len += ROUND_UP(lpVDMInfo->ReservedLen,4);
  396.         nPointers++;
  397.         }
  398.     CaptureBuffer = CsrAllocateCaptureBuffer(nPointers, Len);
  399.     if (CaptureBuffer == NULL) {
  400.         BaseSetLastNTError( STATUS_NO_MEMORY );
  401.         return FALSE;
  402.         }
  403.     if (lpVDMInfo->CmdLine) {
  404.         CsrAllocateMessagePointer( CaptureBuffer,
  405.                                    lpVDMInfo->CmdSize,
  406.                                    (PVOID *)&a->CmdLine
  407.                                  );
  408.         }
  409.     else {
  410.         a->CmdLine = NULL;
  411.         }
  412.     if (lpVDMInfo->AppLen) {
  413.         CsrAllocateMessagePointer( CaptureBuffer,
  414.                                    lpVDMInfo->AppLen,
  415.                                    (PVOID *)&a->AppName
  416.                                  );
  417.         }
  418.     else {
  419.         a->AppName = NULL;
  420.         }
  421.     if (lpVDMInfo->PifLen) {
  422.         CsrAllocateMessagePointer( CaptureBuffer,
  423.                                    lpVDMInfo->PifLen,
  424.                                    (PVOID *)&a->PifFile
  425.                                  );
  426.         }
  427.     else {
  428.         a->PifFile = NULL;
  429.         }
  430.     if (lpVDMInfo->EnviornmentSize) {
  431.         CsrAllocateMessagePointer( CaptureBuffer,
  432.                                    lpVDMInfo->EnviornmentSize,
  433.                                    (PVOID *)&a->Env
  434.                                  );
  435.         }
  436.     else {
  437.         a->Env = NULL;
  438.         }
  439.     if (lpVDMInfo->CurDirectoryLen)
  440.         CsrAllocateMessagePointer( CaptureBuffer,
  441.                                    lpVDMInfo->CurDirectoryLen,
  442.                                    (PVOID *)&a->CurDirectory
  443.                                  );
  444.     else
  445.         a->CurDirectory = NULL;
  446.     CsrAllocateMessagePointer( CaptureBuffer,
  447.                                sizeof(STARTUPINFOA),
  448.                                (PVOID *)&a->StartupInfo
  449.                              );
  450.     if (lpVDMInfo->DesktopLen)
  451.         CsrAllocateMessagePointer( CaptureBuffer,
  452.                                    lpVDMInfo->DesktopLen,
  453.                                    (PVOID *)&a->Desktop
  454.                                  );
  455.     else
  456.         a->Desktop = NULL;
  457.     if (lpVDMInfo->TitleLen)
  458.         CsrAllocateMessagePointer( CaptureBuffer,
  459.                                    lpVDMInfo->TitleLen,
  460.                                    (PVOID *)&a->Title
  461.                                  );
  462.     else
  463.         a->Title = NULL;
  464.     if (lpVDMInfo->ReservedLen)
  465.         CsrAllocateMessagePointer( CaptureBuffer,
  466.                                    lpVDMInfo->ReservedLen,
  467.                                    (PVOID *)&a->Reserved
  468.                                  );
  469.     else
  470.         a->Reserved = NULL;
  471. retry:
  472.     Status = CsrClientCallServer(
  473.                         (PCSR_API_MSG)&m,
  474.                         CaptureBuffer,
  475.                         CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  476.                                             BasepGetNextVDMCommand
  477.                                            ),
  478.                         sizeof( *a )
  479.                         );
  480.     if (a->WaitObjectForVDM) {
  481.         Status = NtWaitForSingleObject(a->WaitObjectForVDM,FALSE,NULL);
  482.         if (Status != STATUS_SUCCESS){
  483.             BaseSetLastNTError(Status);
  484.             return FALSE;
  485.             }
  486.         else {
  487.             a->VDMState |= ASKING_FOR_SECOND_TIME;
  488.             a->ExitCode = 0;
  489.             goto retry;
  490.             }
  491.         }
  492.     if (NT_SUCCESS(Status)) {
  493.         Status = (NTSTATUS)m.ReturnValue;
  494.         }
  495.     if (!NT_SUCCESS( Status )) {
  496.         if (Status == STATUS_INVALID_PARAMETER) {
  497.             //This means one of the buffer size is less than required.
  498.             lpVDMInfo->CmdSize = a->CmdLen;
  499.             lpVDMInfo->AppLen = a->AppLen;
  500.             lpVDMInfo->PifLen = a->PifLen;
  501.             lpVDMInfo->EnviornmentSize = a->EnvLen;
  502.             lpVDMInfo->CurDirectoryLen = a->CurDirectoryLen;
  503.             lpVDMInfo->DesktopLen      = a->DesktopLen;
  504.             lpVDMInfo->TitleLen        = a->TitleLen;
  505.             lpVDMInfo->ReservedLen     = a->ReservedLen;
  506.             }
  507.         else {
  508.             lpVDMInfo->CmdSize = 0;
  509.             lpVDMInfo->AppLen = 0;
  510.             lpVDMInfo->PifLen = 0;
  511.             lpVDMInfo->EnviornmentSize = 0;
  512.             lpVDMInfo->CurDirectoryLen = 0;
  513.             lpVDMInfo->DesktopLen      = 0;
  514.             lpVDMInfo->TitleLen        = 0;
  515.             lpVDMInfo->ReservedLen     = 0;
  516.             }
  517.         CsrFreeCaptureBuffer( CaptureBuffer );
  518.         BaseSetLastNTError(Status);
  519.         return FALSE;
  520.     }
  521.     try {
  522.         if (lpVDMInfo->CmdSize)
  523.             RtlMoveMemory(lpVDMInfo->CmdLine,
  524.                           a->CmdLine,
  525.                           a->CmdLen);
  526.         if (lpVDMInfo->AppLen)
  527.             RtlMoveMemory(lpVDMInfo->AppName,
  528.                           a->AppName,
  529.                           a->AppLen);
  530.         if (lpVDMInfo->PifLen)
  531.             RtlMoveMemory(lpVDMInfo->PifFile,
  532.                           a->PifFile,
  533.                           a->PifLen);
  534.         if (lpVDMInfo->Enviornment)
  535.             RtlMoveMemory(lpVDMInfo->Enviornment,
  536.                           a->Env,
  537.                           a->EnvLen);
  538.         if (lpVDMInfo->CurDirectoryLen)
  539.             RtlMoveMemory(lpVDMInfo->CurDirectory,
  540.                           a->CurDirectory,
  541.                           a->CurDirectoryLen);
  542.         if (a->VDMState & STARTUP_INFO_RETURNED)
  543.             RtlMoveMemory(&lpVDMInfo->StartupInfo,
  544.                           a->StartupInfo,
  545.                           sizeof(STARTUPINFOA));
  546.         if (lpVDMInfo->DesktopLen){
  547.             RtlMoveMemory(lpVDMInfo->Desktop,
  548.                           a->Desktop,
  549.                           a->DesktopLen);
  550.             lpVDMInfo->StartupInfo.lpDesktop = lpVDMInfo->Desktop;
  551.         }
  552.         if (lpVDMInfo->TitleLen){
  553.             RtlMoveMemory(lpVDMInfo->Title,
  554.                           a->Title,
  555.                           a->TitleLen);
  556.             lpVDMInfo->StartupInfo.lpTitle = lpVDMInfo->Title;
  557.         }
  558.         if (lpVDMInfo->ReservedLen){
  559.             RtlMoveMemory(lpVDMInfo->Reserved,
  560.                           a->Reserved,
  561.                           a->ReservedLen);
  562.             lpVDMInfo->StartupInfo.lpReserved = lpVDMInfo->Reserved;
  563.         }
  564.         lpVDMInfo->CmdSize = a->CmdLen;
  565.         lpVDMInfo->AppLen = a->AppLen;
  566.         lpVDMInfo->PifLen = a->PifLen;
  567.         lpVDMInfo->EnviornmentSize = a->EnvLen;
  568.         if (a->VDMState & STARTUP_INFO_RETURNED)
  569.             lpVDMInfo->VDMState = STARTUP_INFO_RETURNED;
  570.         else
  571.             lpVDMInfo->VDMState = 0;
  572.         lpVDMInfo->CurDrive = a->CurrentDrive;
  573.         lpVDMInfo->StdIn  = a->StdIn;
  574.         lpVDMInfo->StdOut = a->StdOut;
  575.         lpVDMInfo->StdErr = a->StdErr;
  576.         lpVDMInfo->iTask = a->iTask;
  577.         lpVDMInfo->CodePage = a->CodePage;
  578.         lpVDMInfo->CurDirectoryLen = a->CurDirectoryLen;
  579.         lpVDMInfo->DesktopLen = a->DesktopLen;
  580.         lpVDMInfo->TitleLen = a->TitleLen;
  581.         lpVDMInfo->ReservedLen = a->ReservedLen;
  582.         lpVDMInfo->dwCreationFlags = a->dwCreationFlags;
  583.         lpVDMInfo->fComingFromBat = a->fComingFromBat;
  584.         CsrFreeCaptureBuffer( CaptureBuffer );
  585.         return TRUE;
  586.         }
  587.     except ( EXCEPTION_EXECUTE_HANDLER ) {
  588.         BaseSetLastNTError(GetExceptionCode());
  589.         CsrFreeCaptureBuffer( CaptureBuffer );
  590.         return FALSE;
  591.         }
  592. }
  593. VOID
  594. APIENTRY
  595. ExitVDM(
  596.     BOOL IsWowCaller,
  597.     ULONG iWowTask
  598.     )
  599. /*++
  600. Routine Description:
  601.     This routine is used by MVDM to exit.
  602. Arguments:
  603.     IsWowCaller - TRUE if the caller is WOWVDM.
  604.                   FALSE if the caller is DOSVDM
  605.                   This parameter is obsolete as basesrv knows about the kind
  606.                   of vdm that is calling us
  607.     iWowTask - if IsWowCaller == FALSE then Dont Care
  608.              - if IsWowCaller == TRUE && iWowTask != -1 kill iWowTask task
  609.              - if IsWowCaller == TRUE && iWowTask == -1 kill all wow task
  610. Return Value:
  611.     None
  612. --*/
  613. {
  614.     NTSTATUS Status;
  615.     BASE_API_MSG m;
  616.     PBASE_EXIT_VDM_MSG c= (PBASE_EXIT_VDM_MSG)&m.u.ExitVDM;
  617.     c->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  618.     if (IsWowCaller) {
  619.        c->iWowTask = iWowTask;
  620.     }
  621.     else {
  622.        c->iWowTask = 0;
  623.     }
  624.     // this parameter means
  625.     c->WaitObjectForVDM =0;
  626.     Status = CsrClientCallServer(
  627.                       (PCSR_API_MSG)&m,
  628.                       NULL,
  629.                       CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  630.                                            BasepExitVDM
  631.                                          ),
  632.                       sizeof( *c )
  633.                       );
  634.     if (NT_SUCCESS(Status) && c->WaitObjectForVDM) {
  635.         NtClose (c->WaitObjectForVDM);
  636.         }
  637.     return;
  638. }
  639. /*++
  640. Routine Description:
  641.     Set new VDM current directories
  642. Arguments:
  643.     cchCurDir - length of buffer in bytes
  644.     lpszCurDir - buffer to return the current director of NTVDM
  645. Return Value:
  646.     TRUE if function succeed
  647.     FALSE if function failed, GetLastError() has the error code
  648. --*/
  649. BOOL
  650. APIENTRY
  651. SetVDMCurrentDirectories(
  652.     IN ULONG  cchCurDirs,
  653.     IN LPSTR  lpszzCurDirs
  654.     )
  655. {
  656.     NTSTATUS Status;
  657.     PCSR_CAPTURE_HEADER CaptureBuffer;
  658.     BASE_API_MSG m;
  659.     PBASE_GET_SET_VDM_CUR_DIRS_MSG a = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m.u.GetSetVDMCurDirs;
  660.     a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  661.     // caller must have a valid console(WOW will fail)
  662.     if (a->ConsoleHandle == (HANDLE) -1) {
  663.         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  664.         return FALSE;
  665.     }
  666.     if (cchCurDirs && lpszzCurDirs) {
  667.         // get capture buffer, one pointer in the message
  668.         CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
  669.         if (CaptureBuffer == NULL) {
  670.             BaseSetLastNTError( STATUS_NO_MEMORY );
  671.             return FALSE;
  672.             }
  673.         CsrAllocateMessagePointer( CaptureBuffer,
  674.                                    cchCurDirs,
  675.                                    (PVOID *)&a->lpszzCurDirs
  676.                                    );
  677.         a->cchCurDirs = cchCurDirs;
  678.         try {
  679.             RtlMoveMemory(a->lpszzCurDirs, lpszzCurDirs, cchCurDirs);
  680.         }
  681.         except (EXCEPTION_EXECUTE_HANDLER) {
  682.             BaseSetLastNTError(GetExceptionCode());
  683.             CsrFreeCaptureBuffer(CaptureBuffer);
  684.             return FALSE;
  685.         }
  686.         Status = CsrClientCallServer(
  687.                             (PCSR_API_MSG)&m,
  688.                             CaptureBuffer,
  689.                             CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  690.                                                 BasepSetVDMCurDirs
  691.                                                 ),
  692.                             sizeof( *a )
  693.                             );
  694.         CsrFreeCaptureBuffer(CaptureBuffer);
  695.         if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  696.             BaseSetLastNTError(Status);
  697.             return FALSE;
  698.         }
  699.     }
  700.     return TRUE;
  701. }
  702. /*++
  703. Routine Description:
  704.     To return current directory of NTVDM.
  705.     This allows the parent process(CMD.EXE in most cases) to keep track the
  706.     current directory after each VDM execution.
  707.     NOTE: this function doesn't apply to wow
  708. Arguments:
  709.     cchCurDir - length of buffer in bytes
  710.     lpszCurDir - buffer to return the current director of NTVDM
  711.     Note: We don't require the process id to the running VDM because
  712.           current directories are global to every VDMs under a single NTVDM
  713.           control -- each console handle has its own current directories
  714. Return Value:
  715.     ULONG - (1). number of bytes written to the given buffer if succeed
  716.             (2). lentgh of the current directory including NULL
  717.                  if the provided buffer is not large enough
  718.             (3). 0  then GetLastError() has the error code
  719. --*/
  720. ULONG
  721. APIENTRY
  722. GetVDMCurrentDirectories(
  723.     IN ULONG  cchCurDirs,
  724.     IN LPSTR  lpszzCurDirs
  725.     )
  726. {
  727.     NTSTATUS Status;
  728.     PCSR_CAPTURE_HEADER CaptureBuffer;
  729.     BASE_API_MSG m;
  730.     PBASE_GET_SET_VDM_CUR_DIRS_MSG a = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m.u.GetSetVDMCurDirs;
  731.     a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  732.     if (a->ConsoleHandle == (HANDLE) -1) {
  733.         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  734.         return 0L;
  735.     }
  736.     if (cchCurDirs && lpszzCurDirs) {
  737.         CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
  738.         if (CaptureBuffer == NULL) {
  739.             BaseSetLastNTError( STATUS_NO_MEMORY );
  740.             return FALSE;
  741.             }
  742.         CsrAllocateMessagePointer( CaptureBuffer,
  743.                                    cchCurDirs,
  744.                                    (PVOID *)&a->lpszzCurDirs
  745.                                    );
  746.         a->cchCurDirs = cchCurDirs;
  747.     }
  748.     else {
  749.         a->cchCurDirs = 0;
  750.         a->lpszzCurDirs = NULL;
  751.         CaptureBuffer = NULL;
  752.     }
  753.     m.ReturnValue = 0xffffffff;
  754.     Status = CsrClientCallServer(
  755.                          (PCSR_API_MSG)&m,
  756.                          CaptureBuffer,
  757.                          CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  758.                                              BasepGetVDMCurDirs
  759.                                              ),
  760.                          sizeof( *a )
  761.                          );
  762.     if (m.ReturnValue == 0xffffffff) {
  763.         a->cchCurDirs = 0;
  764.         }
  765.     if (NT_SUCCESS(Status)) {
  766.         Status = m.ReturnValue;
  767.         }
  768.     if (NT_SUCCESS(Status)) {
  769.         try {
  770.             RtlMoveMemory(lpszzCurDirs, a->lpszzCurDirs, a->cchCurDirs);
  771.             }
  772.         except(EXCEPTION_EXECUTE_HANDLER) {
  773.             Status = GetExceptionCode();
  774.             a->cchCurDirs = 0;
  775.             }
  776.         }
  777.     else {
  778.         BaseSetLastNTError(Status);
  779.         }
  780.     if (CaptureBuffer) {
  781.         CsrFreeCaptureBuffer(CaptureBuffer);
  782.         }
  783.     return a->cchCurDirs;
  784. }
  785. VOID
  786. APIENTRY
  787. CmdBatNotification(
  788.     IN  ULONG   fBeginEnd
  789.     )
  790. /*++
  791. Routine Description:
  792.     This API lets base know about .bat processing from cmd. This is
  793.     required by VDM, so that it can decided correctly when to  put
  794.     command.com prompt on TSRs. If the command came from .bat file
  795.     then VDM should'nt put its prompt. This is important for
  796.     ventura publisher and civilization apps.
  797. Arguments:
  798.     fBeginEnd - CMD_BAT_OPERATION_STARTING  -> .BAT processing is starting
  799.                 CMD_BAT_OPERATION_TERMINATING -> .BAT processing is ending
  800. Return Value:
  801.     None
  802. --*/
  803. {
  804.     BASE_API_MSG m;
  805.     PBASE_BAT_NOTIFICATION_MSG a = (PBASE_BAT_NOTIFICATION_MSG)&m.u.BatNotification;
  806.     a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  807.     if (a->ConsoleHandle == (HANDLE) -1)
  808.         return;
  809.     a->fBeginEnd = fBeginEnd;
  810.     CsrClientCallServer((PCSR_API_MSG)&m,
  811.                          NULL,
  812.                          CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  813.                                              BasepBatNotification
  814.                                              ),
  815.                          sizeof( *a )
  816.                          );
  817.     return;
  818. }
  819. NTSTATUS
  820. APIENTRY
  821. RegisterWowExec(
  822.     IN  HANDLE   hwndWowExec
  823.     )
  824. /*++
  825. Routine Description:
  826.     This API gives basesrv the window handle for the shared WowExec so
  827.     it can send WM_WOWEXECSTARTAPP messages to WowExec.  This
  828.     saves having a thread in WOW dedicated to GetNextVDMCommand.
  829. Arguments:
  830.     hwndWowExec - Win32 window handle for WowExec in shared WOW VDM.
  831.                   Separate WOW VDMs don't register their WowExec handle
  832.                   because they never get commands from base.
  833.                   NULL is passed to de-register any given wowexec
  834. Return Value:
  835.    If hwndWowExec != NULL then returns success if wow had been registered successfully
  836.    if hwndWowExec == NULL then returns success if no tasks are pending to be executed
  837. --*/
  838. {
  839.     BASE_API_MSG m;
  840.     PBASE_REGISTER_WOWEXEC_MSG a = &m.u.RegisterWowExec;
  841.     NTSTATUS Status;
  842.     a->hwndWowExec   = hwndWowExec;
  843.     a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  844.     Status = CsrClientCallServer((PCSR_API_MSG)&m,
  845.                                   NULL,
  846.                                   CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  847.                                                       BasepRegisterWowExec
  848.                                                       ),
  849.                                   sizeof( *a )
  850.                                  );
  851.     return Status;
  852. }
  853. /*++
  854. Routine Description:
  855.     This routine is used to close standard IO handles before returning to the
  856.     caller
  857. Arguments:
  858.     pVDMInfo - VDM Info record containing stdio handles
  859. Return Value:
  860.     None
  861. --*/
  862. VOID
  863. BaseCloseStandardHandle(
  864.     IN PVDMINFO pVDMInfo
  865.     )
  866. {
  867.     if (pVDMInfo->StdIn)
  868.         NtClose (pVDMInfo->StdIn);
  869.     if (pVDMInfo->StdOut)
  870.         NtClose (pVDMInfo->StdOut);
  871.     if (pVDMInfo->StdErr)
  872.         NtClose (pVDMInfo->StdErr);
  873.     pVDMInfo->StdIn  = 0;
  874.     pVDMInfo->StdOut = 0;
  875.     pVDMInfo->StdErr = 0;
  876. }
  877. #ifdef OLD_CFG_BASED
  878. BOOL
  879. BaseGetVDMKeyword(
  880.     PCHAR KeywordLine,
  881.     PCONFIG_KEYWORD *pKeywordLine,
  882.     PCHAR KeywordSize,
  883.     PULONG VdmSize
  884.     )
  885. {
  886.     NTSTATUS Status;
  887.     PCONFIG_FILE ConfigFile;
  888.     PCONFIG_SECTION Section;
  889.     STRING SectionName, KeywordName;
  890.     PCONFIG_KEYWORD pKeywordSize;
  891.     //
  892.     // Retrieve the VDM configuration information from the config file
  893.     //
  894.     Status = RtlOpenConfigFile( NULL, &ConfigFile );
  895.     if (!NT_SUCCESS( Status )) {
  896.         return FALSE;
  897.     }
  898.     //
  899.     // Find WOW section of config file
  900.     //
  901.     RtlInitString( &SectionName, "WOW" );
  902.     Section = RtlLocateSectionConfigFile( ConfigFile, &SectionName );
  903.     if (Section == NULL) {
  904.         RtlCloseConfigFile( ConfigFile );
  905.         return FALSE;
  906.     }
  907.     //
  908.     // Get command line
  909.     //
  910.     RtlInitString( &KeywordName, KeywordLine );
  911.     *pKeywordLine = RtlLocateKeywordConfigFile( Section, &KeywordName );
  912.     if (*pKeywordLine == NULL) {
  913.         RtlCloseConfigFile( ConfigFile );
  914.         return FALSE;
  915.     }
  916.     //
  917.     // Get Vdm size
  918.     //
  919.     RtlInitString( &KeywordName, KeywordSize );
  920.     pKeywordSize = RtlLocateKeywordConfigFile( Section, &KeywordName );
  921.     if (pKeywordSize == NULL) {
  922.         *VdmSize = 1024L * 1024L * 16L;
  923.     } else {
  924.         Status = RtlCharToInteger( pKeywordSize->Value.Buffer, 0, VdmSize );
  925.         if (!NT_SUCCESS( Status )) {
  926.             *VdmSize = 1024L * 1024L * 16L;
  927.         } else {
  928.             *VdmSize *= 1024L * 1024L;   // convert to MB
  929.         }
  930.     }
  931.     return TRUE;
  932. }
  933. #endif
  934. BOOL
  935. BaseGetVDMKeyword(
  936.     LPWSTR  KeywordLine,
  937.     LPSTR   KeywordLineValue,
  938.     LPDWORD KeywordLineSize,
  939.     LPWSTR  KeywordSize,
  940.     LPDWORD VdmSize
  941.     )
  942. {
  943.     NTSTATUS NtStatus;
  944.     UNICODE_STRING UnicodeString,UnicodeTemp;
  945.     UNICODE_STRING KeyName;
  946.     ANSI_STRING AnsiString;
  947.     LPWSTR UnicodeBuffer,Temp;
  948.     OBJECT_ATTRIBUTES ObjectAttributes;
  949.     HANDLE hKey = NULL;
  950.     PKEY_VALUE_FULL_INFORMATION pKeyValueInformation;
  951.     //
  952.     // Allocate Work buffer
  953.     //
  954.     UnicodeBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ), FULL_INFO_BUFFER_SIZE);
  955.     if (!UnicodeBuffer) {
  956.         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  957.         return(FALSE);
  958.     }
  959.     // Open the WOW key
  960.     RtlInitUnicodeString (&KeyName, WOW_ROOT);
  961.     InitializeObjectAttributes(&ObjectAttributes,
  962.                               &KeyName,
  963.                               OBJ_CASE_INSENSITIVE,
  964.                               NULL,
  965.                               NULL
  966.                               );
  967.     NtStatus = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
  968.     if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  969.         BaseSetLastNTError(NtStatus);
  970.         return FALSE;
  971.     }
  972.     if (!GetVDMConfigValue(hKey,KeywordLine,UnicodeBuffer)) {
  973.         NtClose (hKey);
  974.         RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  975.         return(FALSE);
  976.     }
  977.     //
  978.     // Now convert back to ANSI for the caller after doing all the substitution
  979.     //
  980.     pKeyValueInformation = (PVOID)UnicodeBuffer;
  981.     Temp = (LPWSTR)((PBYTE) pKeyValueInformation + pKeyValueInformation->DataOffset);
  982.     RtlInitUnicodeString( &UnicodeString, Temp );
  983.     UnicodeTemp.Buffer =  (LPWSTR)KeywordLineValue;
  984.     UnicodeTemp.Length =  0;
  985.     UnicodeTemp.MaximumLength = MAX_VDM_CFG_LINE;
  986.     NtStatus = RtlExpandEnvironmentStrings_U    (NULL,&UnicodeString, &UnicodeTemp, NULL);
  987.     if (!NT_SUCCESS( NtStatus )){
  988.         NtClose (hKey);
  989.         RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  990.         return FALSE;
  991.     }
  992.     wcscpy(UnicodeString.Buffer,UnicodeTemp.Buffer);
  993.     UnicodeString.Length = UnicodeTemp.Length;
  994.     //
  995.     // Set up an ANSI_STRING that points to the user's buffer
  996.     //
  997.     AnsiString.MaximumLength = (USHORT) *KeywordLineSize;
  998.     AnsiString.Length = 0;
  999.     AnsiString.Buffer = KeywordLineValue;
  1000.     RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
  1001.     *KeywordLineSize = AnsiString.Length;
  1002.     // Always set the VDMSize to 16Mb. (This is for reservation only)
  1003.     // Actual commit is done by SAS_INIT.
  1004.     *VdmSize = 16L;             //default value is 16
  1005.     *VdmSize *= 1024L * 1024L;  // convert From MB
  1006.     NtClose (hKey);
  1007.     RtlFreeHeap(RtlProcessHeap(), 0, UnicodeBuffer);
  1008.     return(TRUE);
  1009. }
  1010. BOOL
  1011. GetVDMConfigValue(
  1012.     HANDLE hKey,
  1013.     LPWSTR Keyword,
  1014.     LPWSTR UnicodeBuffer
  1015.     )
  1016. {
  1017.     NTSTATUS NtStatus;
  1018.     UNICODE_STRING ValueName;
  1019.     PKEY_VALUE_FULL_INFORMATION pKeyValueInformation = (PVOID) UnicodeBuffer;
  1020.     ULONG ValueLength;
  1021.     RtlInitUnicodeString(&ValueName, Keyword);
  1022.     NtStatus = NtQueryValueKey(hKey,
  1023.                                &ValueName,
  1024.                                KeyValueFullInformation,
  1025.                                pKeyValueInformation,
  1026.                                FULL_INFO_BUFFER_SIZE,
  1027.                                &ValueLength);
  1028.     if (NT_SUCCESS(NtStatus))
  1029.             return TRUE;
  1030.     else {
  1031.          BaseSetLastNTError (NtStatus);
  1032.          return FALSE;
  1033.     }
  1034. }
  1035. BOOL
  1036. BaseCheckVDM(
  1037.     IN  ULONG BinaryType,
  1038.     IN  PCWCH lpApplicationName,
  1039.     IN  PCWCH lpCommandLine,
  1040.     IN  PCWCH lpCurrentDirectory,
  1041.     IN  ANSI_STRING *pAnsiStringEnv,
  1042.     IN  PBASE_API_MSG m,
  1043.     IN OUT PULONG iTask,
  1044.     IN  DWORD dwCreationFlags,
  1045.     LPSTARTUPINFOW lpStartupInfo
  1046.     )
  1047. /*++
  1048. Routine Description:
  1049.     This routine calls the windows server to find out if the VDM for the
  1050.     current session is already present. If so, a new process is'nt created
  1051.     instead the DOS binary is dispatched to the existing VDM. Otherwise,
  1052.     a new VDM process is created. This routine also passes the app name
  1053.     and command line to the server in DOS int21/0ah style which is later
  1054.     passed by the server to the VDM.
  1055. Arguments:
  1056.     BinaryType - DOS/WOW binary
  1057.     lpApplicationName -- pointer to the full path name of the executable.
  1058.     lpCommandLine -- command line
  1059.     lpCurrentDirectory - Current directory
  1060.     lpEnvironment,     - Envirinment strings
  1061.     m - pointer to the base api message.
  1062.     iTask - taskid for win16 apps, and no-console dos apps
  1063.     dwCreationFlags - creation flags as passed to createprocess
  1064.     lpStartupInfo =- pointer to startupinfo as passed to createprocess
  1065. Return Value:
  1066.     OEM vs. ANSI:
  1067.     The command line, Application Name, title are converted to OEM strings,
  1068.     suitable for the VDM. All other strings are returned as ANSI.
  1069.     TRUE -- Operation successful, VDM state and other relevant information
  1070.             is in base api message.
  1071.     FALSE -- Operation failed.
  1072. --*/
  1073. {
  1074.     NTSTATUS Status;
  1075.     PPEB Peb;
  1076.     PBASE_CHECKVDM_MSG b= (PBASE_CHECKVDM_MSG)&m->u.CheckVDM;
  1077.     PCSR_CAPTURE_HEADER CaptureBuffer;
  1078.     ANSI_STRING AnsiStringCurrentDir,AnsiStringDesktop;
  1079.     ANSI_STRING AnsiStringReserved, AnsiStringPif;
  1080.     OEM_STRING OemStringCmd, OemStringAppName, OemStringTitle;
  1081.     UNICODE_STRING UnicodeString;
  1082.     PCHAR pch, Buffer = NULL;
  1083.     ULONG Len;
  1084.     ULONG bufPointers;
  1085.     LPWSTR wsBuffer;
  1086.     LPWSTR wsAppName;
  1087.     LPWSTR wsPifName;
  1088.     LPWSTR wsCmdLine;
  1089.     LPWSTR wsPif=(PWSTR)".pif";    // L".pif"
  1090.     LPWSTR wsSharedWowPif=L"wowexec.pif";
  1091.     PWCHAR pwch;
  1092.     BOOLEAN bNewConsole;
  1093.     BOOLEAN bReturn = FALSE;
  1094.     DWORD   dw, dwTotal, Length;
  1095.     WCHAR   wchBuffer[MAX_PATH + 1];
  1096.     ULONG BinarySubType;
  1097.     LPWSTR lpAllocatedReserved = NULL;
  1098.     DWORD   HandleFlags;
  1099.     // does a trivial test of the environment
  1100.     if (!ARGUMENT_PRESENT(pAnsiStringEnv) ||
  1101.         pAnsiStringEnv->Length > MAXIMUM_VDM_ENVIORNMENT) {
  1102.         SetLastError(ERROR_INVALID_PARAMETER);
  1103.         return FALSE;
  1104.         }
  1105.     wsCmdLine = wsAppName = NULL;
  1106.     OemStringCmd.Buffer = NULL;
  1107.     OemStringAppName.Buffer = NULL;
  1108.     AnsiStringCurrentDir.Buffer = NULL;
  1109.     AnsiStringDesktop.Buffer = NULL;
  1110.     AnsiStringPif.Buffer = NULL;
  1111.     OemStringTitle.Buffer = NULL;
  1112.     AnsiStringReserved.Buffer = NULL;
  1113.     wsBuffer = NULL;
  1114.     wsPifName = NULL;
  1115.     BinarySubType = BinaryType & BINARY_SUBTYPE_MASK;
  1116.     BinaryType = BinaryType & ~BINARY_SUBTYPE_MASK;
  1117.     bNewConsole = !NtCurrentPeb()->ProcessParameters->ConsoleHandle ||
  1118.                   (dwCreationFlags & CREATE_NEW_CONSOLE);
  1119.     try {
  1120.         if (BinaryType == BINARY_TYPE_DOS) {
  1121.             Peb = NtCurrentPeb();
  1122.             if (lpStartupInfo && lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) {
  1123.                 b->StdIn = lpStartupInfo->hStdInput;
  1124.                 b->StdOut = lpStartupInfo->hStdOutput;
  1125.                 b->StdErr = lpStartupInfo->hStdError;
  1126.                 }
  1127.             else {
  1128.                 b->StdIn = Peb->ProcessParameters->StandardInput;
  1129.                 b->StdOut = Peb->ProcessParameters->StandardOutput;
  1130.                 b->StdErr = Peb->ProcessParameters->StandardError;
  1131.                 //
  1132.                 // Verify that the standard handles ntvdm process will inherit
  1133.                 // from the calling process are real handles. They are not
  1134.                 // handles if the calling process was created with
  1135.                 // STARTF_USEHOTKEY | STARTF_HASSHELLDATA.
  1136.                 // Note that CreateProcess clears STARTF_USESTANDHANDLES
  1137.                 // if either STARTF_USEHOTKEY or STARTF_HASSHELLDATA is set.
  1138.                 //
  1139.                 if (Peb->ProcessParameters->WindowFlags &
  1140.                     (STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  1141.                     if (b->StdIn && !CONSOLE_HANDLE(b->StdIn) &&
  1142.                         !GetHandleInformation(b->StdIn, &HandleFlags))
  1143.                         b->StdIn = 0;
  1144.                     if (b->StdOut && !CONSOLE_HANDLE(b->StdOut) &&
  1145.                         !GetHandleInformation(b->StdOut, &HandleFlags)) {
  1146.                         if (b->StdErr == b->StdOut)
  1147.                             b->StdErr = 0;
  1148.                         b->StdOut = 0;
  1149.                         }
  1150.                     if (b->StdErr && b->StdErr != b->StdOut &&
  1151.                         !CONSOLE_HANDLE(b->StdErr) &&
  1152.                         !GetHandleInformation(b->StdErr, &HandleFlags))
  1153.                         b->StdErr = 0;
  1154.                     }
  1155.                 }
  1156.             if (CONSOLE_HANDLE((b->StdIn)))
  1157.                 b->StdIn = 0;
  1158.             if (CONSOLE_HANDLE((b->StdOut)))
  1159.                 b->StdOut = 0;
  1160.             if (CONSOLE_HANDLE((b->StdErr)))
  1161.                 b->StdErr = 0;
  1162.             }
  1163.         if (BinaryType == BINARY_TYPE_SEPWOW) {
  1164.             bNewConsole = TRUE;
  1165.             }
  1166.         //
  1167.         // Convert Unicode Application Name to Oem short name
  1168.         //
  1169.              // skiping leading white space
  1170.         while(*lpApplicationName == (WCHAR)' ' || *lpApplicationName == (WCHAR)'t' ) {
  1171.               lpApplicationName++;
  1172.               }
  1173.              // space for short AppName
  1174.         Len = wcslen(lpApplicationName);
  1175.         dwTotal = Len + 1 + MAX_PATH;
  1176.         wsAppName =  RtlAllocateHeap(RtlProcessHeap(),
  1177.                                     MAKE_TAG(VDM_TAG),
  1178.                                     dwTotal * sizeof(WCHAR)
  1179.                                     );
  1180.         if (wsAppName == NULL) {
  1181.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1182.             goto BCVTryExit;
  1183.             }
  1184.         dw = GetShortPathNameW(lpApplicationName, wsAppName, dwTotal);
  1185.         // If getting the short name is impossible, stop right here.
  1186.         // We can not execute a 16bits biranry if we can not find
  1187.         // its appropriate short name alias. Sorry HPFS, Sorry NFS
  1188.         if (0 == dw || dw > dwTotal) {
  1189.             SetLastError(ERROR_BAD_PATHNAME);
  1190.             goto BCVTryExit;
  1191.             }
  1192.         RtlInitUnicodeString(&UnicodeString, wsAppName);
  1193.         Status = RtlUnicodeStringToOemString(&OemStringAppName,
  1194.                                              &UnicodeString,
  1195.                                              TRUE
  1196.                                              );
  1197.         if (!NT_SUCCESS(Status) ){
  1198.             BaseSetLastNTError(Status);
  1199.             goto BCVTryExit;
  1200.             }
  1201.         //
  1202.         // Find len of basename excluding extension,
  1203.         // for CommandTail max len check.
  1204.         //
  1205.         dw = OemStringAppName.Length;
  1206.         pch = OemStringAppName.Buffer;
  1207.         Length = 1;        // start at one for space between cmdname & cmdtail
  1208.         while (dw-- && *pch != '.') {
  1209.             if (*pch == '\') {
  1210.                 Length = 1;
  1211.                 }
  1212.             else {
  1213.                 Length++;
  1214.                 }
  1215.             pch++;
  1216.             }
  1217.         //
  1218.         // Find the beg of the command tail to pass as the CmdLine
  1219.         //
  1220.         Len = wcslen(lpApplicationName);
  1221.         if (L'"' == lpCommandLine[0]) {
  1222.             //
  1223.             // Application name is quoted, skip the quoted text
  1224.             // to get command tail.
  1225.             //
  1226.             pwch = (LPWSTR)&lpCommandLine[1];
  1227.             while (*pwch && L'"' != *pwch++) {
  1228.                 ;
  1229.             }
  1230.         } else if (Len <= wcslen(lpCommandLine) &&
  1231.             0 == _wcsnicmp(lpApplicationName, lpCommandLine, Len)) {
  1232.             //
  1233.             // Application path is also on the command line, skip past
  1234.             // that to reach the command tail instead of looking for
  1235.             // the first white space.
  1236.             //
  1237.             pwch = (LPWSTR)lpCommandLine + Len;
  1238.         } else {
  1239.             //
  1240.             // We assume first token is exename (argv[0]).
  1241.             //
  1242.             pwch = (LPWSTR)lpCommandLine;
  1243.                // skip leading white characters
  1244.             while (*pwch != UNICODE_NULL &&
  1245.                    (*pwch == (WCHAR) ' ' || *pwch == (WCHAR) 't')) {
  1246.                 pwch++;
  1247.                 }
  1248.                // skip first token
  1249.             if (*pwch == (WCHAR) '"') {    // quotes as delimiter
  1250.                 pwch++;
  1251.                 while (*pwch && *pwch++ != '"') {
  1252.                       ;
  1253.                       }
  1254.                 }
  1255.             else {                         // white space as delimiter
  1256.                 while (*pwch && *pwch != ' ' && *pwch != 't') {
  1257.                        pwch++;
  1258.                        }
  1259.                 }
  1260.         }
  1261.         //
  1262.         // pwch points past the application name, now skip any trailing
  1263.         // whitespace.
  1264.         //
  1265.         while (*pwch && (L' ' == *pwch || L't' == *pwch)) {
  1266.             pwch++;
  1267.         }
  1268.         wsCmdLine = pwch;
  1269.         dw = wcslen(wsCmdLine);
  1270.         // convert to oem
  1271.         UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1272.         UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  1273.         UnicodeString.Buffer = wsCmdLine;
  1274.         Status = RtlUnicodeStringToOemString(
  1275.                     &OemStringCmd,
  1276.                     &UnicodeString,
  1277.                     TRUE);
  1278.         if (!NT_SUCCESS(Status) ){
  1279.             BaseSetLastNTError(Status);
  1280.             goto BCVTryExit;
  1281.             }
  1282.         //
  1283.         // check len of command line for dos compatibility
  1284.         //
  1285.         if (OemStringCmd.Length >= MAXIMUM_VDM_COMMAND_LENGTH - Length) {
  1286.             SetLastError(ERROR_INVALID_PARAMETER);
  1287.             goto BCVTryExit;
  1288.             }
  1289.         //
  1290.         // Search for matching pif file. Search order is AppName dir,
  1291.         // followed by win32 default search path. For the shared wow, pif
  1292.         // is wowexec.pif if it exists.
  1293.         //
  1294.         wsBuffer = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( VDM_TAG ),MAX_PATH*sizeof(WCHAR));
  1295.         if (!wsBuffer) {
  1296.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1297.             goto BCVTryExit;
  1298.             }
  1299.         wsPifName = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( VDM_TAG ),MAX_PATH*sizeof(WCHAR));
  1300.         if (!wsPifName) {
  1301.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1302.             goto BCVTryExit;
  1303.             }
  1304.         if (BinaryType == BINARY_TYPE_WIN16) {
  1305.             wcscpy(wsBuffer, wsSharedWowPif);
  1306.             Len = 0;
  1307.             }
  1308.         else {
  1309.             // start with fully qualified app name
  1310.             wcscpy(wsBuffer, lpApplicationName);
  1311.              // strip extension if any
  1312.             pwch = wcsrchr(wsBuffer, (WCHAR)'.');
  1313.             // dos application must have an extention
  1314.             if (pwch == NULL) {
  1315.                  SetLastError(ERROR_INVALID_PARAMETER);
  1316.                  goto BCVTryExit;
  1317.                 }
  1318.             wcscpy(pwch, wsPif);
  1319.             Len = GetFileAttributesW(wsBuffer);
  1320.             if (Len == (DWORD)(-1) || (Len & FILE_ATTRIBUTE_DIRECTORY)) {
  1321.                 Len = 0;
  1322.                 }
  1323.             else {
  1324.                 Len = wcslen(wsBuffer) + 1;
  1325.                 wcsncpy(wsPifName, wsBuffer, Len);
  1326.                 }
  1327.             }
  1328.         if (!Len)  {  // try basename
  1329.                // find beg of basename
  1330.             pwch = wcsrchr(wsBuffer, (WCHAR)'\');
  1331.             if (!pwch ) {
  1332.                  pwch = wcsrchr(wsBuffer, (WCHAR)':');
  1333.                  }
  1334.                // move basename to beg of wsBuffer
  1335.             if (pwch++) {
  1336.                  while (*pwch != UNICODE_NULL &&
  1337.                         *pwch != (WCHAR)' '   && *pwch != (WCHAR)'t' )
  1338.                        {
  1339.                         wsBuffer[Len++] = *pwch++;
  1340.                         }
  1341.                  wsBuffer[Len] = UNICODE_NULL;
  1342.                  }
  1343.             if (Len)  {
  1344.                 Len = SearchPathW(
  1345.                             NULL,
  1346.                             wsBuffer,
  1347.                             wsPif,              // L".pif"
  1348.                             MAX_PATH,
  1349.                             wsPifName,
  1350.                             NULL
  1351.                             );
  1352.                 if (Len >= MAX_PATH) {
  1353.                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1354.                     goto BCVTryExit;
  1355.                     }
  1356.                 }
  1357.             }
  1358.         if (!Len)
  1359.             *wsPifName = UNICODE_NULL;
  1360.         if (!ARGUMENT_PRESENT( lpCurrentDirectory )) {
  1361.             dw = RtlGetCurrentDirectory_U(sizeof (wchBuffer), wchBuffer);
  1362.             wchBuffer[dw / sizeof(WCHAR)] = UNICODE_NULL;
  1363.             dw = GetShortPathNameW(wchBuffer,
  1364.                                    wchBuffer,
  1365.                                    sizeof(wchBuffer) / sizeof(WCHAR)
  1366.                                    );
  1367.             if (dw > sizeof(wchBuffer) / sizeof(WCHAR))
  1368.                 goto BCVTryExit;
  1369.             else if (dw == 0) {
  1370.                 RtlInitUnicodeString(&UnicodeString, wchBuffer);
  1371.                 dw = UnicodeString.Length / sizeof(WCHAR);
  1372.                 }
  1373.             else {
  1374.                 UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1375.                 UnicodeString.Buffer = wchBuffer;
  1376.                 UnicodeString.MaximumLength = (USHORT)sizeof(wchBuffer);
  1377.                 }
  1378.             // DOS limit of 64 includes the final NULL but not the leading
  1379.             // drive and slash. So here we should be checking the ansi length
  1380.             // of current directory + 1 (for NULL) - 3 (for c:).
  1381.             if ( dw - 2 <= MAXIMUM_VDM_CURRENT_DIR ) {
  1382.                 Status = RtlUnicodeStringToAnsiString(
  1383.                                                       &AnsiStringCurrentDir,
  1384.                                                       &UnicodeString,
  1385.                                                       TRUE
  1386.                                                      );
  1387.                 }
  1388.             else {
  1389.                 SetLastError(ERROR_INVALID_PARAMETER);
  1390.                 goto BCVTryExit;
  1391.                 }
  1392.             if ( !NT_SUCCESS(Status) ) {
  1393.                 BaseSetLastNTError(Status);
  1394.                 goto BCVTryExit;
  1395.                 }
  1396.             }
  1397.         else {
  1398.             // first get a full path name
  1399.             dw = GetFullPathNameW(lpCurrentDirectory,
  1400.                                    sizeof(wchBuffer) / sizeof(WCHAR),
  1401.                                    wchBuffer,
  1402.                                    NULL);
  1403.             if (0 != dw && dw <= sizeof(wchBuffer) / sizeof(WCHAR)) {
  1404.                dw = GetShortPathNameW(wchBuffer,
  1405.                                       wchBuffer,
  1406.                                       sizeof(wchBuffer) / sizeof(WCHAR));
  1407.             }
  1408.             if (dw > sizeof(wchBuffer) / sizeof(WCHAR))
  1409.                 goto BCVTryExit;
  1410.             if (dw != 0) {
  1411.                 UnicodeString.Buffer = wchBuffer;
  1412.                 UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1413.                 UnicodeString.MaximumLength = sizeof(wchBuffer);
  1414.                 }
  1415.             else
  1416.                 RtlInitUnicodeString(&UnicodeString, lpCurrentDirectory);
  1417.             Status = RtlUnicodeStringToAnsiString(
  1418.                 &AnsiStringCurrentDir,
  1419.                 &UnicodeString,
  1420.                 TRUE);
  1421.             if ( !NT_SUCCESS(Status) ){
  1422.                 BaseSetLastNTError(Status);
  1423.                 goto BCVTryExit;
  1424.                }
  1425.             // DOS limit of 64 includes the final NULL but not the leading
  1426.             // drive and slash. So here we should be checking the ansi length
  1427.             // of current directory + 1 (for NULL) - 3 (for c:).
  1428.             if((AnsiStringCurrentDir.Length - 2) > MAXIMUM_VDM_CURRENT_DIR) {
  1429.                 SetLastError(ERROR_INVALID_PARAMETER);
  1430.                 goto BCVTryExit;
  1431.                 }
  1432.             }
  1433.         // NT allows applications to use UNC name as their current directory.
  1434.         // while NTVDM can't do that. We will end up a weird drive number
  1435.         // like '' - 'a') here ????????????????????????????????
  1436.         // BUGBUG
  1437.         // Place Current Drive
  1438.         if(AnsiStringCurrentDir.Buffer[0] <= 'Z')
  1439.             b->CurDrive = AnsiStringCurrentDir.Buffer[0] - 'A';
  1440.         else
  1441.             b->CurDrive = AnsiStringCurrentDir.Buffer[0] - 'a';
  1442.         //
  1443.         // Hotkey info in NT traditionally is specified in the
  1444.         // startupinfo.lpReserved field, but Win95 added a
  1445.         // duplicate mechanism.  If the Win95 method was used,
  1446.         // map it to the NT method here so the rest of the
  1447.         // VDM code only has to deal with one method.
  1448.         //
  1449.         // If the caller was stupid enough to specify a hotkey
  1450.         // in lpReserved as well as using STARTF_USEHOTKEY,
  1451.         // the STARTF_USEHOTKEY hotkey will take precedence.
  1452.         //
  1453.         if (lpStartupInfo && lpStartupInfo->dwFlags & STARTF_USEHOTKEY) {
  1454.             DWORD cbAlloc = sizeof(WCHAR) *
  1455.                             (20 +                            // "hotkey.4294967295 " (MAXULONG)
  1456.                              (lpStartupInfo->lpReserved      // length of prev lpReserved
  1457.                               ? wcslen(lpStartupInfo->lpReserved)
  1458.                               : 0
  1459.                              ) +
  1460.                              1                               // NULL terminator
  1461.                             );
  1462.             lpAllocatedReserved = RtlAllocateHeap(RtlProcessHeap(),
  1463.                                                   MAKE_TAG( VDM_TAG ),
  1464.                                                   cbAlloc
  1465.                                                  );
  1466.             if (lpAllocatedReserved) {
  1467.                 swprintf(lpAllocatedReserved,
  1468.                          L"hotkey.%u %s",
  1469.                          HandleToUlong(lpStartupInfo->hStdInput),
  1470.                          lpStartupInfo->lpReserved ? lpStartupInfo->lpReserved : L""
  1471.                          );
  1472.                 lpStartupInfo->dwFlags &= ~STARTF_USEHOTKEY;
  1473.                 lpStartupInfo->hStdInput = 0;
  1474.                 lpStartupInfo->lpReserved = lpAllocatedReserved;
  1475.             }
  1476.         }
  1477.         //
  1478.         // Allocate Capture Buffer
  1479.         //
  1480.         //
  1481.         bufPointers = 2;  // CmdLine, AppName
  1482.         //
  1483.         // CmdLine for capture buffer, 3 for 0xd,0xa and NULL
  1484.         //
  1485.         Len = ROUND_UP((OemStringCmd.Length + 3),4);
  1486.         // AppName, 1 for NULL
  1487.         Len += ROUND_UP((OemStringAppName.Length + 1),4);
  1488.         // Env
  1489.         if (pAnsiStringEnv->Length) {
  1490.             bufPointers++;
  1491.             Len += ROUND_UP(pAnsiStringEnv->Length, 4);
  1492.             }
  1493.         // CurrentDir
  1494.         if (AnsiStringCurrentDir.Length){
  1495.             bufPointers++;
  1496.             Len += ROUND_UP((AnsiStringCurrentDir.Length +1),4); // 1 for NULL
  1497.             }
  1498.         // pif file name, 1 for NULL
  1499.         if (wsPifName && *wsPifName != UNICODE_NULL) {
  1500.             bufPointers++;
  1501.             RtlInitUnicodeString(&UnicodeString,wsPifName);
  1502.             Status = RtlUnicodeStringToAnsiString(&AnsiStringPif,
  1503.                                                   &UnicodeString,
  1504.                                                   TRUE
  1505.                                                   );
  1506.             if ( !NT_SUCCESS(Status) ){
  1507.                 BaseSetLastNTError(Status);
  1508.                 goto BCVTryExit;
  1509.                 }
  1510.             Len += ROUND_UP((AnsiStringPif.Length+1),4);
  1511.             }
  1512.         //
  1513.         // startupinfo space
  1514.         //
  1515.         if (lpStartupInfo) {
  1516.             Len += ROUND_UP(sizeof(STARTUPINFOA),4);
  1517.             bufPointers++;
  1518.             if (lpStartupInfo->lpDesktop) {
  1519.                 bufPointers++;
  1520.                 RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpDesktop);
  1521.                 Status = RtlUnicodeStringToAnsiString(
  1522.                             &AnsiStringDesktop,
  1523.                             &UnicodeString,
  1524.                             TRUE);
  1525.                 if ( !NT_SUCCESS(Status) ){
  1526.                     BaseSetLastNTError(Status);
  1527.                     goto BCVTryExit;
  1528.                     }
  1529.                 Len += ROUND_UP((AnsiStringDesktop.Length+1),4);
  1530.                 }
  1531.             if (lpStartupInfo->lpTitle) {
  1532.                 bufPointers++;
  1533.                 RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpTitle);
  1534.                 Status = RtlUnicodeStringToOemString(
  1535.                             &OemStringTitle,
  1536.                             &UnicodeString,
  1537.                             TRUE);
  1538.                 if ( !NT_SUCCESS(Status) ){
  1539.                     BaseSetLastNTError(Status);
  1540.                     goto BCVTryExit;
  1541.                     }
  1542.                 Len += ROUND_UP((OemStringTitle.Length+1),4);
  1543.                 }
  1544.             if (lpStartupInfo->lpReserved) {
  1545.                 bufPointers++;
  1546.                 RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpReserved);
  1547.                 Status = RtlUnicodeStringToAnsiString(
  1548.                             &AnsiStringReserved,
  1549.                             &UnicodeString,
  1550.                             TRUE);
  1551.                 if ( !NT_SUCCESS(Status) ){
  1552.                     BaseSetLastNTError(Status);
  1553.                     goto BCVTryExit;
  1554.                     }
  1555.                 Len += ROUND_UP((AnsiStringReserved.Length+1),4);
  1556.                 }
  1557.             }
  1558.         // capture message buffer
  1559.         CaptureBuffer = CsrAllocateCaptureBuffer(bufPointers, Len);
  1560.         if (CaptureBuffer == NULL) {
  1561.             BaseSetLastNTError( STATUS_NO_MEMORY );
  1562.             goto BCVTryExit;
  1563.             }
  1564.         // Allocate CmdLine pointer
  1565.         CsrAllocateMessagePointer( CaptureBuffer,
  1566.                                    ROUND_UP((OemStringCmd.Length + 3),4),
  1567.                                    (PVOID *)&b->CmdLine
  1568.                                  );
  1569.         // Copy Command Line
  1570.         RtlMoveMemory (b->CmdLine, OemStringCmd.Buffer, OemStringCmd.Length);
  1571.         b->CmdLine[OemStringCmd.Length] = 0xd;
  1572.         b->CmdLine[OemStringCmd.Length+1] = 0xa;
  1573.         b->CmdLine[OemStringCmd.Length+2] = 0;
  1574.         b->CmdLen = (USHORT)(OemStringCmd.Length + 3);
  1575.         // Allocate AppName pointer
  1576.         CsrAllocateMessagePointer( CaptureBuffer,
  1577.                                    ROUND_UP((OemStringAppName.Length + 1),4),
  1578.                                    (PVOID *)&b->AppName
  1579.                                  );
  1580.         // Copy AppName
  1581.         RtlMoveMemory (b->AppName,
  1582.                        OemStringAppName.Buffer,
  1583.                        OemStringAppName.Length
  1584.                        );
  1585.         b->AppName[OemStringAppName.Length] = 0;
  1586.         b->AppLen = OemStringAppName.Length + 1;
  1587.         // Allocate PifFile pointer, Copy PifFile name
  1588.         if(AnsiStringPif.Buffer) {
  1589.             CsrAllocateMessagePointer( CaptureBuffer,
  1590.                                        ROUND_UP((AnsiStringPif.Length + 1),4),
  1591.                                        (PVOID *)&b->PifFile
  1592.                                      );
  1593.             RtlMoveMemory(b->PifFile,
  1594.                           AnsiStringPif.Buffer,
  1595.                           AnsiStringPif.Length);
  1596.             b->PifFile[AnsiStringPif.Length] = 0;
  1597.             b->PifLen = AnsiStringPif.Length + 1;
  1598.             }
  1599.         else {
  1600.             b->PifLen = 0;
  1601.             b->PifFile = NULL;
  1602.             }
  1603.         // Allocate Env pointer, Copy Env strings
  1604.         if(pAnsiStringEnv->Length) {
  1605.             CsrAllocateMessagePointer( CaptureBuffer,
  1606.                                        ROUND_UP((pAnsiStringEnv->Length),4),
  1607.                                        (PVOID *)&b->Env
  1608.                                      );
  1609.             RtlMoveMemory(b->Env,
  1610.                           pAnsiStringEnv->Buffer,
  1611.                           pAnsiStringEnv->Length);
  1612.             b->EnvLen = pAnsiStringEnv->Length;
  1613.             }
  1614.         else {
  1615.             b->EnvLen = 0;
  1616.             b->Env = NULL;
  1617.             }
  1618.         if(AnsiStringCurrentDir.Length) {
  1619.             // Allocate Curdir pointer
  1620.             CsrAllocateMessagePointer( CaptureBuffer,
  1621.                                        ROUND_UP((AnsiStringCurrentDir.Length + 1),4),
  1622.                                        (PVOID *)&b->CurDirectory
  1623.                                        );
  1624.             // copy cur directory
  1625.             RtlMoveMemory (b->CurDirectory,
  1626.                            AnsiStringCurrentDir.Buffer,
  1627.                            AnsiStringCurrentDir.Length+1);
  1628.             b->CurDirectoryLen = AnsiStringCurrentDir.Length+1;
  1629.             }
  1630.         else {
  1631.             b->CurDirectory = NULL;
  1632.             b->CurDirectoryLen = 0;
  1633.             }
  1634.         // Allocate startupinfo pointer
  1635.         if (lpStartupInfo) {
  1636.             CsrAllocateMessagePointer( CaptureBuffer,
  1637.                                        ROUND_UP(sizeof(STARTUPINFOA),4),
  1638.                                        (PVOID *)&b->StartupInfo
  1639.                                      );
  1640.             // Copy startupinfo
  1641.             b->StartupInfo->dwX  =  lpStartupInfo->dwX;
  1642.             b->StartupInfo->dwY  =  lpStartupInfo->dwY;
  1643.             b->StartupInfo->dwXSize      =  lpStartupInfo->dwXSize;
  1644.             b->StartupInfo->dwYSize      =  lpStartupInfo->dwYSize;
  1645.             b->StartupInfo->dwXCountChars=      lpStartupInfo->dwXCountChars;
  1646.             b->StartupInfo->dwYCountChars=      lpStartupInfo->dwYCountChars;
  1647.             b->StartupInfo->dwFillAttribute=lpStartupInfo->dwFillAttribute;
  1648.             b->StartupInfo->dwFlags      =  lpStartupInfo->dwFlags;
  1649.             b->StartupInfo->wShowWindow =       lpStartupInfo->wShowWindow;
  1650.             b->StartupInfo->cb           =  sizeof(STARTUPINFOA);
  1651.             }
  1652.         else {
  1653.             b->StartupInfo = NULL;
  1654.             }
  1655.         // Allocate pointer for Desktop info if needed
  1656.         if (AnsiStringDesktop.Buffer) {
  1657.             CsrAllocateMessagePointer( CaptureBuffer,
  1658.                                        ROUND_UP((AnsiStringDesktop.Length + 1),4),
  1659.                                        (PVOID *)&b->Desktop
  1660.                                      );
  1661.             // Copy desktop string
  1662.             RtlMoveMemory (b->Desktop,
  1663.                            AnsiStringDesktop.Buffer,
  1664.                            AnsiStringDesktop.Length+1);
  1665.             b->DesktopLen =AnsiStringDesktop.Length+1;
  1666.             }
  1667.         else {
  1668.             b->Desktop = NULL;
  1669.             b->DesktopLen =0;
  1670.             }
  1671.         // Allocate pointer for Title info if needed
  1672.         if (OemStringTitle.Buffer) {
  1673.             CsrAllocateMessagePointer( CaptureBuffer,
  1674.                                        ROUND_UP((OemStringTitle.Length + 1),4),
  1675.                                        (PVOID *)&b->Title
  1676.                                      );
  1677.             // Copy title string
  1678.             RtlMoveMemory (b->Title,
  1679.                            OemStringTitle.Buffer,
  1680.                            OemStringTitle.Length+1);
  1681.             b->TitleLen = OemStringTitle.Length+1;
  1682.             }
  1683.         else {
  1684.             b->Title = NULL;
  1685.             b->TitleLen = 0;
  1686.             }
  1687.         // Allocate pointer for Reserved field if needed
  1688.         if (AnsiStringReserved.Buffer) {
  1689.             CsrAllocateMessagePointer( CaptureBuffer,
  1690.                                        ROUND_UP((AnsiStringReserved.Length + 1),4),
  1691.                                        (PVOID *)&b->Reserved
  1692.                                      );
  1693.             // Copy reserved string
  1694.             RtlMoveMemory (b->Reserved,
  1695.                            AnsiStringReserved.Buffer,
  1696.                            AnsiStringReserved.Length+1);
  1697.             b->ReservedLen = AnsiStringReserved.Length+1;
  1698.             }
  1699.         else {
  1700.             b->Reserved = NULL;
  1701.             b->ReservedLen = 0;
  1702.             }
  1703.         // VadimB: this code is of no consequence to our marvelous new
  1704.         // architecture for tracking shared wows.
  1705.         // Reason: the checkvdm command is executed within the context of
  1706.         // a parent process thus at this point ConsoleHandle is of any
  1707.         // interest only to DOS apps.
  1708.         if (BinaryType == BINARY_TYPE_WIN16)
  1709.             b->ConsoleHandle = (HANDLE)-1;
  1710.         else if (bNewConsole)
  1711.             b->ConsoleHandle = 0;
  1712.         else
  1713.             b->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1714.         b->VDMState = FALSE;
  1715.         b->BinaryType = BinaryType;
  1716.         b->CodePage = (ULONG) GetConsoleCP ();
  1717.         b->dwCreationFlags = dwCreationFlags;
  1718.         Status = CsrClientCallServer(
  1719.                           (PCSR_API_MSG)m,
  1720.                           CaptureBuffer,
  1721.                           CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1722.                                                BasepCheckVDM
  1723.                                              ),
  1724.                           sizeof( *b )
  1725.                           );
  1726.         CsrFreeCaptureBuffer(CaptureBuffer);
  1727.         if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m->ReturnValue)) {
  1728.             BaseSetLastNTError((NTSTATUS)m->ReturnValue);
  1729.             goto BCVTryExit;
  1730.             }
  1731.         // VadimB: This iTask could be :
  1732.         //   (*) If not wow task - then dos task id (items below are not
  1733.         //       relevant for this case)
  1734.         //   (*) Shared wow exists and ready - this is a wow task id
  1735.         //       that is unique across all the shared wows
  1736.         *iTask = b->iTask;
  1737.         bReturn = TRUE;
  1738. BCVTryExit:;
  1739.         }
  1740.     finally {
  1741.         if(Buffer != NULL)
  1742.             RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)Buffer);
  1743.         if(wsBuffer != NULL)
  1744.             RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)wsBuffer);
  1745.         if(wsPifName != NULL)
  1746.             RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)wsPifName);
  1747.         if(OemStringCmd.Buffer != NULL)
  1748.             RtlFreeOemString(&OemStringCmd);
  1749.         if(OemStringAppName.Buffer != NULL)
  1750.             RtlFreeOemString(&OemStringAppName);
  1751.         if(AnsiStringPif.Buffer != NULL)
  1752.            RtlFreeAnsiString(&AnsiStringPif);
  1753.         if(AnsiStringCurrentDir.Buffer != NULL)
  1754.             RtlFreeAnsiString(&AnsiStringCurrentDir);
  1755.         if(AnsiStringDesktop.Buffer != NULL)
  1756.             RtlFreeAnsiString(&AnsiStringDesktop);
  1757.         if(OemStringTitle.Buffer != NULL)
  1758.             RtlFreeAnsiString(&OemStringTitle);
  1759.         if(AnsiStringReserved.Buffer != NULL)
  1760.             RtlFreeAnsiString(&AnsiStringReserved);
  1761.         if (wsAppName != NULL)
  1762.             RtlFreeHeap(RtlProcessHeap(), 0, wsAppName);
  1763.         if (lpAllocatedReserved != NULL)
  1764.             RtlFreeHeap(RtlProcessHeap(), 0, lpAllocatedReserved);
  1765.         }
  1766.     return bReturn;
  1767. }
  1768. BOOL
  1769. BaseUpdateVDMEntry(
  1770.     IN ULONG UpdateIndex,
  1771.     IN OUT HANDLE *WaitHandle,
  1772.     IN ULONG IndexInfo,
  1773.     IN ULONG BinaryType
  1774.     )
  1775. {
  1776.     NTSTATUS Status;
  1777.     BASE_API_MSG m;
  1778.     PBASE_UPDATE_VDM_ENTRY_MSG c= (PBASE_UPDATE_VDM_ENTRY_MSG)&m.u.UpdateVDMEntry;
  1779.     switch (UpdateIndex) {
  1780.         case UPDATE_VDM_UNDO_CREATION:
  1781.             c->iTask = HandleToUlong(*WaitHandle);
  1782.             c->VDMCreationState = (USHORT)IndexInfo;
  1783.             break;
  1784.         case UPDATE_VDM_PROCESS_HANDLE:
  1785.             c->VDMProcessHandle = *WaitHandle;  // Actually this is VDM handle
  1786.             c->iTask = IndexInfo;
  1787.             break;
  1788.         }
  1789.     // VadimB: this ConsoleHandle is of no consequence to the
  1790.     // shared wow tracking mechanism
  1791.     if(BinaryType == BINARY_TYPE_WIN16)
  1792.         c->ConsoleHandle = (HANDLE)-1;
  1793.     else if (c->iTask)
  1794.         c->ConsoleHandle = 0;
  1795.     else
  1796.         c->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1797.     c->EntryIndex = (WORD)UpdateIndex;
  1798.     c->BinaryType = BinaryType;
  1799.     Status = CsrClientCallServer(
  1800.                       (PCSR_API_MSG)&m,
  1801.                       NULL,
  1802.                       CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1803.                                            BasepUpdateVDMEntry
  1804.                                          ),
  1805.                       sizeof( *c )
  1806.                       );
  1807.     if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  1808.         BaseSetLastNTError((NTSTATUS)m.ReturnValue);
  1809.         return FALSE;
  1810.         }
  1811.     switch (UpdateIndex) {
  1812.         case UPDATE_VDM_UNDO_CREATION:
  1813.             break;
  1814.         case UPDATE_VDM_PROCESS_HANDLE:
  1815.             *WaitHandle = c->WaitObjectForParent;
  1816.             break;
  1817.     }
  1818.     return TRUE;
  1819. }
  1820. ULONG
  1821. BaseIsDosApplication(
  1822.     IN PUNICODE_STRING PathName,
  1823.     IN NTSTATUS Status
  1824.     )
  1825. /*++
  1826. Routine Description:
  1827.     Determines if app is a ".com" or a ".pif" type of app
  1828.     by looking at the extension, and the Status from NtCreateSection
  1829.     for PAGE_EXECUTE.
  1830. Arguments:
  1831.     PathName    -- Supplies a pointer to the path string
  1832.     Status      -- Status code from CreateSection call
  1833.     bNewConsole -- Pif can exec only from a new console
  1834. Return Value:
  1835.     file is a compif dos application
  1836.     SCS_DOS_BINARY - ".com", may also be a .exe extension
  1837.     SCS_PIF_BINARY - ".pif"
  1838.     0 -- file is not a dos application, may be a .bat or .cmd file
  1839. --*/
  1840. {
  1841.     UNICODE_STRING String;
  1842.          // check for .com extension
  1843.     String.Length = BaseDotComSuffixName.Length;
  1844.     String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1845.                     sizeof(WCHAR)]);
  1846.     if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE))
  1847.         return BINARY_TYPE_DOS_COM;
  1848.         // check for .pif extension
  1849.     String.Length = BaseDotPifSuffixName.Length;
  1850.     String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1851.                     sizeof(WCHAR)]);
  1852.     if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE))
  1853.         return BINARY_TYPE_DOS_PIF;
  1854.         // check for .exe extension
  1855.     String.Length = BaseDotExeSuffixName.Length;
  1856.     String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1857.         sizeof(WCHAR)]);
  1858.     if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE))
  1859.         return BINARY_TYPE_DOS_EXE;
  1860.     return 0;
  1861. }
  1862. BOOL
  1863. BaseGetVdmConfigInfo(
  1864.     IN  LPCWSTR CommandLine,
  1865.     IN  ULONG   DosSeqId,
  1866.     IN  ULONG   BinaryType,
  1867.     IN  PUNICODE_STRING CmdLineString,
  1868.     OUT PULONG VdmSize
  1869.     )
  1870. /*++
  1871. Routine Description:
  1872.     This routine locates the VDM configuration information for Wow vdms in
  1873.     the system configuration file.  It also reconstructs the commandline so
  1874.     that we can start the VDM.  The new command line is composed from the
  1875.     information in the configuration file + the old command line.
  1876. Arguments:
  1877.     CommandLine -- pointer to a string pointer that is used to pass the
  1878.         command line string
  1879.     DosSeqId - new console session id. This parameter is also valid for
  1880.                shared wow as it is passed to ntvdm as -i parameter. Another
  1881.                parameter to identify shared wow is passed to ntvdm as
  1882.                '-ws' where 'w' stands for wow app, 's' stands for separate
  1883.                In response to this 's' parameter ntvdm launches a
  1884.                separate wow (one-time shot). By default, ntvdm starts a shared
  1885.                wow.
  1886.     VdmSize -- Returns the size in bytes of the VDM to be created
  1887.     BinaryType - dos, sharedwow, sepwow
  1888. Return Value:
  1889.     TRUE -- VDM configuration information was available
  1890.     FALSE -- VDM configuration information was not available
  1891. Notes:
  1892. --*/
  1893. {
  1894.     NTSTATUS Status;
  1895.     BOOL bRet;
  1896.     DWORD dw;
  1897.     ANSI_STRING AnsiString;
  1898.     LPSTR NewCmdLine=NULL;
  1899.     PCH   pSrc, pDst, pch;
  1900.     ULONG Len;
  1901.     char CmdLine[MAX_VDM_CFG_LINE];
  1902.     CmdLineString->Buffer = NULL;
  1903.     Len = MAX_VDM_CFG_LINE;
  1904.     if (BinaryType == BINARY_TYPE_DOS) {
  1905.         bRet = BaseGetVDMKeyword(CMDLINE, CmdLine, &Len, DOSSIZE, VdmSize);
  1906.         }
  1907.     else {
  1908.         bRet = BaseGetVDMKeyword(WOWCMDLINE, CmdLine, &Len, WOWSIZE, VdmSize);
  1909.         }
  1910.     if (!bRet) {
  1911.         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1912.         return FALSE;
  1913.         }
  1914.     //
  1915.     // Allocate memory to replace the CommandLine
  1916.     // extra space is needed for long->short name conversion,
  1917.     // separate wow, and extension.
  1918.     //
  1919.     NewCmdLine = RtlAllocateHeap(RtlProcessHeap(),
  1920.                                  MAKE_TAG( VDM_TAG ),
  1921.                                  MAX_PATH + MAX_VDM_CFG_LINE
  1922.                                  );
  1923.     if (!NewCmdLine) {
  1924.         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1925.         return FALSE;
  1926.         }
  1927.     //
  1928.     // Copy over the cmdline checking for special args
  1929.     // and locating the beg of wowkernel
  1930.     //
  1931.     pSrc = CmdLine;
  1932.     pDst = NewCmdLine;
  1933.     //
  1934.     // first token must be "\%SystemRoot%\system32\ntvdm", search
  1935.     // for the tail of the pathname to traverse possible long file name
  1936.     // safely.
  1937.     //
  1938.     pch = strstr(pSrc, "\system32\ntvdm");
  1939.     if (!pch) {
  1940.         BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1941.         return FALSE;
  1942.         }
  1943.     // mov pch to trailing space in "ntvdm "
  1944.     while (*pch && *pch != ' ') {
  1945.         pch++;
  1946.         }
  1947.     //
  1948.     // copy first token (ntvdm path name), surrounded by quotes for
  1949.     // possible long file name
  1950.     //
  1951.    *pDst++ = '"';
  1952.     while (pSrc < pch) {
  1953.        *pDst++ = *pSrc++;
  1954.        }
  1955.     *pDst++ = '"';
  1956.     //
  1957.     // Add -f arg, so ntvdm knows it wasn't invoked directly
  1958.     //
  1959.     *pDst++ = ' ';
  1960.     *pDst++ = '-';
  1961.     *pDst++ = 'f';
  1962.     //
  1963.     // Add DosSeqId for new console
  1964.     //
  1965.     if (DosSeqId) {
  1966.         sprintf(pDst, " -i%lx", DosSeqId);
  1967.         pDst += strlen(pDst);
  1968.         }
  1969.     //
  1970.     // Copy over everything up to the " -a " (exclusive)
  1971.     // CAVEAT: we assume -a is last
  1972.     //
  1973.     pch = strstr(pSrc, " -a ");
  1974.     if (pch) {
  1975.         while (pSrc < pch) {
  1976.            *pDst++ = *pSrc++;
  1977.            }
  1978.         }
  1979.     else {
  1980.         while (*pSrc) {
  1981.            *pDst++ = *pSrc++;
  1982.            }
  1983.         }
  1984.     *pDst = '';
  1985.     //
  1986.     // for wow -a is mandatory to specify win16 krnl, and is expected
  1987.     // to be the last cmdline parameter
  1988.     //
  1989.     if (BinaryType != BINARY_TYPE_DOS) { // shared wow, sep wow
  1990.         PCH pWowKernel;
  1991.         if (!*pSrc) {
  1992.             BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1993.             return FALSE;
  1994.             }
  1995.         //
  1996.         // Add -w to tell ntvdm its wow (mandatory)
  1997.         //
  1998.         *pDst++ = ' ';
  1999.         *pDst++ = '-';
  2000.         *pDst++ = 'w';
  2001.         //
  2002.         // identify that this wow is a separate wow by -ws
  2003.         //
  2004.         if (BINARY_TYPE_SEPWOW == BinaryType) {
  2005.            *pDst++ = 's';
  2006.         }
  2007.         //
  2008.         // copy over the " -a WowKernelPathname" argument
  2009.         // and locate beg of WowKernelPathname in destination
  2010.         //
  2011.         pWowKernel = pDst;
  2012.         while (*pSrc) {
  2013.            *pDst++ = *pSrc++;
  2014.            }
  2015.         pWowKernel += 4;      // find beg of WowKernelPathaname
  2016.         while (*pWowKernel == ' ') {
  2017.            pWowKernel++;
  2018.            }
  2019.         //
  2020.         // Append file extension to destination
  2021.         //
  2022.         strcpy(pDst, ".exe");
  2023.         //
  2024.         // convert wowkernel to short name
  2025.         //
  2026.         Len = MAX_PATH + MAX_VDM_CFG_LINE - (ULONG)((ULONG_PTR)pWowKernel - (ULONG_PTR)NewCmdLine) -1;
  2027.         dw = GetShortPathNameA(pWowKernel, pWowKernel, Len);
  2028.         if (dw > Len) {
  2029.             RtlFreeHeap(RtlProcessHeap(), 0, NewCmdLine);
  2030.             return FALSE;
  2031.             }
  2032.         }
  2033.     RtlInitAnsiString(&AnsiString, NewCmdLine);
  2034.     Status = RtlAnsiStringToUnicodeString(CmdLineString, &AnsiString, TRUE);
  2035.     if (!NT_SUCCESS(Status)) {
  2036.         BaseSetLastNTError(Status);
  2037.         RtlFreeHeap(RtlProcessHeap(), 0, NewCmdLine);
  2038.         CmdLineString->Buffer = NULL;
  2039.         return FALSE;
  2040.         }
  2041.     RtlFreeHeap(RtlProcessHeap(), 0, NewCmdLine);
  2042.     return TRUE;
  2043. }
  2044. BOOL
  2045. BaseCheckForVDM(
  2046.     IN HANDLE hProcess,
  2047.     OUT LPDWORD lpExitCode
  2048.     )
  2049. {
  2050.     NTSTATUS Status;
  2051.     EVENT_BASIC_INFORMATION ebi;
  2052.     BASE_API_MSG m;
  2053.     PBASE_GET_VDM_EXIT_CODE_MSG a = (PBASE_GET_VDM_EXIT_CODE_MSG)&m.u.GetVDMExitCode;
  2054.     Status = NtQueryEvent (
  2055.                 hProcess,
  2056.                 EventBasicInformation,
  2057.                 &ebi,
  2058.                 sizeof(ebi),
  2059.                 NULL);
  2060.     if(!NT_SUCCESS(Status))
  2061.         return FALSE;
  2062.     a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  2063.     a->hParent = hProcess;
  2064.     Status = CsrClientCallServer(
  2065.                       (PCSR_API_MSG)&m,
  2066.                       NULL,
  2067.                       CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  2068.                       BasepGetVDMExitCode),
  2069.                       sizeof( *a )
  2070.                       );
  2071.     if (!NT_SUCCESS(Status)) {
  2072.         return FALSE;
  2073.         }
  2074.     *lpExitCode = (DWORD)a->ExitCode;
  2075.     return TRUE;
  2076. }
  2077. DWORD
  2078. APIENTRY
  2079. GetShortPathNameA(
  2080.     IN  LPCSTR  lpszLongPath,
  2081.     IN  LPSTR   lpShortPath,
  2082.     IN  DWORD   cchBuffer
  2083.     )
  2084. {
  2085.     UNICODE_STRING  UString, UStringRet;
  2086.     ANSI_STRING     AString;
  2087.     NTSTATUS        Status;
  2088.     WCHAR           TempPathW[MAX_PATH];
  2089.     LPWSTR          lpShortPathW = NULL;
  2090.     DWORD           ReturnValue;
  2091.     DWORD           ReturnValueW;
  2092.     if (lpszLongPath == NULL) {
  2093.         SetLastError(ERROR_INVALID_PARAMETER);
  2094.         return 0;
  2095.         }
  2096.     // We have to initialize it before the "try" statement
  2097.     AString.Buffer = NULL;
  2098.     UString.Buffer = NULL;
  2099.     ReturnValue = 0;
  2100.     ReturnValueW = 0;
  2101.     try {
  2102.         if (!Basep8BitStringToDynamicUnicodeString(&UString, lpszLongPath )) {
  2103.             goto gspTryExit;
  2104.             }
  2105.         // we have to get the real converted path in order to find out
  2106.         // the required length. An UNICODE char does not necessarily convert
  2107.         // to one ANSI char(A DBCS is basically TWO ANSI char!!!!!).
  2108.         // First, we use the buffer allocated from the stack. If the buffer
  2109.         // is too small, we then allocate it from heap.
  2110.         // A check of (lpShortPathW && TempPathW != lpShortPathW) will reveal
  2111.         // if we have allocated a buffer from heap and need to release it.
  2112.         lpShortPathW = TempPathW;
  2113.         ReturnValueW = GetShortPathNameW(UString.Buffer, lpShortPathW, sizeof(TempPathW) / sizeof(WCHAR));
  2114.         if (ReturnValueW >= sizeof(TempPathW) / sizeof(WCHAR))
  2115.             {
  2116.             // the stack-based buffer is too small. Allocate a new buffer
  2117.             // from heap.
  2118.             lpShortPathW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2119.                                         ReturnValueW * sizeof(WCHAR)
  2120.                                         );
  2121.             if (lpShortPathW) {
  2122.                 ReturnValueW = GetShortPathNameW(UString.Buffer, lpShortPathW, ReturnValueW);
  2123.                 }
  2124.             else {
  2125.                 ReturnValueW = 0;
  2126.                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2127.                 }
  2128.             }
  2129.         if (ReturnValueW)
  2130.             {
  2131.             // we are here because we have something interesting left to do.
  2132.             // Convert the UNICODE path name to ANSI(or OEM).
  2133.             UString.MaximumLength = (USHORT)((ReturnValueW + 1) * sizeof(WCHAR));
  2134.             UStringRet.Buffer = lpShortPathW;
  2135.             UStringRet.Length = (USHORT)(ReturnValueW * sizeof(WCHAR));
  2136.             Status = BasepUnicodeStringTo8BitString(&AString,
  2137.                                                     &UStringRet,
  2138.                                                     TRUE
  2139.                                                     );
  2140.             if (!NT_SUCCESS(Status))
  2141.                 {
  2142.                 BaseSetLastNTError(Status);
  2143.                 ReturnValue=0;
  2144.                 goto gspTryExit;
  2145.                 }
  2146.             // now AString.Length contains the size of the converted path
  2147.             // name. If the caller provides enough buffer, copy the
  2148.             // path name.
  2149.             ReturnValue = AString.Length;
  2150.             if (ARGUMENT_PRESENT(lpShortPath) && cchBuffer > ReturnValue)
  2151.                 {
  2152.                 RtlMoveMemory(lpShortPath, AString.Buffer, ReturnValue);
  2153.                 // terminate the string with NULL char
  2154.                 lpShortPath[ReturnValue] = '';
  2155.                 }
  2156.             else
  2157.                 {
  2158.                 // either the caller does not provide a buffer or
  2159.                 // the provided buffer is too small return the required size,
  2160.                 // including the terminated null char
  2161.                 ReturnValue++;
  2162.                 }
  2163.             }
  2164. gspTryExit:;
  2165.         }
  2166.     finally {
  2167.             if (UString.Buffer)
  2168.                 RtlFreeUnicodeString(&UString);
  2169.             if (AString.Buffer)
  2170.                 RtlFreeAnsiString(&AString);
  2171.             if (lpShortPathW && lpShortPathW != TempPathW)
  2172.                 RtlFreeHeap(RtlProcessHeap(), 0, lpShortPathW);
  2173.         }
  2174.     return ReturnValue;
  2175. }
  2176. /****
  2177. GetShortPathName
  2178. Description:
  2179.     This function converts the given path name to its short form if
  2180.      needed. The conversion  may not be necessary and in that case,
  2181.      this function simply copies down the given name to the return buffer.
  2182.     The caller can have the return buffer set equal to the given path name
  2183.      address.
  2184. Parameters:
  2185.     lpszLongPath -  Points to a NULL terminated string.
  2186.     lpszShortPath - Buffer address to return the short name.
  2187.     cchBuffer - Buffer size in char of lpszShortPath.
  2188. Return Value
  2189.     If the GetShortPathName function succeeds, the return value is the length,
  2190.     in characters, of the string copied to lpszShortPath,
  2191.     not including the terminating
  2192.     null character.
  2193.     If the lpszShortPath is too small, the return value is
  2194.     the size of the buffer, in
  2195.     characters, required to hold the path.
  2196.     If the function fails, the return value is zero. To get
  2197.     extended error information, use
  2198.     the GetLastError function.
  2199. Remarks:
  2200.     The "short name" can be longer than its "long name". lpszLongPath doesn't
  2201.     have to be a fully qualified path name or a long path name.
  2202. ****/
  2203. DWORD
  2204. APIENTRY
  2205. GetShortPathNameW(
  2206.     IN  LPCWSTR lpszLongPath,
  2207.     IN  LPWSTR  lpszShortPath,
  2208.     IN  DWORD   cchBuffer
  2209.     )
  2210. {
  2211.     LPCWSTR         pcs;
  2212.     LPWSTR          pSrcCopy, pSrc, pFirst, pLast, pDst;
  2213.     WCHAR           wch;
  2214.     HANDLE          FindHandle;
  2215.     WIN32_FIND_DATAW        FindData;
  2216.     LPWSTR          Buffer;
  2217.     DWORD           ReturnLen, Length;
  2218.     UINT PrevErrorMode;
  2219.     if (!ARGUMENT_PRESENT(lpszLongPath)) {
  2220.         SetLastError(ERROR_INVALID_PARAMETER);
  2221.         return 0;
  2222.         }
  2223.     //
  2224.     // override the error mode since we will be touching the media.
  2225.     // This is to prevent file system's pop-up when the given path does not
  2226.     // exist or the media is not available.
  2227.     // we are doing this because we can not depend on the caller's current
  2228.     // error mode. NOTE: the old error mode must be restored.
  2229.     PrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  2230.     try {
  2231.         Buffer = NULL;
  2232.         pSrcCopy = NULL;
  2233.         // first, make sure the given path exist
  2234.         if (0xFFFFFFFF == GetFileAttributesW(lpszLongPath))
  2235.         {
  2236.             //
  2237.             // (bjm - 3/17/99)
  2238.             // This behavior (failing if the file does not exist) is new (to NT) with NT 5.  
  2239.             // (It's the Win9x behavior.)
  2240.             // Give an exception to Norton AntiVirus Uninstall.
  2241.             // If we fail this call, there will be a registry value left behind in VDD that'll cause
  2242.             // undeserved ugly messages for a user.  Norton AV Uninstall counts on NT 4 behavior
  2243.             // which did not care if the file existed to do this conversion.  This was changed in
  2244.             // NT 5.0 to match Win9x behavior.
  2245.             //
  2246.             if ( !NtCurrentPeb() || !(NtCurrentPeb()->AppCompatInfo) ||
  2247.                 !(((PAPP_COMPAT_INFO)(NtCurrentPeb()->AppCompatInfo))->CompatibilityFlags.QuadPart & KACF_OLDGETSHORTPATHNAME ) )
  2248.             {
  2249.                 // last error has been set by GetFileAttributes
  2250.                 ReturnLen = 0;
  2251.                 goto gsnTryExit;
  2252.             }
  2253.         }
  2254.         
  2255.         pcs = SkipPathTypeIndicator_U(lpszLongPath);
  2256.         if (!pcs || *pcs == UNICODE_NULL || !FindLFNorSFN_U((LPWSTR)pcs, &pFirst, &pLast, TRUE))
  2257.             {
  2258.             // nothing to convert, copy down the source string
  2259.             // to the buffer if necessary
  2260.             ReturnLen = wcslen(lpszLongPath);
  2261.             if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2262.                 {
  2263.                 if (lpszShortPath != lpszLongPath)
  2264.                     RtlMoveMemory(lpszShortPath, lpszLongPath,
  2265.                                   (ReturnLen + 1) * sizeof(WCHAR)
  2266.                                   );
  2267.                 }
  2268.             else {
  2269.                 // the caller does not provide enough buffer, return
  2270.                 // necessary string length plus the terminated null char
  2271.                 ReturnLen++;
  2272.                 }
  2273.             goto gsnTryExit;
  2274.             }
  2275.         // conversions  are necessary, make a local copy of the string
  2276.         // because we have to party on it.
  2277.         ASSERT(!pSrcCopy);
  2278.         // get the source string length
  2279.         Length  = wcslen(lpszLongPath) + 1;
  2280.         pSrcCopy = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2281.                                    Length * sizeof(WCHAR)
  2282.                                    );
  2283.         if (!pSrcCopy) {
  2284.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2285.             goto gsnTryExit;
  2286.             }
  2287.         wcsncpy(pSrcCopy, lpszLongPath, Length);
  2288.         // pFirst points to the first char of the very first LFN in the path
  2289.         // pLast points to the char right after the last char of the very
  2290.         // first LFN in the path. *pLast could be UNICODE_NULL
  2291.         pFirst = pSrcCopy + (pFirst - lpszLongPath);
  2292.         pLast = pSrcCopy  + (pLast - lpszLongPath);
  2293.         //
  2294.         // We allow lpszShortPath be overlapped with lpszLongPath so
  2295.         // allocate a local buffer.
  2296.         pDst = lpszShortPath;
  2297.         if (cchBuffer > 0 && ARGUMENT_PRESENT(lpszShortPath) &&
  2298.             (lpszShortPath >= lpszLongPath &&lpszShortPath < lpszLongPath + Length ||
  2299.              lpszShortPath < lpszLongPath && lpszShortPath + cchBuffer >= lpszLongPath))
  2300.             {
  2301.             ASSERT(!Buffer);
  2302.             Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2303.                                            cchBuffer * sizeof(WCHAR));
  2304.             if (!Buffer){
  2305.                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2306.                 goto gsnTryExit;
  2307.             }
  2308.             pDst = Buffer;
  2309.         }
  2310.         pSrc = pSrcCopy;
  2311.         ReturnLen = 0;
  2312.         do {
  2313.             // there are three pointers involve in the conversion loop:
  2314.             // pSrc, pFirst and pLast. Their relationship
  2315.             // is:
  2316.             //
  2317.             // "c:long~1.1\foo.bar\long~2.2\bar"
  2318.             //  ^          ^          ^       ^
  2319.             //  |          |          |       |
  2320.             //  |          pSrc       pFirst  pLast
  2321.             //  pSrcCopy
  2322.             //
  2323.             // pSrcCopy always points to the very first char of the entire
  2324.             // path.
  2325.             //
  2326.             // chars between pSrc(included) and pFirst(not included)
  2327.             // do not need conversion so we simply copy them.
  2328.             // chars between pFirst(included) and pLast(not included)
  2329.             // need conversion.
  2330.             //
  2331.             Length = (ULONG)(pFirst - pSrc);
  2332.             if (Length) {
  2333.                 ReturnLen += Length;
  2334.                 if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath)) {
  2335.                     RtlMoveMemory(pDst, pSrc, Length * sizeof(WCHAR));
  2336.                     pDst += Length;
  2337.                     }
  2338.                 }
  2339.             wch = *pLast;
  2340.             *pLast = UNICODE_NULL;
  2341.             FindHandle = FindFirstFileW(pSrcCopy, &FindData);
  2342.             *pLast = wch;
  2343.             if (INVALID_HANDLE_VALUE != FindHandle) {
  2344.                 FindClose(FindHandle);
  2345.                 // if no short name could be found, copy the original name.
  2346.                 // the origian name starts with pFirst(included) and ends
  2347.                 // with pLast(excluded).
  2348.                 if (!(Length = wcslen(FindData.cAlternateFileName)))
  2349.                     Length = (ULONG)(pLast - pFirst);
  2350.                 else
  2351.                     pFirst = FindData.cAlternateFileName;
  2352.                 ReturnLen += Length;
  2353.                 if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2354.                     {
  2355.                     RtlMoveMemory(pDst, pFirst, Length * sizeof(WCHAR));
  2356.                     pDst += Length;
  2357.                     }
  2358.                  }
  2359.             else {
  2360.                 // part of the path does not exist, fail the function
  2361.                 //
  2362.                 ReturnLen = 0;
  2363.                 break;
  2364.                 }
  2365.             // move to next path name
  2366.             pSrc = pLast;
  2367.             if (*pLast == UNICODE_NULL)
  2368.                 break;
  2369.             }while (FindLFNorSFN_U(pSrc, &pFirst, &pLast, TRUE));
  2370.         // if ReturnLen == 0, we fail somewhere inside while loop.
  2371.         if (ReturnLen) {
  2372.             // (*pSrc == UNICODE_NULL) means the last pathname is a LFN which
  2373.             // has been dealt with. otherwise, the substring pointed by
  2374.             // pSrc is a legal short path name and we have to copy it
  2375.             //Length could be zero
  2376.             Length = wcslen(pSrc);
  2377.             ReturnLen += Length;
  2378.             if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2379.                 {
  2380.                 //include the terminated null char
  2381.                 RtlMoveMemory(pDst, pSrc, (Length + 1)* sizeof(WCHAR));
  2382.                 if (Buffer)
  2383.                     RtlMoveMemory(lpszShortPath, Buffer, (ReturnLen + 1) * sizeof(WCHAR));
  2384.                 }
  2385.             else
  2386.                 // not enough buffer, the return value counts the terminated NULL
  2387.                 ReturnLen++;
  2388.             }
  2389. gsnTryExit:;
  2390.         }
  2391.     finally {
  2392.          if (Buffer)
  2393.             RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
  2394.          if (pSrcCopy)
  2395.             RtlFreeHeap(RtlProcessHeap(), 0, pSrcCopy);
  2396.         }
  2397.     // restore the error mode
  2398.     SetErrorMode(PrevErrorMode);
  2399.     return ReturnLen;
  2400. }
  2401. /**
  2402.    function to create VDM environment for the new executable.
  2403.    Input:   lpEnvironmen = optinal environment strings prototype in UNICODE.
  2404.                            If it is NULL, this function use the environment
  2405.                            block attached to the process
  2406.             pAStringEnv  = pointer to a ANSI_STRING to receive the
  2407.                            new environment strings.
  2408.             pUStringEnv  = pointer to a UNICODE_STRING to receive the
  2409.                            new environment strings.
  2410.     Output: FALSE if the creattion failed.
  2411.             TRUE  creation successful, pAStringEnv has been setup.
  2412.     This function was provided so that BaseCheckVdm can have correct
  2413.     environment(includes the newly create NTVDM process). This was done
  2414.     because before command.com gets the next command, users can have
  2415.     tons of things specified in config.sys and autoexec.bat which
  2416.     may rely on current directory of each drive.
  2417. **/
  2418. BOOL BaseCreateVDMEnvironment(
  2419.     PWCHAR lpEnvironment,
  2420.     ANSI_STRING * pAStringEnv,
  2421.     UNICODE_STRING  *pUStringEnv
  2422.     )
  2423. {
  2424.     WCHAR  *pEnv, *pDst, *EnvStrings,* pTmp, *pNewEnv;
  2425.     DWORD   cchEnv, dw, Length, dwRemain;
  2426.     NTSTATUS    Status;
  2427.     UINT        NameType;
  2428.     BOOL        bRet = FALSE;
  2429.     SIZE_T      EnvSize;
  2430.     if (!ARGUMENT_PRESENT(pAStringEnv) || !ARGUMENT_PRESENT(pUStringEnv)){
  2431.         SetLastError(ERROR_INVALID_PARAMETER);
  2432.         return FALSE;
  2433.         }
  2434.     try {
  2435.         // the environment strings are shared by every thread of the same
  2436.         // process. Since we have no idea of what the caller process
  2437.         // is, we have to grab the entire environment to our local buffer in one
  2438.         // shot then we can walk through the strings.
  2439.         // Note that if another thread makes call to RtlSetEnvironmentVariable
  2440.         // then we are out of sync. It is a problem of process structure and
  2441.         // I don't want to think about it now.
  2442.         // The funny thing is that we have to assume the environment
  2443.         // is a block of strings(otherwise, how can we do it?)t, nothing more and
  2444.         // nothing less. If someday and somebody dares to change it, he will be
  2445.         // the one to blame. If the caller(CreateProcess)
  2446.         // provides the environment, we assume it is safe to walk through it.
  2447.         //
  2448.         if (lpEnvironment == NULL) {
  2449.             // create a new environment and inherit the current process env
  2450.             Status = RtlCreateEnvironment(TRUE, (PVOID *)&EnvStrings);
  2451.             if (!NT_SUCCESS(Status))
  2452.                 goto bveTryExit;
  2453.             }
  2454.         else
  2455.             EnvStrings = lpEnvironment;
  2456.         if (EnvStrings == NULL) {
  2457.             SetLastError(ERROR_BAD_ENVIRONMENT);
  2458.             goto bveTryExit;
  2459.             }
  2460.         // figure out how long the environment is
  2461.         // why can Rtl just provides such a function for us?
  2462.         //
  2463.         cchEnv = 0;
  2464.         pEnv = EnvStrings;
  2465.         // environment is double-null terminated
  2466.         while (!(*pEnv++ == UNICODE_NULL && *pEnv == UNICODE_NULL))
  2467.             cchEnv++;
  2468.         // count the last two NULLs
  2469.         cchEnv += 2;
  2470.         // we don't want to change the original environment, so
  2471.         // make a local buffer for it.
  2472.         EnvSize = (cchEnv + MAX_PATH) * sizeof(WCHAR);
  2473.         pNewEnv = NULL;
  2474.         Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  2475.                                           &pNewEnv,
  2476.                                           0,
  2477.                                           &EnvSize,
  2478.                                           MEM_COMMIT,
  2479.                                           PAGE_READWRITE
  2480.                                         );
  2481.         if (!NT_SUCCESS(Status) ) {
  2482.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2483.             goto bveTryExit;
  2484.             }
  2485.         // give the last two for null
  2486.         dwRemain = MAX_PATH - 2;
  2487.         // now walk through the environment string
  2488.         pEnv = EnvStrings;
  2489.         // the new environmet will be
  2490.         pDst = pNewEnv;
  2491.         while (*pEnv != UNICODE_NULL) {
  2492.             // current directory environment has the form as:
  2493.             // "=d:=d:pathname" where d: is the drive designator.
  2494.             if (pEnv[0] == L'=')
  2495.                 {
  2496.                 if ((pEnv[1] >= L'A' && pEnv[1] <= L'Z' || pEnv[1] >= L'a' && pEnv[1] <= L'z') &&
  2497.                      pEnv[2] == L':' && pEnv[3] == L'=' && wcslen(pEnv) >= 7)
  2498.                     {
  2499.                     // hack hack!!!!
  2500.                     // if the path points to the root directory,
  2501.                     // bypass the conversion. Dos or Wow keeps current directory
  2502.                     // for every valid drive. If we do the conversion for
  2503.                     // every current directory, it could take several
  2504.                     // seconds on removable drives, especially, on
  2505.                     // floppy drives.
  2506.                     if (pEnv[7] == UNICODE_NULL &&
  2507.                         (pEnv[6] == L'\' || pEnv[6] == L'/') &&
  2508.                         pEnv[5] == L':' &&
  2509.                         (pEnv[4] >= L'A' && pEnv[4] <= L'Z' ||
  2510.                          pEnv[4] >= L'a' && pEnv[4] <= L'z'))
  2511.                         {
  2512.                         NameType = ENV_NAME_TYPE_NO_PATH;
  2513.                         }
  2514.                     else
  2515.                         {
  2516.                         // copy "=N:=", where N is the drive letter
  2517.                         *pDst++ = *pEnv++;*pDst++ = *pEnv++;
  2518.                         *pDst++ = *pEnv++;*pDst++ = *pEnv++;
  2519.                         NameType = ENV_NAME_TYPE_SINGLE_PATH;
  2520.                         }
  2521.                     }
  2522.                 else {
  2523.                     // a weird environment was detected.
  2524.                     // treat it as no path
  2525.                     NameType = ENV_NAME_TYPE_NO_PATH;
  2526.                     }
  2527.                 }
  2528.             else {
  2529.                 pTmp = pEnv;
  2530.                 // copy down the name and the '='
  2531.                 while (*pEnv != UNICODE_NULL && (*pDst++ = *pEnv++) != L'=')
  2532.                     ;
  2533.                 NameType = BaseGetEnvNameType_U(pTmp, (DWORD)(pEnv - pTmp) - 1);
  2534.                 }
  2535.             if (NameType == ENV_NAME_TYPE_NO_PATH) {
  2536.                 while ((*pDst++ = *pEnv++) != UNICODE_NULL)
  2537.                     ;
  2538.                 }
  2539.             else if (NameType == ENV_NAME_TYPE_SINGLE_PATH) {
  2540.                     Length = wcslen(pEnv) + 1;
  2541.                     dw = GetShortPathNameW(pEnv, pDst, Length + dwRemain);
  2542.                     // if the conversion failed, we simply pass down the original
  2543.                     // one no matter what the reason is. This is done because we
  2544.                     // are doing the environment strings.
  2545.                     if (dw == 0 || dw >= Length + dwRemain){
  2546.                         RtlMoveMemory(pDst, pEnv, Length * sizeof(WCHAR));
  2547.                         dw = Length - 1;
  2548.                         }
  2549.                     pDst += dw + 1;
  2550.                     pEnv += Length;
  2551.                     if (dw > Length)
  2552.                         dwRemain -= dw - Length;
  2553.                     }
  2554.                  else {
  2555.                     // multiple path name found.
  2556.                     // the character ';' is used for seperator
  2557.                      pTmp = pEnv;
  2558.                      while(*pEnv != UNICODE_NULL) {
  2559.                         if (*pEnv == L';') {
  2560.                             // length not include the ';'
  2561.                             Length = (DWORD)(pEnv - pTmp);
  2562.                             if (Length > 0) {
  2563.                                 *pEnv = UNICODE_NULL;
  2564.                                 dw = GetShortPathNameW(pTmp, pDst, Length + 1 + dwRemain);
  2565.                                 // again, if the conversion failed, use the original one
  2566.                                 if (dw == 0 || dw > Length + dwRemain) {
  2567.                                     RtlMoveMemory(pDst, pTmp, Length * sizeof(WCHAR));
  2568.                                     dw = Length;
  2569.                                     }
  2570.                                 pDst += dw;
  2571.                                 *pDst++ = *pEnv++ = L';';
  2572.                                 if (dw > Length)
  2573.                                     dwRemain -= dw - Length;
  2574.                                 }
  2575.                              // skip all consecutive ';'
  2576.                              while (*pEnv == L';')
  2577.                                 *pDst++ = *pEnv++;
  2578.                              pTmp = pEnv;
  2579.                              }
  2580.                         else
  2581.                             pEnv++;
  2582.                         }
  2583.                     // convert the last one
  2584.                     if ((Length = (DWORD)(pEnv - pTmp)) != 0) {
  2585.                         dw = GetShortPathNameW(pTmp, pDst, Length+1 + dwRemain);
  2586.                         if (dw == 0 || dw > Length) {
  2587.                             RtlMoveMemory(pDst, pTmp, Length * sizeof(WCHAR));
  2588.                             dw = Length;
  2589.                             }
  2590.                         pDst += dw;
  2591.                         if (dw > Length)
  2592.                             dwRemain -= dw - Length;
  2593.                         }
  2594.                     *pDst++ = *pEnv++;
  2595.                     }
  2596.             }
  2597.         *pDst++ = UNICODE_NULL;
  2598.         cchEnv = (ULONG)((ULONG_PTR)pDst - (ULONG_PTR)pNewEnv);
  2599.         pUStringEnv->MaximumLength = pUStringEnv->Length = (USHORT)cchEnv;
  2600.         pUStringEnv->Buffer = pNewEnv;
  2601.         Status = RtlUnicodeStringToAnsiString(pAStringEnv,
  2602.                                               pUStringEnv,
  2603.                                               TRUE
  2604.                                               );
  2605.         if (!NT_SUCCESS(Status)) {
  2606.             BaseSetLastNTError(Status);
  2607.             }
  2608.         else
  2609.             bRet = TRUE;
  2610. bveTryExit:;
  2611.         }
  2612.     finally {
  2613.          if (lpEnvironment == NULL && EnvStrings != NULL)
  2614.             RtlDestroyEnvironment(EnvStrings);
  2615.         }
  2616.     return bRet;
  2617. }
  2618. /**
  2619.     Destroy the environment block created by BaseCreateVDMEnvironment
  2620.     Input: ANSI_STRING * pAnsiStringVDMEnv
  2621.                       Environment block in ANSI, should be freed via
  2622.                       RtlFreeAnsiString
  2623.            UNICODE_STRING * pUnicodeStringEnv
  2624.                       Environment block in UNICODE. The Buffer should
  2625.                       be freed with RtlFreeHeap.
  2626.     Output: should always be TRUE.
  2627. **/
  2628. BOOL
  2629. BaseDestroyVDMEnvironment(
  2630.     ANSI_STRING *pAStringEnv,
  2631.     UNICODE_STRING *pUStringEnv
  2632.     )
  2633. {
  2634.     if (pAStringEnv->Buffer)
  2635.         RtlFreeAnsiString(pAStringEnv);
  2636.     if (pUStringEnv->Buffer) {
  2637.         NTSTATUS Status;
  2638.         SIZE_T RegionSize;
  2639.         //
  2640.         // Free the specified environment variable block.
  2641.         //
  2642.         RegionSize = 0;
  2643.         Status = NtFreeVirtualMemory( NtCurrentProcess(),
  2644.                                       &pUStringEnv->Buffer,
  2645.                                       &RegionSize,
  2646.                                       MEM_RELEASE
  2647.                                     );
  2648.     }
  2649.     return TRUE;
  2650. }
  2651. /**
  2652.     This function returns the name type of the given environment variable name
  2653.     The name type has three possibilities. Each one represents if the
  2654.     given name can have pathnames as its value.
  2655.      ENV_NAME_TYPE_NO_PATH:   no pathname can be its value
  2656.      ENV_NAME_TYPE_SINGLE_PATH: single pathname
  2657.      ENV_NAME_MULTIPLE_PATH: multiple path
  2658.     SIDE NOTE:
  2659.         Currently, nt can not installed on a long path and it seems
  2660.         that systemroot and windir are never be in long path.
  2661. **/
  2662. UINT
  2663. BaseGetEnvNameType_U(WCHAR * Name, DWORD NameLength)
  2664. {
  2665. // so far we only take care of five predefined names:
  2666. // PATH
  2667. // WINDIR and
  2668. // SYSTEMROOT.
  2669. // TEMP
  2670. // TMP
  2671. //
  2672. static ENV_INFO     EnvInfoTable[STD_ENV_NAME_COUNT] = {
  2673.     {ENV_NAME_TYPE_MULTIPLE_PATH, ENV_NAME_PATH_LEN, ENV_NAME_PATH},
  2674.     {ENV_NAME_TYPE_SINGLE_PATH, ENV_NAME_WINDIR_LEN, ENV_NAME_WINDIR},
  2675.     {ENV_NAME_TYPE_SINGLE_PATH, ENV_NAME_SYSTEMROOT_LEN, ENV_NAME_SYSTEMROOT},
  2676.     {ENV_NAME_TYPE_MULTIPLE_PATH, ENV_NAME_TEMP_LEN, ENV_NAME_TEMP},
  2677.     {ENV_NAME_TYPE_MULTIPLE_PATH, ENV_NAME_TMP_LEN, ENV_NAME_TMP}
  2678.     };
  2679.    UINT NameType;
  2680.    int  i;
  2681.     NameType = ENV_NAME_TYPE_NO_PATH;
  2682.     for (i = 0; i < STD_ENV_NAME_COUNT; i++) {
  2683.         if (EnvInfoTable[i].NameLength == NameLength &&
  2684.             !_wcsnicmp(EnvInfoTable[i].Name, Name, NameLength)) {
  2685.             NameType = EnvInfoTable[i].NameType;
  2686.             break;
  2687.             }
  2688.         }
  2689.     return NameType;
  2690. }
  2691. DWORD
  2692. APIENTRY
  2693. GetLongPathNameA(
  2694.     IN  LPCSTR  lpszShortPath,
  2695.     IN  LPSTR   lpLongPath,
  2696.     IN  DWORD   cchBuffer
  2697.     )
  2698. {
  2699.     UNICODE_STRING  UString, UStringRet;
  2700.     ANSI_STRING     AString;
  2701.     NTSTATUS        Status;
  2702.     LPWSTR          lpLongPathW;
  2703.     WCHAR           TempPathW[MAX_PATH];
  2704.     DWORD           ReturnValue, ReturnValueW;
  2705.     if (lpszShortPath == NULL) {
  2706.         SetLastError(ERROR_INVALID_PARAMETER);
  2707.         return 0;
  2708.         }
  2709.     AString.Buffer = NULL;
  2710.     UString.Buffer = NULL;
  2711.     ReturnValue = 0;
  2712.     ReturnValueW = 0;
  2713.     try {
  2714.         if (!Basep8BitStringToDynamicUnicodeString(&UString, lpszShortPath )) {
  2715.             goto glpTryExit;
  2716.             }
  2717.         // we have to get the real converted path in order to find out
  2718.         // the required length. An UNICODE char does not necessarily convert
  2719.         // to one ANSI char(A DBCS is basically TWO ANSI char!!!!!).
  2720.         // First, we use the buffer allocated from the stack. If the buffer
  2721.         // is too small, we then allocate it from heap.
  2722.         // A check of (lpLongPathW && TempPathW != lpLongPathW) will reveal
  2723.         // if we have allocated a buffer from heap and need to release it.
  2724.         lpLongPathW = TempPathW;
  2725.         ReturnValueW = GetLongPathNameW(UString.Buffer, lpLongPathW, sizeof(TempPathW) / sizeof(WCHAR));
  2726.         if (ReturnValueW >= sizeof(TempPathW) / sizeof(WCHAR))
  2727.             {
  2728.             // the stack-based buffer is too small. Allocate a new buffer
  2729.             // from heap.
  2730.             lpLongPathW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2731.                                         ReturnValueW * sizeof(WCHAR)
  2732.                                         );
  2733.             if (lpLongPathW) {
  2734.                 ReturnValueW = GetLongPathNameW(UString.Buffer, lpLongPathW, ReturnValueW);
  2735.                 }
  2736.             else {
  2737.                 ReturnValueW = 0;
  2738.                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2739.                 }
  2740.             }
  2741.         if (ReturnValueW)
  2742.             {
  2743.             // we are here because we have something interesting left to do.
  2744.             // Convert the UNICODE path name to ANSI(or OEM).
  2745.             UString.MaximumLength = (USHORT)((ReturnValueW + 1) * sizeof(WCHAR));
  2746.             UStringRet.Buffer = lpLongPathW;
  2747.             UStringRet.Length = (USHORT)(ReturnValueW * sizeof(WCHAR));
  2748.             Status = BasepUnicodeStringTo8BitString(&AString,
  2749.                                                     &UStringRet,
  2750.                                                     TRUE
  2751.                                                     );
  2752.             if (!NT_SUCCESS(Status))
  2753.                 {
  2754.                 BaseSetLastNTError(Status);
  2755.                 ReturnValue=0;
  2756.                 goto glpTryExit;
  2757.                 }
  2758.             // now AString.Length contains the size of the converted path
  2759.             // name. If the caller provides enough buffer, copy the
  2760.             // path name.
  2761.             ReturnValue = AString.Length;
  2762.             if (ARGUMENT_PRESENT(lpLongPath) && cchBuffer > ReturnValue)
  2763.                 {
  2764.                 RtlMoveMemory(lpLongPath, AString.Buffer, ReturnValue);
  2765.                 // terminate the buffer with NULL char.
  2766.                 lpLongPath[ReturnValue] = '';
  2767.                 }
  2768.             else
  2769.                 {
  2770.                 // either the caller does not provide a buffer or
  2771.                 // the provided buffer is too small, return the required size,
  2772.                 // including the terminated null char.
  2773.                 ReturnValue++;
  2774.                 }
  2775.             }
  2776. glpTryExit:;
  2777.         }
  2778.     finally {
  2779.             if (UString.Buffer)
  2780.                 RtlFreeUnicodeString(&UString);
  2781.             if (AString.Buffer)
  2782.                 RtlFreeAnsiString(&AString);
  2783.             if (lpLongPathW && lpLongPathW != TempPathW)
  2784.                 RtlFreeHeap(RtlProcessHeap(), 0, lpLongPathW);
  2785.         }
  2786.     return ReturnValue;
  2787. }
  2788. DWORD
  2789. APIENTRY
  2790. GetLongPathNameW(
  2791.     IN  LPCWSTR lpszShortPath,
  2792.     IN  LPWSTR  lpszLongPath,
  2793.     IN  DWORD   cchBuffer
  2794. )
  2795. {
  2796.     LPCWSTR pcs;
  2797.     DWORD ReturnLen, Length;
  2798.     LPWSTR pSrc, pSrcCopy, pFirst, pLast, Buffer, pDst;
  2799.     WCHAR   wch;
  2800.     HANDLE          FindHandle;
  2801.     WIN32_FIND_DATAW        FindData;
  2802.     UINT PrevErrorMode;
  2803.     if (!ARGUMENT_PRESENT(lpszShortPath)) {
  2804.         SetLastError(ERROR_INVALID_PARAMETER);
  2805.         return 0;
  2806.         }
  2807.     //
  2808.     // override the error mode since we will be touching the media.
  2809.     // This is to prevent file system's pop-up when the given path does not
  2810.     // exist or the media is not available.
  2811.     // we are doing this because we can not depend on the caller's current
  2812.     // error mode. NOTE: the old error mode must be restored.
  2813.     PrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  2814.     try {
  2815.         Buffer = NULL;
  2816.         pSrcCopy = NULL;
  2817.         // first make sure the given path exist.
  2818.         //
  2819.         if (0xFFFFFFFF == GetFileAttributesW(lpszShortPath))
  2820.         {
  2821.             // last error has been set by GetFileAttributes
  2822.             ReturnLen = 0;
  2823.             goto glnTryExit;
  2824.         }
  2825.         pcs = SkipPathTypeIndicator_U(lpszShortPath);
  2826.         if (!pcs || *pcs == UNICODE_NULL || !FindLFNorSFN_U((LPWSTR)pcs, &pFirst, &pLast, FALSE))
  2827.             {
  2828.             // The path is ok and does not need conversion at all.
  2829.             // Check if we need to do copy
  2830.             ReturnLen = wcslen(lpszShortPath);
  2831.             if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszLongPath))
  2832.                 {
  2833.                 if (lpszLongPath != lpszShortPath)
  2834.                     RtlMoveMemory(lpszLongPath, lpszShortPath,
  2835.                                       (ReturnLen + 1)* sizeof(WCHAR)
  2836.                                       );
  2837.                 }
  2838.             else {
  2839.                 // No buffer or buffer too small, the return size
  2840.                 // has to count the terminated NULL char
  2841.                 ReturnLen++;
  2842.                 }
  2843.             goto glnTryExit;
  2844.             }
  2845.         // conversions  are necessary, make a local copy of the string
  2846.         // because we have to party on it.
  2847.         ASSERT(!pSrcCopy);
  2848.         Length = wcslen(lpszShortPath) + 1;
  2849.         pSrcCopy = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2850.                                    Length * sizeof(WCHAR)
  2851.                                    );
  2852.         if (!pSrcCopy) {
  2853.             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2854.             goto glnTryExit;
  2855.             }
  2856.         RtlMoveMemory(pSrcCopy, lpszShortPath, Length * sizeof(WCHAR));
  2857.         // pFirst points to the first char of the very first SFN in the path
  2858.         // pLast points to the char right after the last char of the very
  2859.         // first SFN in the path. *pLast could be UNICODE_NULL
  2860.         pFirst = pSrcCopy + (pFirst - lpszShortPath);
  2861.         pLast = pSrcCopy + (pLast - lpszShortPath);
  2862.         //
  2863.         // We allow lpszShortPath be overlapped with lpszLongPath so
  2864.         // allocate a local buffer if necessary:
  2865.         // (1) the caller does provide a legitimate buffer and
  2866.         // (2) the buffer overlaps with lpszShortName
  2867.         pDst = lpszLongPath;
  2868.         if (cchBuffer && ARGUMENT_PRESENT(lpszLongPath) &&
  2869.             (lpszLongPath >= lpszShortPath && lpszLongPath < lpszShortPath + Length ||
  2870.              lpszLongPath < lpszShortPath && lpszLongPath + cchBuffer >= lpszShortPath))
  2871.             {
  2872.             ASSERT(!Buffer);
  2873.             Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2874.                                            cchBuffer * sizeof(WCHAR));
  2875.             if (!Buffer){
  2876.                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2877.                 goto glnTryExit;
  2878.                 }
  2879.             pDst = Buffer;
  2880.             }
  2881.         pSrc = pSrcCopy;
  2882.         ReturnLen = 0;
  2883.         do {
  2884.             // there are three pointers involve in the conversion loop:
  2885.             // pSrc, pFirst and pLast. Their relationship
  2886.             // is:
  2887.             //
  2888.             // "c:long~1.1\foo.bar\long~2.2\bar"
  2889.             //  ^          ^          ^       ^
  2890.             //  |          |          |       |
  2891.             //  |          pSrc       pFirst  pLast
  2892.             //  pSrcCopy
  2893.             //
  2894.             // pSrcCopy always points to the very first char of the entire
  2895.             // path.
  2896.             //
  2897.             // chars between pSrc(included) and pFirst(not included)
  2898.             // do not need conversion so we simply copy them.
  2899.             // chars between pFirst(included) and pLast(not included)
  2900.             // need conversion.
  2901.             //
  2902.             Length = (ULONG)(pFirst - pSrc);
  2903.             ReturnLen += Length;
  2904.             if (Length && cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2905.                 {
  2906.                 RtlMoveMemory(pDst, pSrc, Length * sizeof(WCHAR));
  2907.                 pDst += Length;
  2908.                 }
  2909.             // now try to convert the name, chars between pFirst and (pLast - 1)
  2910.             wch = *pLast;
  2911.             *pLast = UNICODE_NULL;
  2912.             FindHandle = FindFirstFileW(pSrcCopy, &FindData);
  2913.             *pLast = wch;
  2914.             if (FindHandle != INVALID_HANDLE_VALUE){
  2915.                 FindClose(FindHandle);
  2916.                 // if no long name, copy the original name
  2917.                 // starts with pFirst(included) and ends with pLast(excluded)
  2918.                 if (!(Length = wcslen(FindData.cFileName)))
  2919.                     Length = (ULONG)(pLast - pFirst);
  2920.                 else
  2921.                     pFirst = FindData.cFileName;
  2922.                 ReturnLen += Length;
  2923.                 if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszLongPath))
  2924.                     {
  2925.                     RtlMoveMemory(pDst, pFirst, Length * sizeof(WCHAR));
  2926.                     pDst += Length;
  2927.                     }
  2928.                 }
  2929.             else {
  2930.                 // invalid path, reset the length, mark the error and
  2931.                 // bail out of the loop. We will be copying the source
  2932.                 // to destination later.
  2933.                 //
  2934.                 ReturnLen = 0;
  2935.                 break;
  2936.                 }
  2937.             pSrc = pLast;
  2938.             if (*pSrc == UNICODE_NULL)
  2939.                 break;
  2940.             } while (FindLFNorSFN_U(pSrc, &pFirst, &pLast, FALSE));
  2941.         if (ReturnLen) {
  2942.             //copy the rest of the path from pSrc. This may only contain
  2943.             //a single NULL char
  2944.             Length = wcslen(pSrc);
  2945.             ReturnLen += Length;
  2946.             if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszLongPath))
  2947.                 {
  2948.                 RtlMoveMemory(pDst, pSrc, (Length + 1) * sizeof(WCHAR));
  2949.                 if (Buffer)
  2950.                     RtlMoveMemory(lpszLongPath, Buffer, (ReturnLen + 1) * sizeof(WCHAR));
  2951.                 }
  2952.             else
  2953.                 ReturnLen++;
  2954.             }
  2955. glnTryExit:
  2956.         ;
  2957.         }
  2958.         finally {
  2959.             if (pSrcCopy)
  2960.                 RtlFreeHeap(RtlProcessHeap(), 0, pSrcCopy);
  2961.             if (Buffer)
  2962.                 RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
  2963.             }
  2964.     // restore error mode.
  2965.     SetErrorMode(PrevErrorMode);
  2966.     return ReturnLen;
  2967. }
  2968. /**
  2969.     Search for SFN(Short File Name) or LFN(Long File Name) in the
  2970.     given path depends on FindLFN.
  2971.     Input: LPWSTR Path
  2972.                 The given path name. Does not have to be fully qualified.
  2973.                 However, path type separaters are not allowed.
  2974.            LPWSTR* ppFirst
  2975.                 To return the pointer points to the first char
  2976.                 of the name found.
  2977.            LPWSTR* ppLast
  2978.                 To return the pointer points the char right after
  2979.                 the last char of the name found.
  2980.            BOOL FindLFN
  2981.                 TRUE to search for LFN, otherwise, search for SFN
  2982.     Output:
  2983.             TRUE
  2984.                 if the target file name type is found, ppFirst and
  2985.                 ppLast are filled with pointers.
  2986.             FALSE
  2987.                 if the target file name type not found.
  2988.     Remark: "\." and "\.." are special cases. When encountered, they
  2989.             are ignored and the function continue to search
  2990. **/
  2991. BOOL
  2992. FindLFNorSFN_U(
  2993.     LPWSTR  Path,
  2994.     LPWSTR* ppFirst,
  2995.     LPWSTR* ppLast,
  2996.     BOOL    FindLFN
  2997.     )
  2998. {
  2999.     LPWSTR pFirst, pLast;
  3000.     BOOL TargetFound;
  3001.     ASSERT(Path);
  3002.     pFirst = Path;
  3003.     TargetFound = FALSE;
  3004.     while(TRUE) {
  3005.         //skip over leading path separator
  3006.         // it is legal to have multiple path separators in between
  3007.         // name such as "foobar\\\multiplepathchar"
  3008.         while (*pFirst != UNICODE_NULL  && (*pFirst == L'\' || *pFirst == L'/'))
  3009.             pFirst++;
  3010.         if (*pFirst == UNICODE_NULL)
  3011.             break;
  3012.         pLast = pFirst + 1;
  3013.         while (*pLast != UNICODE_NULL && *pLast != L'\' && *pLast != L'/')
  3014.             pLast++;
  3015.         if (FindLFN)
  3016.             TargetFound = !IsShortName_U(pFirst, (int)(pLast - pFirst));
  3017.         else
  3018.             TargetFound = !IsLongName_U(pFirst, (int)(pLast - pFirst));
  3019.         if (TargetFound) {
  3020.             if(ppFirst && ppLast) {
  3021.                 *ppFirst = pFirst;
  3022.                 // pLast point to the last char of the path/file name
  3023.                 *ppLast = pLast;
  3024.                 }
  3025.             break;
  3026.             }
  3027.         if (*pLast == UNICODE_NULL)
  3028.             break;
  3029.         pFirst = pLast + 1;
  3030.         }
  3031.     return TargetFound;
  3032. }
  3033. LPCWSTR
  3034. SkipPathTypeIndicator_U(
  3035.     LPCWSTR Path
  3036.     )
  3037. {
  3038.     RTL_PATH_TYPE   RtlPathType;
  3039.     LPCWSTR         pFirst;
  3040.     DWORD           Count;
  3041.     RtlPathType = RtlDetermineDosPathNameType_U(Path);
  3042.     switch (RtlPathType) {
  3043.         // form: "\server_nameshare_namerest_of_the_path"
  3044.         case RtlPathTypeUncAbsolute:
  3045.             pFirst = Path + 2;
  3046.             Count = 2;
  3047.             // guard for UNICODE_NULL is necessary because
  3048.             // RtlDetermineDosPathNameType_U doesn't really
  3049.             // verify an UNC name.
  3050.             while (Count && *pFirst != UNICODE_NULL) {
  3051.                 if (*pFirst == L'\' || *pFirst == L'/')
  3052.                     Count--;
  3053.                 pFirst++;
  3054.                 }
  3055.             break;
  3056.         // form: "\.rest_of_the_path"
  3057.         case RtlPathTypeLocalDevice:
  3058.             pFirst = Path + 4;
  3059.             break;
  3060.         // form: "\."
  3061.         case RtlPathTypeRootLocalDevice:
  3062.             pFirst = NULL;
  3063.             break;
  3064.         // form: "D:rest_of_the_path"
  3065.         case RtlPathTypeDriveAbsolute:
  3066.             pFirst = Path + 3;
  3067.             break;
  3068.         // form: "D:rest_of_the_path"
  3069.         case RtlPathTypeDriveRelative:
  3070.             pFirst = Path + 2;
  3071.             break;
  3072.         // form: "rest_of_the_path"
  3073.         case RtlPathTypeRooted:
  3074.             pFirst = Path + 1;
  3075.             break;
  3076.         // form: "rest_of_the_path"
  3077.         case RtlPathTypeRelative:
  3078.             pFirst = Path;
  3079.             break;
  3080.         default:
  3081.             pFirst = NULL;
  3082.             break;
  3083.         }
  3084.     return pFirst;
  3085. }
  3086. /**
  3087.     This function determines if the given name is a valid short name.
  3088.     This function only does "obvious" testing since there are not precise
  3089.     ways to cover all the file systems(each file system has its own
  3090.     file name domain(for example, FAT allows all extended chars and space char
  3091.     while NTFS **may** not).
  3092.     The main purpose is to help the caller decide if a long to short name
  3093.     conversion is necessary. When in doubt, this function simply tells the
  3094.     caller that the given name is NOT a short name so that caller would
  3095.     do whatever it takes to convert the name.
  3096.     This function applies strict rules in deciding if the given name
  3097.     is a valid short name. For example, a name containing any extended chars
  3098.     is treated as invalid; a name with embedded space chars is also treated
  3099.     as invalid.
  3100.     A name is a valid short name if ALL the following conditions are met:
  3101.     (1). total length <= 13.
  3102.     (2). 0 < base name length <= 8.
  3103.     (3). extention name length <= 3.
  3104.     (4). only one '.' is allowed and must not be the first char.
  3105.     (5). every char must be legal defined by the IllegalMask array.
  3106.     null path, "." and ".." are treated valid.
  3107.     Input: LPCWSTR Name -  points to the name to be checked. It does not
  3108.                            have to be NULL terminated.
  3109.            int Length - Length of the name, not including teminated NULL char.
  3110.     output: TRUE - if the given name is a short file name.
  3111.             FALSE - if the given name is not a short file name
  3112. **/
  3113. // bit set -> char is illegal
  3114. DWORD   IllegalMask[] =
  3115. {
  3116.     // code 0x00 - 0x1F --> all illegal
  3117.     0xFFFFFFFF,
  3118.     // code 0x20 - 0x3f --> 0x20,0x22,0x2A-0x2C,0x2F and 0x3A-0x3F are illegal
  3119.     0xFC009C05,
  3120.     // code 0x40 - 0x5F --> 0x5B-0x5D are illegal
  3121.     0x38000000,
  3122.     // code 0x60 - 0x7F --> 0x7C is illegal
  3123.     0x10000000
  3124. };
  3125. BOOL
  3126. IsShortName_U(
  3127.     LPCWSTR Name,
  3128.     int     Length
  3129.     )
  3130. {
  3131.     int Index;
  3132.     BOOL ExtensionFound;
  3133.     DWORD      dwStatus;
  3134.     UNICODE_STRING UnicodeName;
  3135.     ANSI_STRING AnsiString;
  3136.     UCHAR      AnsiBuffer[MAX_PATH];
  3137.     UCHAR      Char;
  3138.     ASSERT(Name);
  3139.     // total length must less than 13(8.3 = 8 + 1 + 3 = 12)
  3140.     if (Length > 12)
  3141.         return FALSE;
  3142.     //  "" or "." or ".."
  3143.     if (!Length)
  3144.         return TRUE;
  3145.     if (L'.' == *Name)
  3146.     {
  3147.         // "." or ".."
  3148.         if (1 == Length || (2 == Length && L'.' == Name[1]))
  3149.             return TRUE;
  3150.         else
  3151.             // '.' can not be the first char(base name length is 0)
  3152.             return FALSE;
  3153.     }
  3154.     UnicodeName.Buffer = (LPWSTR)Name;
  3155.     UnicodeName.Length =
  3156.     UnicodeName.MaximumLength = (USHORT)(Length * sizeof(WCHAR));
  3157.     AnsiString.Buffer = AnsiBuffer;
  3158.     AnsiString.Length = 0;
  3159.     AnsiString.MaximumLength = MAX_PATH; // make a dangerous assumption
  3160.     dwStatus = BasepUnicodeStringTo8BitString(&AnsiString,
  3161.                                               &UnicodeName,
  3162.                                               FALSE);
  3163.     if (! NT_SUCCESS(dwStatus)) {
  3164.          return(FALSE);
  3165.     }
  3166.     // all trivial cases are tested, now we have to walk through the name
  3167.     ExtensionFound = FALSE;
  3168.     for (Index = 0; Index < AnsiString.Length; Index++)
  3169.     {
  3170.         Char = AnsiString.Buffer[Index];
  3171.         // Skip over and Dbcs characters
  3172.         if (IsDBCSLeadByte(Char)) {
  3173.             //
  3174.             //  1) if we're looking at base part ( !ExtensionPresent ) and the 8th byte
  3175.             //     is in the dbcs leading byte range, it's error ( Index == 7 ). If the
  3176.             //     length of base part is more than 8 ( Index > 7 ), it's definitely error.
  3177.             //
  3178.             //  2) if the last byte ( Index == DbcsName.Length - 1 ) is in the dbcs leading
  3179.             //     byte range, it's error
  3180.             //
  3181.             if ((!ExtensionFound && (Index >= 7)) ||
  3182.                 (Index == AnsiString.Length - 1)) {
  3183.                 return FALSE;
  3184.             }
  3185.             Index += 1;
  3186.             continue;
  3187.         }
  3188.         // make sure the char is legal
  3189.         if (Char > 0x7F || IllegalMask[Char / 32] & (1 << (Char % 32)))
  3190.             return FALSE;
  3191.         if ('.' == Char)
  3192.         {
  3193.             // (1) can have only one '.'
  3194.             // (2) can not have more than 3 chars following.
  3195.             if (ExtensionFound || Length - (Index + 1) > 3)
  3196.             {
  3197.                 return FALSE;
  3198.             }
  3199.             ExtensionFound = TRUE;
  3200.         }
  3201.         // base length > 8 chars
  3202.         if (Index >= 8 && !ExtensionFound)
  3203.             return FALSE;
  3204.     }
  3205.     return TRUE;
  3206. }
  3207. /**
  3208.     This function determines if the given name is a valid long name.
  3209.     This function only does "obvious" testing since there are not precise
  3210.     ways to cover all the file systems(each file system has its own
  3211.     file name domain(for example, FAT allows all extended chars and space char
  3212.     while NTFS **may** not)
  3213.     This function helps the caller to determine if a short to long name
  3214.     conversion is necessary. When in doubt, this function simply tells the
  3215.     caller that the given name is NOT a long name so that caller would
  3216.     do whatever it takes to convert the name.
  3217.     A name is a valid long name if one of the following conditions is met:
  3218.     (1). total length >= 13.
  3219.     (2). 0 == base name length ||  base name length > 8.
  3220.     (3). extention name length > 3.
  3221.     (4). '.' is the first char.
  3222.     (5). muitlple '.'
  3223.     null path, "." and ".." are treat as valid long name.
  3224.     Input: LPCWSTR Name -  points to the name to be checked. It does not
  3225.                            have to be NULL terminated.
  3226.            int Length - Length of the name, not including teminated NULL char.
  3227.     output: TRUE - if the given name is a long file name.
  3228.             FALSE - if the given name is not a long file name
  3229. **/
  3230. BOOL
  3231. IsLongName_U(
  3232.     LPCWSTR Name,
  3233.     int Length
  3234.     )
  3235. {
  3236.     int Index;
  3237.     BOOL ExtensionFound;
  3238.     // (1) NULL path
  3239.     // (2) total length > 12
  3240.     // (3) . is the first char (cover "." and "..")
  3241.     if (!Length || Length > 12 || L'.' == *Name)
  3242.         return TRUE;
  3243.     ExtensionFound = FALSE;
  3244.     for (Index = 0; Index < Length; Index++)
  3245.     {
  3246.         if (L'.' == Name[Index])
  3247.         {
  3248.             // multiple . or extension longer than 3
  3249.             if (ExtensionFound || Length - (Index + 1) > 3)
  3250.                 return TRUE;
  3251.             ExtensionFound = TRUE;
  3252.         }
  3253.         // base length longer than 8
  3254.         if (Index >= 8 && !ExtensionFound)
  3255.             return TRUE;
  3256.     }
  3257.     return FALSE;
  3258. }