[KERNEL32]
[reactos.git] / dll / win32 / kernel32 / client / vdm.c
index 2c122e0..e367948 100644 (file)
@@ -2,7 +2,7 @@
  * PROJECT:         ReactOS Win32 Base API
  * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            dll/win32/kernel32/client/vdm.c
- * PURPOSE:         Virtual Dos Machine (VDM) Support
+ * PURPOSE:         Virtual DOS Machines (VDM) Support
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  */
 
@@ -26,11 +26,11 @@ typedef struct _ENV_INFO
 
 ENV_INFO BasepEnvNameType[] =
 {
-    {3, sizeof(L"PATH"), L"PATH"},
-    {2, sizeof(L"WINDIR"), L"WINDIR"},
+    {3, sizeof(L"PATH")      , L"PATH"      },
+    {2, sizeof(L"WINDIR")    , L"WINDIR"    },
     {2, sizeof(L"SYSTEMROOT"), L"SYSTEMROOT"},
-    {3, sizeof(L"TEMP"), L"TEMP"},
-    {3, sizeof(L"TMP"), L"TMP"},
+    {3, sizeof(L"TEMP")      , L"TEMP"      },
+    {3, sizeof(L"TMP")       , L"TMP"       },
 };
 
 UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com");
@@ -49,35 +49,382 @@ BaseIsDosApplication(IN PUNICODE_STRING PathName,
     /* Is it a .com? */
     String.Length = BaseDotComSuffixName.Length;
     String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
-    if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return 2;
+    if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return BINARY_TYPE_COM;
 
     /* Is it a .pif? */
     String.Length = BaseDotPifSuffixName.Length;
     String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
-    if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return 3;
+    if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return BINARY_TYPE_PIF;
 
     /* Is it an exe? */
     String.Length = BaseDotExeSuffixName.Length;
     String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
-    if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return 1;
+    if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return BINARY_TYPE_EXE;
+
     return 0;
 }
 
-BOOL
+NTSTATUS
 WINAPI
 BaseCheckVDM(IN ULONG BinaryType,
              IN PCWCH ApplicationName,
              IN PCWCH CommandLine,
              IN PCWCH CurrentDirectory,
              IN PANSI_STRING AnsiEnvironment,
-             IN PCSR_API_MESSAGE Msg,
+             IN PBASE_API_MESSAGE ApiMessage,
              IN OUT PULONG iTask,
              IN DWORD CreationFlags,
-             IN LPSTARTUPINFOW StartupInfo)
+             IN LPSTARTUPINFOW StartupInfo,
+             IN HANDLE hUserToken OPTIONAL)
 {
-    /* This is not supported */
-    UNIMPLEMENTED;
-    return FALSE;
+    NTSTATUS Status;
+    PBASE_CHECK_VDM CheckVdm = &ApiMessage->Data.CheckVDMRequest;
+    PCSR_CAPTURE_BUFFER CaptureBuffer;
+    PWCHAR CurrentDir = NULL;
+    PWCHAR ShortAppName = NULL;
+    PWCHAR ShortCurrentDir = NULL;
+    ULONG Length;
+    PCHAR AnsiCmdLine = NULL;
+    PCHAR AnsiAppName = NULL;
+    PCHAR AnsiCurDirectory = NULL;
+    PCHAR AnsiDesktop = NULL;
+    PCHAR AnsiTitle = NULL;
+    PCHAR AnsiReserved = NULL;
+    STARTUPINFOA AnsiStartupInfo;
+    ULONG NumStrings = 5;
+
+    if (CurrentDirectory == NULL)
+    {
+        /* Allocate memory for the current directory path */
+        Length = GetCurrentDirectoryW(0, NULL);
+        CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                             HEAP_ZERO_MEMORY,
+                                             Length * sizeof(WCHAR));
+        if (CurrentDir == NULL)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Cleanup;
+        }
+
+        /* Get the current directory */
+        GetCurrentDirectoryW(Length, CurrentDir);
+        CurrentDirectory = CurrentDir;
+    }
+
+    /* Calculate the size of the short application name */
+    Length = GetShortPathNameW(ApplicationName, NULL, 0);
+
+    /* Allocate memory for the short application name */
+    ShortAppName = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                           HEAP_ZERO_MEMORY,
+                                           Length * sizeof(WCHAR));
+    if (!ShortAppName)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    /* Get the short application name */
+    if (!GetShortPathNameW(ApplicationName, ShortAppName, Length))
+    {
+        /* Try to determine which error occurred */
+        switch (GetLastError())
+        {
+            case ERROR_NOT_ENOUGH_MEMORY:
+            {
+                Status = STATUS_NO_MEMORY;
+                break;
+            }
+
+            case ERROR_INVALID_PARAMETER:
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            default:
+            {
+                Status = STATUS_OBJECT_PATH_INVALID;
+            }
+        }
+
+        goto Cleanup;
+    }
+
+    /* Calculate the size of the short current directory path */
+    Length = GetShortPathNameW(CurrentDirectory, NULL, 0);
+
+    /* Allocate memory for the short current directory path */
+    ShortCurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                              HEAP_ZERO_MEMORY,
+                                              Length * sizeof(WCHAR));
+    if (!ShortCurrentDir)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    /* Get the short current directory path */
+    if (!GetShortPathNameW(CurrentDirectory, ShortCurrentDir, Length))
+    {
+        /* Try to determine which error occurred */
+        switch (GetLastError())
+        {
+            case ERROR_NOT_ENOUGH_MEMORY:
+            {
+                Status = STATUS_NO_MEMORY;
+                break;
+            }
+
+            case ERROR_INVALID_PARAMETER:
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            default:
+            {
+                Status = STATUS_OBJECT_PATH_INVALID;
+            }
+        }
+        goto Cleanup;
+    }
+
+    /* Setup the input parameters */
+    CheckVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+    CheckVdm->BinaryType = BinaryType;
+    CheckVdm->CodePage = CP_ACP;
+    CheckVdm->dwCreationFlags = CreationFlags;
+    CheckVdm->CurDrive = CurrentDirectory[0] - L'A';
+    CheckVdm->CmdLen = wcslen(CommandLine) + 1;
+    CheckVdm->AppLen = wcslen(ShortAppName) + 1;
+    CheckVdm->PifLen = 0; // TODO: PIF file support!
+    CheckVdm->CurDirectoryLen = wcslen(ShortCurrentDir) + 1;
+    CheckVdm->EnvLen = AnsiEnvironment->Length;
+    CheckVdm->DesktopLen = (StartupInfo->lpDesktop != NULL) ? (wcslen(StartupInfo->lpDesktop) + 1) : 0;
+    CheckVdm->TitleLen = (StartupInfo->lpTitle != NULL) ? (wcslen(StartupInfo->lpTitle) + 1) : 0;
+    CheckVdm->ReservedLen = (StartupInfo->lpReserved != NULL) ? (wcslen(StartupInfo->lpReserved) + 1) : 0;
+
+    if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
+    {
+        /* Set the standard handles */
+        CheckVdm->StdIn = StartupInfo->hStdInput;
+        CheckVdm->StdOut = StartupInfo->hStdOutput;
+        CheckVdm->StdErr = StartupInfo->hStdError;
+    }
+
+    /* Allocate memory for the ANSI strings */
+    AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen);
+    AnsiAppName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->AppLen);
+    AnsiCurDirectory = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CurDirectoryLen);
+    if (StartupInfo->lpDesktop) AnsiDesktop = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                                                     HEAP_ZERO_MEMORY,
+                                                                     CheckVdm->DesktopLen);
+    if (StartupInfo->lpTitle) AnsiTitle = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                                                 HEAP_ZERO_MEMORY,
+                                                                 CheckVdm->TitleLen);
+    if (StartupInfo->lpReserved) AnsiReserved = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
+                                                                       HEAP_ZERO_MEMORY,
+                                                                       CheckVdm->ReservedLen);
+
+    if (!AnsiCmdLine
+        || !AnsiAppName
+        || !AnsiCurDirectory
+        || (StartupInfo->lpDesktop && !AnsiDesktop)
+        || (StartupInfo->lpTitle && !AnsiTitle)
+        || (StartupInfo->lpReserved && !AnsiReserved))
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    /* Convert the command line into an ANSI string */
+    WideCharToMultiByte(CP_ACP,
+                        0,
+                        CommandLine,
+                        CheckVdm->CmdLen,
+                        AnsiCmdLine,
+                        CheckVdm->CmdLen,
+                        NULL,
+                        NULL);
+
+    /* Convert the short application name into an ANSI string */
+    WideCharToMultiByte(CP_ACP,
+                        0,
+                        ShortAppName,
+                        CheckVdm->AppLen,
+                        AnsiAppName,
+                        CheckVdm->AppLen,
+                        NULL,
+                        NULL);
+
+    /* Convert the short current directory path into an ANSI string */
+    WideCharToMultiByte(CP_ACP,
+                        0,
+                        ShortCurrentDir,
+                        CheckVdm->CurDirectoryLen,
+                        AnsiCurDirectory,
+                        CheckVdm->CurDirectoryLen,
+                        NULL,
+                        NULL);
+
+    if (StartupInfo->lpDesktop)
+    {
+        /* Convert the desktop name into an ANSI string */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            StartupInfo->lpDesktop,
+                            CheckVdm->DesktopLen,
+                            AnsiDesktop,
+                            CheckVdm->DesktopLen,
+                            NULL,
+                            NULL);
+        NumStrings++;
+    }
+
+    if (StartupInfo->lpTitle)
+    {
+        /* Convert the title into an ANSI string */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            StartupInfo->lpTitle,
+                            CheckVdm->TitleLen,
+                            AnsiTitle,
+                            CheckVdm->TitleLen,
+                            NULL,
+                            NULL);
+        NumStrings++;
+    }
+
+    if (StartupInfo->lpReserved)
+    {
+        /* Convert the reserved value into an ANSI string */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            StartupInfo->lpReserved,
+                            CheckVdm->ReservedLen,
+                            AnsiReserved,
+                            CheckVdm->ReservedLen,
+                            NULL,
+                            NULL);
+        NumStrings++;
+    }
+
+    /* Fill the ANSI startup info structure */
+    RtlCopyMemory(&AnsiStartupInfo, StartupInfo, sizeof(STARTUPINFO));
+    AnsiStartupInfo.lpReserved = AnsiReserved;
+    AnsiStartupInfo.lpDesktop = AnsiDesktop;
+    AnsiStartupInfo.lpTitle = AnsiTitle;
+
+    /* Allocate the capture buffer */
+    CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings,
+                                             CheckVdm->CmdLen
+                                             + CheckVdm->AppLen
+                                             + CheckVdm->PifLen
+                                             + CheckVdm->CurDirectoryLen
+                                             + CheckVdm->DesktopLen
+                                             + CheckVdm->TitleLen
+                                             + CheckVdm->ReservedLen
+                                             + CheckVdm->EnvLen
+                                             + sizeof(STARTUPINFOA));
+    if (CaptureBuffer == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Cleanup;
+    }
+
+    /* Capture the command line */
+    CsrCaptureMessageBuffer(CaptureBuffer,
+                            AnsiCmdLine,
+                            CheckVdm->CmdLen,
+                            (PVOID*)&CheckVdm->CmdLine);
+
+    /* Capture the application name */
+    CsrCaptureMessageBuffer(CaptureBuffer,
+                            AnsiAppName,
+                            CheckVdm->AppLen,
+                            (PVOID*)&CheckVdm->AppName);
+
+    CheckVdm->PifFile = NULL; // TODO: PIF file support!
+
+    /* Capture the current directory */
+    CsrCaptureMessageBuffer(CaptureBuffer,
+                            AnsiCurDirectory,
+                            CheckVdm->CurDirectoryLen,
+                            (PVOID*)&CheckVdm->CurDirectory);
+
+    /* Capture the environment */
+    CsrCaptureMessageBuffer(CaptureBuffer,
+                            AnsiEnvironment->Buffer,
+                            CheckVdm->EnvLen,
+                            (PVOID*)&CheckVdm->Env);
+
+    /* Capture the startup info structure */
+    CsrCaptureMessageBuffer(CaptureBuffer,
+                            &AnsiStartupInfo,
+                            sizeof(STARTUPINFOA),
+                            (PVOID*)&CheckVdm->StartupInfo);
+
+    if (StartupInfo->lpDesktop)
+    {
+        /* Capture the desktop name */
+        CsrCaptureMessageBuffer(CaptureBuffer,
+                                AnsiDesktop,
+                                CheckVdm->DesktopLen,
+                                (PVOID*)&CheckVdm->Desktop);
+    }
+    else CheckVdm->Desktop = NULL;
+
+    if (StartupInfo->lpTitle)
+    {
+        /* Capture the title */
+        CsrCaptureMessageBuffer(CaptureBuffer,
+                                AnsiTitle,
+                                CheckVdm->TitleLen,
+                                (PVOID*)&CheckVdm->Title);
+    }
+    else CheckVdm->Title = NULL;
+
+    if (StartupInfo->lpReserved)
+    {
+        /* Capture the reserved parameter */
+        CsrCaptureMessageBuffer(CaptureBuffer,
+                                AnsiReserved,
+                                CheckVdm->ReservedLen,
+                                (PVOID*)&CheckVdm->Reserved);
+    }
+    else CheckVdm->Reserved = NULL;
+
+    /* Send the message to CSRSS */
+    Status = CsrClientCallServer((PCSR_API_MESSAGE)ApiMessage,
+                                 CaptureBuffer,
+                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCheckVDM),
+                                 sizeof(BASE_CHECK_VDM));
+
+    /* Write back the task ID */
+    *iTask = CheckVdm->iTask;
+
+Cleanup:
+
+    /* Free the ANSI strings */
+    if (AnsiCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine);
+    if (AnsiAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName);
+    if (AnsiCurDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory);
+    if (AnsiDesktop) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop);
+    if (AnsiTitle) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle);
+    if (AnsiReserved) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved);
+
+    /* Free the capture buffer */
+    CsrFreeCaptureBuffer(CaptureBuffer);
+
+    /* Free the short paths */
+    if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName);
+    if (ShortCurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir);
+
+    /* Free the current directory, if it was allocated here */
+    if (CurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir);
+
+    return Status;
 }
 
 BOOL
@@ -88,56 +435,61 @@ BaseUpdateVDMEntry(IN ULONG UpdateIndex,
                    IN ULONG BinaryType)
 {
     NTSTATUS Status;
-    CSR_API_MESSAGE Msg;
-    ULONG CsrRequest = MAKE_CSR_API(UPDATE_VDM_ENTRY, CSR_CONSOLE);
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest;
 
     /* Check what update is being sent */
     switch (UpdateIndex)
     {
         /* VDM is being undone */
         case VdmEntryUndo:
-
+        {
             /* Tell the server how far we had gotten along */
-            Msg.Data.UpdateVdmEntry.iTask = (ULONG)*WaitHandle;
-            Msg.Data.UpdateVdmEntry.VDMCreationState = IndexInfo;
+            UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle);
+            UpdateVdmEntry->VDMCreationState = IndexInfo;
             break;
+        }
 
         /* VDM is ready with a new process handle */
         case VdmEntryUpdateProcess:
-
+        {
             /* Send it the process handle */
-            Msg.Data.UpdateVdmEntry.VDMProcessHandle = *WaitHandle;
-            Msg.Data.UpdateVdmEntry.iTask = IndexInfo;
+            UpdateVdmEntry->VDMProcessHandle = *WaitHandle;
+            UpdateVdmEntry->iTask = IndexInfo;
             break;
+        }
     }
 
     /* Also check what kind of binary this is for the console handle */
     if (BinaryType == BINARY_TYPE_WOW)
     {
         /* Magic value for 16-bit apps */
-        Msg.Data.UpdateVdmEntry.ConsoleHandle = (HANDLE)-1;
+        UpdateVdmEntry->ConsoleHandle = (HANDLE)-1;
     }
-    else if (Msg.Data.UpdateVdmEntry.iTask)
+    else if (UpdateVdmEntry->iTask)
     {
         /* No handle for true VDM */
-        Msg.Data.UpdateVdmEntry.ConsoleHandle = 0;
+        UpdateVdmEntry->ConsoleHandle = NULL;
     }
     else
     {
-        /* Otherwise, send the regular consoel handle */
-        Msg.Data.UpdateVdmEntry.ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+        /* Otherwise, use the regular console handle */
+        UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
     }
 
     /* Finally write the index and binary type */
-    Msg.Data.UpdateVdmEntry.EntryIndex = UpdateIndex;
-    Msg.Data.UpdateVdmEntry.BinaryType = BinaryType;
+    UpdateVdmEntry->EntryIndex = UpdateIndex;
+    UpdateVdmEntry->BinaryType = BinaryType;
 
     /* Send the message to CSRSS */
-    Status = CsrClientCallServer(&Msg, NULL, CsrRequest, sizeof(Msg));
-    if (!(NT_SUCCESS(Status)) || !(NT_SUCCESS(Msg.Status)))
+    Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                                 NULL,
+                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepUpdateVDMEntry),
+                                 sizeof(BASE_UPDATE_VDM_ENTRY));
+    if (!NT_SUCCESS(Status))
     {
         /* Handle failure */
-        BaseSetLastNTError(Msg.Status);
+        BaseSetLastNTError(Status);
         return FALSE;
     }
 
@@ -145,7 +497,7 @@ BaseUpdateVDMEntry(IN ULONG UpdateIndex,
     if (UpdateIndex == VdmEntryUpdateProcess)
     {
         /* Return it to the caller */
-        *WaitHandle = Msg.Data.UpdateVdmEntry.WaitObjectForParent;
+        *WaitHandle = UpdateVdmEntry->WaitObjectForParent;
     }
 
     /* We made it */
@@ -159,8 +511,8 @@ BaseCheckForVDM(IN HANDLE ProcessHandle,
 {
     NTSTATUS Status;
     EVENT_BASIC_INFORMATION EventBasicInfo;
-    CSR_API_MESSAGE Msg;
-    ULONG CsrRequest = MAKE_CSR_API(GET_VDM_EXIT_CODE, CSR_CONSOLE);
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest;
 
     /* It's VDM if the process is actually a wait handle (an event) */
     Status = NtQueryEvent(ProcessHandle,
@@ -171,21 +523,24 @@ BaseCheckForVDM(IN HANDLE ProcessHandle,
     if (!NT_SUCCESS(Status)) return FALSE;
 
     /* Setup the input parameters */
-    Msg.Data.GetVdmExitCode.ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
-    Msg.Data.GetVdmExitCode.hParent = ProcessHandle;
+    GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+    GetVdmExitCode->hParent = ProcessHandle;
 
     /* Call CSRSS */
-    Status = CsrClientCallServer(&Msg, NULL, CsrRequest, sizeof(Msg));
+    Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                                 NULL,
+                                 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMExitCode),
+                                 sizeof(BASE_GET_VDM_EXIT_CODE));
     if (!NT_SUCCESS(Status)) return FALSE;
 
     /* Get the exit code from the reply */
-    *ExitCode = Msg.Data.GetVdmExitCode.ExitCode;
+    *ExitCode = GetVdmExitCode->ExitCode;
     return TRUE;
 }
 
 BOOL
 WINAPI
-BaseGetVdmConfigInfo(IN LPCWSTR Reserved,
+BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
                      IN ULONG DosSeqId,
                      IN ULONG BinaryType,
                      IN PUNICODE_STRING CmdLineString,
@@ -198,7 +553,7 @@ BaseGetVdmConfigInfo(IN LPCWSTR Reserved,
     /* Clear the buffer in case we fail */
     CmdLineString->Buffer = 0;
 
-    /* Always return the same size */
+    /* Always return the same size: 16 Mb */
     *VdmSize = 0x1000000;
 
     /* Get the system directory */
@@ -213,24 +568,31 @@ BaseGetVdmConfigInfo(IN LPCWSTR Reserved,
     /* Check if this is VDM with a DOS Sequence ID */
     if (DosSeqId)
     {
-        /* Build the VDM string for it */
+        /*
+         * Build the VDM string for it:
+         * -i%lx : Gives the DOS Sequence ID;
+         * %s%c  : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
+         */
         _snwprintf(CommandLine,
                    sizeof(CommandLine),
                    L"\"%s\\ntvdm.exe\" -i%lx %s%c",
                    Buffer,
                    DosSeqId,
-                   (BinaryType == 0x10) ? L" " : L"-w",
-                   (BinaryType == 0x40) ? 's' : ' ');
+                   (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
+                   (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
     }
     else
     {
-        /* Non-DOS, build the stirng for it without the task ID */
+        /*
+         * Build the string for it without the DOS Sequence ID:
+         * %s%c  : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
+         */
         _snwprintf(CommandLine,
                    sizeof(CommandLine),
-                   L"\"%s\\ntvdm.exe\"  %s%c",
+                   L"\"%s\\ntvdm.exe\" %s%c",
                    Buffer,
-                   (BinaryType == 0x10) ? L" " : L"-w",
-                   (BinaryType == 0x40) ? 's' : ' ');
+                   (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
+                   (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
     }
 
     /* Create the actual string */
@@ -300,7 +662,7 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
 {
     BOOL Result;
     ULONG RegionSize, EnvironmentSize = 0;
-    PWCHAR p, Environment, NewEnvironment;
+    PWCHAR p, Environment, NewEnvironment = NULL;
     NTSTATUS Status;
 
     /* Make sure we have both strings */
@@ -362,8 +724,8 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
 
     /* Initialize the unicode string to hold it */
     EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
-    RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, EnvironmentSize);
-    UnicodeEnv->Length = EnvironmentSize;
+    RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
+    UnicodeEnv->Length = (USHORT)EnvironmentSize;
 
     /* Create the ASCII version of it */
     Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
@@ -673,7 +1035,7 @@ GetBinaryTypeW (
     }
   }
 
-  DPRINT1("Invalid binary type returned!\n", BinType);
+  DPRINT1("Invalid binary type %lu returned!\n", BinType);
   return FALSE;
 }
 
@@ -735,17 +1097,31 @@ CmdBatNotification (
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
-DWORD
+VOID
 WINAPI
-ExitVDM (
-    DWORD   Unknown0,
-    DWORD   Unknown1
-    )
+ExitVDM(BOOL IsWow, ULONG iWowTask)
 {
-    STUB;
-    return 0;
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
+
+    /* Setup the input parameters */
+    ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+    ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
+    ExitVdm->WaitObjectForVDM = NULL;
+
+    /* Call CSRSS */
+    CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                        NULL,
+                        CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
+                        sizeof(BASE_EXIT_VDM));
+
+    /* Close the returned wait object handle, if any */
+    if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
+    {
+        CloseHandle(ExitVdm->WaitObjectForVDM);
+    }
 }
 
 
@@ -754,9 +1130,7 @@ ExitVDM (
  */
 DWORD
 WINAPI
-GetNextVDMCommand (
-    DWORD   Unknown0
-    )
+GetNextVDMCommand(PGET_NEXT_VDM_COMMAND_DATA CommandData)
 {
     STUB;
     return 0;
@@ -764,17 +1138,51 @@ GetNextVDMCommand (
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 DWORD
 WINAPI
-GetVDMCurrentDirectories (
-    DWORD   Unknown0,
-    DWORD   Unknown1
-    )
+GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
 {
-    STUB;
-    return 0;
+    BASE_API_MESSAGE ApiMessage;
+    PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
+    PCSR_CAPTURE_BUFFER CaptureBuffer;
+
+    /* Allocate the capture buffer */
+    CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
+    if (CaptureBuffer == NULL)
+    {
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        return 0;
+    }
+
+    /* Setup the input parameters */
+    VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
+    CsrAllocateMessagePointer(CaptureBuffer,
+                              cchCurDirs,
+                              (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
+
+    /* Call CSRSS */
+    CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                        CaptureBuffer,
+                        CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
+                        sizeof(BASE_GETSET_VDM_CURDIRS));
+
+    /* Set the last error */
+    BaseSetLastNTError(ApiMessage.Status);
+
+    if (NT_SUCCESS(ApiMessage.Status))
+    {
+        /* Copy the result */
+        RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
+    }
+
+    /* Free the capture buffer */
+    CsrFreeCaptureBuffer(CaptureBuffer);
+
+    /* Return the size if it was successful, or if the buffer was too small */
+    return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
+           ? VDMCurrentDirsRequest->cchCurDirs : 0;
 }