[KERNEL32]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 12 Sep 2015 16:23:32 +0000 (16:23 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 12 Sep 2015 16:23:32 +0000 (16:23 +0000)
GetNextVDMCommand function:
- Avoid using deep nested levels of indentation.
- Fix the error check conditions (+ status value) for the CsrClientCallServer call to make it compatible with what windows' basesrv can return to us.

[BASESRV]
- Remove some useless "NTAPI" from functions.
- Factor out some code used for creating and destroying console records, and for the destruction of the pair of event handles.
- Use "IsListEmpty" when needed.
- Fix BaseSrvFillCommandInfo so that it returns the needed lengths (even if the user-given lengths are zero) and set the expected status error in case the buffer lenghts are too small (not STATUS_BUFFER_TOO_SMALL but STATUS_INVALID_PARAMETER because it's what kernel32 error check expects, for windows compat; see above).
- Fix initialization of new DOS records: no need to create a new one if there is one already free (status VDM_READY).
- Fix the loop that searches for a valid DOS record containing command information available as well as the conditions in which case our caller needs to wait in GetNextVDMCommand call.

NOTE: The internal state flags of the DOS records have normally nothing to do with the VDM state flags we report back to the user.

CORE-8247 CORE-9711 CORE-9773

svn path=/trunk/; revision=69201

reactos/dll/win32/kernel32/client/vdm.c
reactos/subsystems/win/basesrv/vdm.c
reactos/subsystems/win/basesrv/vdm.h

index 5f37d7a..0164cb4 100644 (file)
@@ -1411,8 +1411,8 @@ BOOL
 WINAPI
 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
 {
+    BOOL Success = FALSE;
     NTSTATUS Status;
-    BOOL Result = FALSE;
     BASE_API_MESSAGE ApiMessage;
     PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest;
     PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest;
@@ -1420,311 +1420,343 @@ GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
     PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
     ULONG NumStrings = 0;
 
-    if (CommandData != NULL)
+    /*
+     * Special case to test whether the VDM is the first one.
+     */
+    if (CommandData == NULL)
     {
-        if ((CommandData->VDMState == VDM_INC_REENTER_COUNT)
-            || (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
+        /* Call CSRSS */
+        CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                            NULL,
+                            CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
+                            sizeof(*IsFirstVdm));
+        if (!NT_SUCCESS(ApiMessage.Status))
         {
-            /* Setup the input parameters */
-            SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
-            SetReenterCount->fIncDec = CommandData->VDMState;
-
-            /* Call CSRSS */
-            Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
-                                         NULL,
-                                         CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
-                                         sizeof(*SetReenterCount));
-            BaseSetLastNTError(Status);
-            Result = NT_SUCCESS(Status);
+            BaseSetLastNTError(ApiMessage.Status);
+            return FALSE;
         }
-        else
+
+        /* Return TRUE if this is the first VDM */
+        return IsFirstVdm->FirstVDM;
+    }
+
+    /* CommandData != NULL */
+
+    /*
+     * Special case to increment or decrement the reentrancy count.
+     */
+    if ((CommandData->VDMState == VDM_INC_REENTER_COUNT) ||
+        (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
+    {
+        /* Setup the input parameters */
+        SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+        SetReenterCount->fIncDec = CommandData->VDMState;
+
+        /* Call CSRSS */
+        CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                            NULL,
+                            CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
+                            sizeof(*SetReenterCount));
+        if (!NT_SUCCESS(ApiMessage.Status))
         {
-            /* Clear the structure */
-            ZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
-
-            /* Setup the input parameters */
-            GetNextVdmCommand->iTask = CommandData->TaskId;
-            GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
-            GetNextVdmCommand->CmdLen = CommandData->CmdLen;
-            GetNextVdmCommand->AppLen = CommandData->AppLen;
-            GetNextVdmCommand->PifLen = CommandData->PifLen;
-            GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
-            GetNextVdmCommand->EnvLen = CommandData->EnvLen;
-            GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
-            GetNextVdmCommand->TitleLen = CommandData->TitleLen;
-            GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
-            GetNextVdmCommand->VDMState = CommandData->VDMState;
-
-            /* Count the number of strings */
-            if (CommandData->CmdLen) NumStrings++;
-            if (CommandData->AppLen) NumStrings++;
-            if (CommandData->PifLen) NumStrings++;
-            if (CommandData->CurDirectoryLen) NumStrings++;
-            if (CommandData->EnvLen) NumStrings++;
-            if (CommandData->DesktopLen) NumStrings++;
-            if (CommandData->TitleLen) NumStrings++;
-            if (CommandData->ReservedLen) NumStrings++;
-
-            /* Allocate the capture buffer */
-            CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
-                                                     GetNextVdmCommand->CmdLen
-                                                     + GetNextVdmCommand->AppLen
-                                                     + GetNextVdmCommand->PifLen
-                                                     + GetNextVdmCommand->CurDirectoryLen
-                                                     + GetNextVdmCommand->EnvLen
-                                                     + GetNextVdmCommand->DesktopLen
-                                                     + GetNextVdmCommand->TitleLen
-                                                     + GetNextVdmCommand->ReservedLen
-                                                     + sizeof(STARTUPINFOA));
-            if (CaptureBuffer == NULL)
-            {
-                BaseSetLastNTError(STATUS_NO_MEMORY);
-                goto Cleanup;
-            }
+            BaseSetLastNTError(ApiMessage.Status);
+            return FALSE;
+        }
 
-            /* Allocate memory for the startup info */
-            CsrAllocateMessagePointer(CaptureBuffer,
-                                      sizeof(STARTUPINFOA),
-                                      (PVOID*)&GetNextVdmCommand->StartupInfo);
+        return TRUE;
+    }
 
-            if (CommandData->CmdLen)
-            {
-                /* Allocate memory for the command line */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->CmdLen,
-                                          (PVOID*)&GetNextVdmCommand->CmdLine);
-            }
+    /*
+     * TODO!
+     * Special case to retrieve or set WOW information.
+     */
+    // TODO: if CommandData->VDMState & (VDM_LIST_WOW_PROCESSES | VDM_LIST_WOW_TASKS | VDM_ADD_WOW_TASK)
+    // then call BasepGetNextVDMCommand in a simpler way!
 
-            if (CommandData->AppLen)
-            {
-                /* Allocate memory for the application name */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->AppLen,
-                                          (PVOID*)&GetNextVdmCommand->AppName);
-            }
+    /*
+     * Regular case.
+     */
 
-            if (CommandData->PifLen)
-            {
-                /* Allocate memory for the PIF file name */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->PifLen,
-                                          (PVOID*)&GetNextVdmCommand->PifFile);
-            }
+    /* Clear the structure */
+    RtlZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
 
-            if (CommandData->CurDirectoryLen)
-            {
-                /* Allocate memory for the current directory */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->CurDirectoryLen,
-                                          (PVOID*)&GetNextVdmCommand->CurDirectory);
-            }
+    /* Setup the input parameters */
+    GetNextVdmCommand->iTask = CommandData->TaskId;
+    GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+    GetNextVdmCommand->CmdLen = CommandData->CmdLen;
+    GetNextVdmCommand->AppLen = CommandData->AppLen;
+    GetNextVdmCommand->PifLen = CommandData->PifLen;
+    GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
+    GetNextVdmCommand->EnvLen = CommandData->EnvLen;
+    GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
+    GetNextVdmCommand->TitleLen = CommandData->TitleLen;
+    GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
+    GetNextVdmCommand->VDMState = CommandData->VDMState;
+
+    /* Count the number of strings */
+    if (CommandData->CmdLen) NumStrings++;
+    if (CommandData->AppLen) NumStrings++;
+    if (CommandData->PifLen) NumStrings++;
+    if (CommandData->CurDirectoryLen) NumStrings++;
+    if (CommandData->EnvLen) NumStrings++;
+    if (CommandData->DesktopLen) NumStrings++;
+    if (CommandData->TitleLen) NumStrings++;
+    if (CommandData->ReservedLen) NumStrings++;
 
-            if (CommandData->EnvLen)
-            {
-                /* Allocate memory for the environment */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->EnvLen,
-                                          (PVOID*)&GetNextVdmCommand->Env);
-            }
+    /* Allocate the capture buffer */
+    CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
+                                             GetNextVdmCommand->CmdLen
+                                             + GetNextVdmCommand->AppLen
+                                             + GetNextVdmCommand->PifLen
+                                             + GetNextVdmCommand->CurDirectoryLen
+                                             + GetNextVdmCommand->EnvLen
+                                             + GetNextVdmCommand->DesktopLen
+                                             + GetNextVdmCommand->TitleLen
+                                             + GetNextVdmCommand->ReservedLen
+                                             + sizeof(*GetNextVdmCommand->StartupInfo));
+    if (CaptureBuffer == NULL)
+    {
+        BaseSetLastNTError(STATUS_NO_MEMORY);
+        goto Cleanup;
+    }
 
-            if (CommandData->DesktopLen)
-            {
-                /* Allocate memory for the desktop name */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->DesktopLen,
-                                          (PVOID*)&GetNextVdmCommand->Desktop);
-            }
+    /* Capture the data */
 
-            if (CommandData->TitleLen)
-            {
-                /* Allocate memory for the title */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->TitleLen,
-                                          (PVOID*)&GetNextVdmCommand->Title);
-            }
+    CsrAllocateMessagePointer(CaptureBuffer,
+                              sizeof(*GetNextVdmCommand->StartupInfo),
+                              (PVOID*)&GetNextVdmCommand->StartupInfo);
 
-            if (CommandData->ReservedLen)
-            {
-                /* Allocate memory for the reserved parameter */
-                CsrAllocateMessagePointer(CaptureBuffer,
-                                          CommandData->ReservedLen,
-                                          (PVOID*)&GetNextVdmCommand->Reserved);
-            }
+    if (CommandData->CmdLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->CmdLen,
+                                  (PVOID*)&GetNextVdmCommand->CmdLine);
+    }
 
-            do
-            {
-                /* Call CSRSS */
-                Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
-                                             CaptureBuffer,
-                                             CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
-                                             sizeof(*GetNextVdmCommand));
-                if (!NT_SUCCESS(Status))
-                {
-                    /* Store the correct lengths */
-                    CommandData->CmdLen = GetNextVdmCommand->CmdLen;
-                    CommandData->AppLen = GetNextVdmCommand->AppLen;
-                    CommandData->PifLen = GetNextVdmCommand->PifLen;
-                    CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
-                    CommandData->EnvLen = GetNextVdmCommand->EnvLen;
-                    CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
-                    CommandData->TitleLen = GetNextVdmCommand->TitleLen;
-                    CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
-
-                    BaseSetLastNTError(Status);
-                    goto Cleanup;
-                }
+    if (CommandData->AppLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->AppLen,
+                                  (PVOID*)&GetNextVdmCommand->AppName);
+    }
 
-                /* Did we receive an event handle? */
-                if (GetNextVdmCommand->WaitObjectForVDM != NULL)
-                {
-                    /* Wait for the event to become signaled and try again */
-                    Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
-                                                   FALSE,
-                                                   NULL);
-                    if (!NT_SUCCESS(Status))
-                    {
-                        BaseSetLastNTError(Status);
-                        goto Cleanup;
-                    }
+    if (CommandData->PifLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->PifLen,
+                                  (PVOID*)&GetNextVdmCommand->PifFile);
+    }
 
-                    /* Set the retry flag and clear the exit code */
-                    GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
-                    GetNextVdmCommand->ExitCode = 0;
-                }
-            }
-            while (GetNextVdmCommand->WaitObjectForVDM != NULL);
+    if (CommandData->CurDirectoryLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->CurDirectoryLen,
+                                  (PVOID*)&GetNextVdmCommand->CurDirectory);
+    }
 
-            /* Write back the standard handles */
-            CommandData->StdIn = GetNextVdmCommand->StdIn;
-            CommandData->StdOut = GetNextVdmCommand->StdOut;
-            CommandData->StdErr = GetNextVdmCommand->StdErr;
+    if (CommandData->EnvLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->EnvLen,
+                                  (PVOID*)&GetNextVdmCommand->Env);
+    }
 
-            /* Write back the startup info */
-            RtlMoveMemory(&CommandData->StartupInfo,
-                          GetNextVdmCommand->StartupInfo,
-                          sizeof(STARTUPINFOA));
+    if (CommandData->DesktopLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->DesktopLen,
+                                  (PVOID*)&GetNextVdmCommand->Desktop);
+    }
 
-            if (CommandData->CmdLen)
-            {
-                /* Write back the command line */
-                RtlMoveMemory(CommandData->CmdLine,
-                              GetNextVdmCommand->CmdLine,
-                              GetNextVdmCommand->CmdLen);
+    if (CommandData->TitleLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->TitleLen,
+                                  (PVOID*)&GetNextVdmCommand->Title);
+    }
 
-                /* Set the actual length */
-                CommandData->CmdLen = GetNextVdmCommand->CmdLen;
-            }
+    if (CommandData->ReservedLen)
+    {
+        CsrAllocateMessagePointer(CaptureBuffer,
+                                  CommandData->ReservedLen,
+                                  (PVOID*)&GetNextVdmCommand->Reserved);
+    }
 
-            if (CommandData->AppLen)
-            {
-                /* Write back the application name */
-                RtlMoveMemory(CommandData->AppName,
-                              GetNextVdmCommand->AppName,
-                              GetNextVdmCommand->AppLen);
+    while (TRUE)
+    {
+        /* Call CSRSS */
+        Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+                                     CaptureBuffer,
+                                     CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
+                                     sizeof(*GetNextVdmCommand));
 
-                /* Set the actual length */
-                CommandData->AppLen = GetNextVdmCommand->AppLen;
-            }
+        /* Exit the waiting loop if we did not receive any event handle */
+        if (GetNextVdmCommand->WaitObjectForVDM == NULL)
+            break;
 
-            if (CommandData->PifLen)
-            {
-                /* Write back the PIF file name */
-                RtlMoveMemory(CommandData->PifFile,
-                              GetNextVdmCommand->PifFile,
-                              GetNextVdmCommand->PifLen);
+        /* Wait for the event to become signaled and try again */
+        Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
+                                       FALSE, NULL);
+        if (Status != STATUS_SUCCESS)
+        {
+            /* Fail if we timed out, or if some other error happened */
+            BaseSetLastNTError(Status);
+            goto Cleanup;
+        }
 
-                /* Set the actual length */
-                CommandData->PifLen = GetNextVdmCommand->PifLen;
-            }
+        /* Set the retry flag, clear the exit code, and retry a query */
+        GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
+        GetNextVdmCommand->ExitCode = 0;
+    }
 
-            if (CommandData->CurDirectoryLen)
-            {
-                /* Write back the current directory */
-                RtlMoveMemory(CommandData->CurDirectory,
-                              GetNextVdmCommand->CurDirectory,
-                              GetNextVdmCommand->CurDirectoryLen);
+    if (!NT_SUCCESS(Status))
+    {
+        if (Status == STATUS_INVALID_PARAMETER)
+        {
+            /*
+             * One of the buffer lengths was less than required. Store the correct ones.
+             * Note that the status code is not STATUS_BUFFER_TOO_SMALL as one would expect,
+             * in order to keep compatibility with Windows 2003 BASESRV.DLL.
+             */
+            CommandData->CmdLen = GetNextVdmCommand->CmdLen;
+            CommandData->AppLen = GetNextVdmCommand->AppLen;
+            CommandData->PifLen = GetNextVdmCommand->PifLen;
+            CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
+            CommandData->EnvLen      = GetNextVdmCommand->EnvLen;
+            CommandData->DesktopLen  = GetNextVdmCommand->DesktopLen;
+            CommandData->TitleLen    = GetNextVdmCommand->TitleLen;
+            CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
+        }
+        else
+        {
+            /* Any other failure */
+            CommandData->CmdLen = 0;
+            CommandData->AppLen = 0;
+            CommandData->PifLen = 0;
+            CommandData->CurDirectoryLen = 0;
+            CommandData->EnvLen      = 0;
+            CommandData->DesktopLen  = 0;
+            CommandData->TitleLen    = 0;
+            CommandData->ReservedLen = 0;
+        }
 
-                /* Set the actual length */
-                CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
-            }
+        BaseSetLastNTError(Status);
+        goto Cleanup;
+    }
 
-            if (CommandData->EnvLen)
-            {
-                /* Write back the environment */
-                RtlMoveMemory(CommandData->Env,
-                              GetNextVdmCommand->Env,
-                              GetNextVdmCommand->EnvLen);
+    /* Write back the standard handles */
+    CommandData->StdIn  = GetNextVdmCommand->StdIn;
+    CommandData->StdOut = GetNextVdmCommand->StdOut;
+    CommandData->StdErr = GetNextVdmCommand->StdErr;
 
-                /* Set the actual length */
-                CommandData->EnvLen = GetNextVdmCommand->EnvLen;
-            }
+    /* Write back the startup info */
+    RtlMoveMemory(&CommandData->StartupInfo,
+                  GetNextVdmCommand->StartupInfo,
+                  sizeof(*GetNextVdmCommand->StartupInfo));
 
-            if (CommandData->DesktopLen)
-            {
-                /* Write back the desktop name */
-                RtlMoveMemory(CommandData->Desktop,
-                              GetNextVdmCommand->Desktop,
-                              GetNextVdmCommand->DesktopLen);
+    if (CommandData->CmdLen)
+    {
+        /* Write back the command line */
+        RtlMoveMemory(CommandData->CmdLine,
+                      GetNextVdmCommand->CmdLine,
+                      GetNextVdmCommand->CmdLen);
 
-                /* Set the actual length */
-                CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
-            }
+        /* Set the actual length */
+        CommandData->CmdLen = GetNextVdmCommand->CmdLen;
+    }
 
-            if (CommandData->TitleLen)
-            {
-                /* Write back the title */
-                RtlMoveMemory(CommandData->Title,
-                              GetNextVdmCommand->Title,
-                              GetNextVdmCommand->TitleLen);
+    if (CommandData->AppLen)
+    {
+        /* Write back the application name */
+        RtlMoveMemory(CommandData->AppName,
+                      GetNextVdmCommand->AppName,
+                      GetNextVdmCommand->AppLen);
 
-                /* Set the actual length */
-                CommandData->TitleLen = GetNextVdmCommand->TitleLen;
-            }
+        /* Set the actual length */
+        CommandData->AppLen = GetNextVdmCommand->AppLen;
+    }
 
-            if (CommandData->ReservedLen)
-            {
-                /* Write back the reserved parameter */
-                RtlMoveMemory(CommandData->Reserved,
-                              GetNextVdmCommand->Reserved,
-                              GetNextVdmCommand->ReservedLen);
+    if (CommandData->PifLen)
+    {
+        /* Write back the PIF file name */
+        RtlMoveMemory(CommandData->PifFile,
+                      GetNextVdmCommand->PifFile,
+                      GetNextVdmCommand->PifLen);
 
-                /* Set the actual length */
-                CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
-            }
+        /* Set the actual length */
+        CommandData->PifLen = GetNextVdmCommand->PifLen;
+    }
 
-            /* Write the remaining output parameters */
-            CommandData->TaskId = GetNextVdmCommand->iTask;
-            CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
-            CommandData->CodePage = GetNextVdmCommand->CodePage;
-            CommandData->ExitCode = GetNextVdmCommand->ExitCode;
-            CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
-            CommandData->VDMState = GetNextVdmCommand->VDMState;
-            CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
-
-            /* It was successful */
-            Result = TRUE;
-        }
+    if (CommandData->CurDirectoryLen)
+    {
+        /* Write back the current directory */
+        RtlMoveMemory(CommandData->CurDirectory,
+                      GetNextVdmCommand->CurDirectory,
+                      GetNextVdmCommand->CurDirectoryLen);
+
+        /* Set the actual length */
+        CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
     }
-    else
+
+    if (CommandData->EnvLen)
     {
-        /* Call CSRSS */
-        Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
-                                     NULL,
-                                     CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
-                                     sizeof(*IsFirstVdm));
-        if (!NT_SUCCESS(Status))
-        {
-            BaseSetLastNTError(Status);
-            goto Cleanup;
-        }
+        /* Write back the environment */
+        RtlMoveMemory(CommandData->Env,
+                      GetNextVdmCommand->Env,
+                      GetNextVdmCommand->EnvLen);
 
-        /* Return TRUE if this is the first VDM */
-        Result = IsFirstVdm->FirstVDM;
+        /* Set the actual length */
+        CommandData->EnvLen = GetNextVdmCommand->EnvLen;
+    }
+
+    if (CommandData->DesktopLen)
+    {
+        /* Write back the desktop name */
+        RtlMoveMemory(CommandData->Desktop,
+                      GetNextVdmCommand->Desktop,
+                      GetNextVdmCommand->DesktopLen);
+
+        /* Set the actual length */
+        CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
+    }
+
+    if (CommandData->TitleLen)
+    {
+        /* Write back the title */
+        RtlMoveMemory(CommandData->Title,
+                      GetNextVdmCommand->Title,
+                      GetNextVdmCommand->TitleLen);
+
+        /* Set the actual length */
+        CommandData->TitleLen = GetNextVdmCommand->TitleLen;
+    }
+
+    if (CommandData->ReservedLen)
+    {
+        /* Write back the reserved parameter */
+        RtlMoveMemory(CommandData->Reserved,
+                      GetNextVdmCommand->Reserved,
+                      GetNextVdmCommand->ReservedLen);
+
+        /* Set the actual length */
+        CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
     }
 
+    /* Write the remaining output parameters */
+    CommandData->TaskId        = GetNextVdmCommand->iTask;
+    CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
+    CommandData->CodePage      = GetNextVdmCommand->CodePage;
+    CommandData->ExitCode      = GetNextVdmCommand->ExitCode;
+    CommandData->CurrentDrive  = GetNextVdmCommand->CurrentDrive;
+    CommandData->VDMState      = GetNextVdmCommand->VDMState;
+    CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
+
+    /* It was successful */
+    Success = TRUE;
+
 Cleanup:
     if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer); 
-    return Result;
+    return Success;
 }
 
 
index 2493120..ca9c33e 100644 (file)
@@ -22,9 +22,31 @@ LIST_ENTRY VDMConsoleListHead;
 RTL_CRITICAL_SECTION DosCriticalSection;
 RTL_CRITICAL_SECTION WowCriticalSection;
 
-/* FUNCTIONS ******************************************************************/
+/* HELPER FUNCTIONS ***********************************************************/
 
-NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
+PVDM_CONSOLE_RECORD BaseSrvCreateConsoleRecord(VOID)
+{
+    PVDM_CONSOLE_RECORD ConsoleRecord;
+
+    ConsoleRecord = RtlAllocateHeap(BaseSrvHeap, HEAP_ZERO_MEMORY,
+                                    sizeof(VDM_CONSOLE_RECORD));
+    if (ConsoleRecord == NULL)
+        return NULL;
+
+    /* Initialize the console record */
+    ConsoleRecord->ConsoleHandle = NULL;
+    ConsoleRecord->ProcessHandle = NULL;
+    ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
+    ConsoleRecord->ReenterCount = 0;
+    ConsoleRecord->CurrentDirs = NULL;
+    ConsoleRecord->CurDirsLength = 0;
+    ConsoleRecord->SessionId = 0;
+    InitializeListHead(&ConsoleRecord->DosListHead);
+
+    return ConsoleRecord;
+}
+
+NTSTATUS BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
 {
     PLIST_ENTRY i;
     PVDM_CONSOLE_RECORD CurrentRecord = NULL;
@@ -46,7 +68,31 @@ NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD
     return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
 }
 
-NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
+VOID BaseSrvDestroyConsoleRecord(PVDM_CONSOLE_RECORD ConsoleRecord)
+{
+    if (ConsoleRecord->CurrentDirs != NULL)
+    {
+        /* Free the current directories */
+        RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
+        ConsoleRecord->CurrentDirs = NULL;
+        ConsoleRecord->CurDirsLength = 0;
+    }
+
+    /* Close the process handle */
+    if (ConsoleRecord->ProcessHandle)
+        NtClose(ConsoleRecord->ProcessHandle);
+
+    /* Close the event handle */
+    if (ConsoleRecord->ServerEvent)
+        NtClose(ConsoleRecord->ServerEvent);
+
+    /* Remove the console record */
+    // RemoveEntryList(&ConsoleRecord->Entry);
+    RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
+
+}
+
+NTSTATUS GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
 {
     PLIST_ENTRY i;
     PVDM_CONSOLE_RECORD CurrentRecord = NULL;
@@ -65,7 +111,7 @@ NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Re
     return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
 }
 
-ULONG NTAPI GetNextDosSesId(VOID)
+ULONG GetNextDosSesId(VOID)
 {
     ULONG SessionId;
     PLIST_ENTRY i;
@@ -94,7 +140,7 @@ ULONG NTAPI GetNextDosSesId(VOID)
     return SessionId;
 }
 
-BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
+BOOLEAN BaseSrvIsVdmAllowed(VOID)
 {
     NTSTATUS Status;
     BOOLEAN VdmAllowed = TRUE;
@@ -191,7 +237,7 @@ BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
     return VdmAllowed;
 }
 
-NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
+NTSTATUS BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
 {
     NTSTATUS Status;
 
@@ -212,7 +258,27 @@ NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientE
     return Status;
 }
 
-VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
+VOID BaseSrvDestroyPairWaitHandles(HANDLE ServerEvent, HANDLE ClientEvent)
+{
+    if (ServerEvent) NtClose(ServerEvent);
+    if (ClientEvent)
+    {
+        /* Close the remote handle */
+        NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
+                          ClientEvent,
+                          NULL,
+                          NULL,
+                          0,
+                          0,
+                          DUPLICATE_CLOSE_SOURCE);
+    }
+}
+
+/* WOW SUPPORT FUNCTIONS ******************************************************/
+
+/* DOS SUPPORT FUNCTIONS ******************************************************/
+
+VOID BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
 {
     /* Free the allocated structure members */
     if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
@@ -228,9 +294,7 @@ VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
     RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
 }
 
-VOID
-NTAPI
-BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
+VOID BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
 {
     ULONG ProcessId = HandleToUlong(CsrProcess->ClientId.UniqueProcess);
     PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
@@ -241,22 +305,33 @@ BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
     RtlEnterCriticalSection(&DosCriticalSection);
 
     /* Search for a record that has the same process handle */
-    for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink)
+    i = VDMConsoleListHead.Flink;
+    while (i != &VDMConsoleListHead)
     {
         ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
+        i = i->Flink;
 
         if (ConsoleRecord->ProcessId == ProcessId)
         {
+            if (ConsoleRecord->ServerEvent)
+            {
+                NtClose(ConsoleRecord->ServerEvent);
+                ConsoleRecord->ServerEvent = NULL;
+            }
+
             /* Cleanup the DOS records */
-            while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
+            while (!IsListEmpty(&ConsoleRecord->DosListHead))
             {
                 DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
-                                              VDM_DOS_RECORD,
-                                              Entry);
+                                              VDM_DOS_RECORD, Entry);
 
                 /* Set the event and close it */
-                NtSetEvent(DosRecord->ServerEvent, NULL);
-                NtClose(DosRecord->ServerEvent);
+                if (DosRecord->ServerEvent)
+                {
+                    NtSetEvent(DosRecord->ServerEvent, NULL);
+                    NtClose(DosRecord->ServerEvent);
+                    DosRecord->ServerEvent = NULL;
+                }
 
                 /* Remove the DOS entry */
                 if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
@@ -264,24 +339,9 @@ BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
                 RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
             }
 
-            if (ConsoleRecord->CurrentDirs != NULL)
-            {
-                /* Free the current directories */
-                RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
-                ConsoleRecord->CurrentDirs = NULL;
-                ConsoleRecord->CurDirsLength = 0;
-            }
-
-            /* Close the process handle */
-            if (ConsoleRecord->ProcessHandle) NtClose(ConsoleRecord->ProcessHandle);
-
-            /* Close the event handle */
-            if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
-
             /* Remove the console record */
-            i = i->Blink;
             RemoveEntryList(&ConsoleRecord->Entry);
-            RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
+            BaseSrvDestroyConsoleRecord(ConsoleRecord);
         }
     }
 
@@ -289,7 +349,7 @@ BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
     RtlLeaveCriticalSection(&DosCriticalSection);
 }
 
-BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
+BOOLEAN BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
 {
     BOOLEAN Success = FALSE;
     PVDM_COMMAND_INFO CommandInfo = NULL;
@@ -436,8 +496,8 @@ Cleanup:
     return Success;
 }
 
-NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
-                                      PBASE_GET_NEXT_VDM_COMMAND Message)
+NTSTATUS BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
+                                PBASE_GET_NEXT_VDM_COMMAND Message)
 {
     NTSTATUS Status = STATUS_SUCCESS;
 
@@ -453,116 +513,84 @@ NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
     Message->VDMState = CommandInfo->VDMState;
     Message->fComingFromBat = CommandInfo->ComingFromBat;
 
-    if (CommandInfo->CmdLen && Message->CmdLen)
+    if (Message->CmdLen >= CommandInfo->CmdLen)
     {
-        if (Message->CmdLen >= CommandInfo->CmdLen)
-        {
-            /* Copy the command line */
-            RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->CmdLen = CommandInfo->CmdLen;
+        /* Copy the command line */
+        RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->CmdLen = CommandInfo->CmdLen;
 
-    if (CommandInfo->AppLen && Message->AppLen)
+    if (Message->AppLen >= CommandInfo->AppLen)
     {
-        if (Message->AppLen >= CommandInfo->AppLen)
-        {
-            /* Copy the application name */
-            RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->AppLen = CommandInfo->AppLen;
+        /* Copy the application name */
+        RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->AppLen = CommandInfo->AppLen;
 
-    if (CommandInfo->PifLen && Message->PifLen)
+    if (Message->PifLen >= CommandInfo->PifLen)
     {
-        if (Message->PifLen >= CommandInfo->PifLen)
-        {
-            /* Copy the PIF file name */
-            RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->PifLen = CommandInfo->PifLen;
+        /* Copy the PIF file name */
+        RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->PifLen = CommandInfo->PifLen;
 
-    if (CommandInfo->CurDirectoryLen && Message->CurDirectoryLen)
+    if (Message->CurDirectoryLen >= CommandInfo->CurDirectoryLen)
     {
-        if (Message->CurDirectoryLen >= CommandInfo->CurDirectoryLen)
-        {
-            /* Copy the current directory */
-            RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
+        /* Copy the current directory */
+        RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
 
-    if (CommandInfo->EnvLen && Message->EnvLen)
+    if (Message->EnvLen >= CommandInfo->EnvLen)
     {
-        if (Message->EnvLen >= CommandInfo->EnvLen)
-        {
-            /* Copy the environment */
-            RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->EnvLen = CommandInfo->EnvLen;
+        /* Copy the environment */
+        RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->EnvLen = CommandInfo->EnvLen;
 
     /* Copy the startup info */
     RtlMoveMemory(Message->StartupInfo,
                   &CommandInfo->StartupInfo,
                   sizeof(STARTUPINFOA));
 
-    if (CommandInfo->DesktopLen && Message->DesktopLen)
+    if (Message->DesktopLen >= CommandInfo->DesktopLen)
     {
-        if (Message->DesktopLen >= CommandInfo->DesktopLen)
-        {
-            /* Copy the desktop name */
-            RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->DesktopLen = CommandInfo->DesktopLen;
+        /* Copy the desktop name */
+        RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->DesktopLen = CommandInfo->DesktopLen;
 
-    if (CommandInfo->TitleLen && Message->TitleLen)
+    if (Message->TitleLen >= CommandInfo->TitleLen)
     {
-        if (Message->TitleLen >= CommandInfo->TitleLen)
-        {
-            /* Copy the title */
-            RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->TitleLen = CommandInfo->TitleLen;
+        /* Copy the title */
+        RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->TitleLen = CommandInfo->TitleLen;
 
-    if (CommandInfo->ReservedLen && Message->ReservedLen)
+    if (Message->ReservedLen >= CommandInfo->ReservedLen)
     {
-        if (Message->ReservedLen >= CommandInfo->ReservedLen)
-        {
-            /* Copy the reserved parameter */
-            RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
-        }
-        else Status = STATUS_BUFFER_TOO_SMALL;
-
-        Message->ReservedLen = CommandInfo->ReservedLen;
+        /* Copy the reserved parameter */
+        RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
     }
+    else Status = STATUS_INVALID_PARAMETER;
+    Message->ReservedLen = CommandInfo->ReservedLen;
 
     return Status;
 }
 
-VOID NTAPI BaseInitializeVDM(VOID)
+VOID BaseInitializeVDM(VOID)
 {
     /* Initialize the list head */
     InitializeListHead(&VDMConsoleListHead);
 
-    /* Initialize the critical section */
+    /* Initialize the critical sections */
     RtlInitializeCriticalSection(&DosCriticalSection);
     RtlInitializeCriticalSection(&WowCriticalSection);
 }
@@ -577,6 +605,7 @@ CSR_API(BaseSrvCheckVDM)
     PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
     PVDM_DOS_RECORD DosRecord = NULL;
     BOOLEAN NewConsoleRecord = FALSE;
+    BOOLEAN NewDosRecord = FALSE;
 
     /* Don't do anything if the VDM has been disabled in the registry */
     if (!BaseSrvIsVdmAllowed()) return STATUS_VDM_DISALLOWED;
@@ -627,53 +656,75 @@ CSR_API(BaseSrvCheckVDM)
         /* Get the console record */
         Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
                                          &ConsoleRecord);
-
         if (!NT_SUCCESS(Status))
         {
             /* Allocate a new console record */
-            ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap,
-                                                                 HEAP_ZERO_MEMORY,
-                                                                 sizeof(VDM_CONSOLE_RECORD));
+            ConsoleRecord = BaseSrvCreateConsoleRecord();
             if (ConsoleRecord == NULL)
             {
                 Status = STATUS_NO_MEMORY;
                 goto Cleanup;
             }
 
-            /* Remember that the console record was allocated here */
-            NewConsoleRecord = TRUE;
-
             /* Initialize the console record */
             ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
-            ConsoleRecord->ProcessHandle = NULL;
-            ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
-            ConsoleRecord->ReenterCount = 0;
-            ConsoleRecord->CurrentDirs = NULL;
-            ConsoleRecord->CurDirsLength = 0;
-            ConsoleRecord->SessionId = GetNextDosSesId();
-            InitializeListHead(&ConsoleRecord->DosListHead);
+            if (ConsoleRecord->ConsoleHandle == NULL)
+            {
+                /* The parent doesn't have a console, get a new session ID */
+                ConsoleRecord->SessionId = GetNextDosSesId();
+            }
+            else
+            {
+                /* No session ID is needed */
+                ConsoleRecord->SessionId = 0;
+            }
+
+            /* Remember that the console record was allocated here */
+            NewConsoleRecord = TRUE;
         }
 
-        /* Allocate a new DOS record */
-        DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
-                                                     HEAP_ZERO_MEMORY,
-                                                     sizeof(VDM_DOS_RECORD));
-        if (DosRecord == NULL)
+        if (!NewConsoleRecord)
         {
-            Status = STATUS_NO_MEMORY;
-            goto Cleanup;
+            /* Get the primary DOS record */
+            DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
+                                                           VDM_DOS_RECORD, Entry);
+
+            if (DosRecord->State != VDM_READY) // == VDM_NOT_READY
+            {
+                /* Allocate a new DOS record */
+                DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
+                                                             HEAP_ZERO_MEMORY,
+                                                             sizeof(VDM_DOS_RECORD));
+                if (DosRecord == NULL)
+                {
+                    Status = STATUS_NO_MEMORY;
+                    goto Cleanup;
+                }
+
+                /* Remember that the DOS record was allocated here */
+                NewDosRecord = TRUE;
+            }
+        }
+        else
+        {
+            /* Allocate a new DOS record */
+            DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
+                                                         HEAP_ZERO_MEMORY,
+                                                         sizeof(VDM_DOS_RECORD));
+            if (DosRecord == NULL)
+            {
+                Status = STATUS_NO_MEMORY;
+                goto Cleanup;
+            }
+
+            /* Remember that the DOS record was allocated here */
+            NewDosRecord = TRUE;
         }
 
         /* Initialize the DOS record */
-        DosRecord->State = VDM_NOT_LOADED;
+        DosRecord->State = VDM_NOT_READY;
         DosRecord->ExitCode = 0;
 
-        Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
-        if (!NT_SUCCESS(Status)) goto Cleanup;
-
-        /* Return the client event handle */
-        CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
-
         /* Translate the input structure into a VDM command structure and set it in the DOS record */
         if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
         {
@@ -682,9 +733,23 @@ CSR_API(BaseSrvCheckVDM)
             goto Cleanup;
         }
 
-        /* Add the DOS record */
-        InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
+        if (NewDosRecord)
+        {
+            /* Add the DOS record */
+            InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
+        }
+
+        if (!NewConsoleRecord)
+        {
+            Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
+            if (!NT_SUCCESS(Status)) goto Cleanup;
+
+            /* Return the client event handle */
+            CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
+        }
 
+        // FIXME: We may notify ONLY if ConsoleRecord->nReEntrancy is > 0
+        // in case NewConsoleRecord == FALSE AND NewDosRecord == TRUE.
         if (ConsoleRecord->ServerEvent)
         {
             /* Signal the session event */
@@ -697,13 +762,7 @@ CSR_API(BaseSrvCheckVDM)
             InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
         }
 
-        if (ConsoleRecord->ConsoleHandle == NULL)
-        {
-            /* The parent doesn't have a console, so return the session ID */
-            CheckVdmRequest->iTask = ConsoleRecord->SessionId;
-        }
-        else CheckVdmRequest->iTask = 0;
-
+        CheckVdmRequest->iTask = ConsoleRecord->SessionId;
         CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
         Status = STATUS_SUCCESS;
     }
@@ -718,21 +777,13 @@ Cleanup:
     /* Check if it failed */
     if (!NT_SUCCESS(Status))
     {
-        /* Free the DOS record */
-        if (DosRecord != NULL)
+        /* Free the DOS record if it was allocated here */
+        if (NewDosRecord)
         {
-            if (DosRecord->ServerEvent) NtClose(DosRecord->ServerEvent);
-            if (DosRecord->ClientEvent)
-            {
-                /* Close the remote handle */
-                NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
-                                  DosRecord->ClientEvent,
-                                  NULL,
-                                  NULL,
-                                  0,
-                                  0,
-                                  DUPLICATE_CLOSE_SOURCE);
-            }
+            ASSERT(DosRecord != NULL);
+
+            BaseSrvDestroyPairWaitHandles(DosRecord->ServerEvent,
+                                          DosRecord->ClientEvent);
 
             RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
             DosRecord = NULL;
@@ -741,6 +792,8 @@ Cleanup:
         /* Free the console record if it was allocated here */
         if (NewConsoleRecord)
         {
+            ASSERT(ConsoleRecord != NULL);
+
             RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
             ConsoleRecord = NULL;
         }
@@ -787,8 +840,7 @@ CSR_API(BaseSrvUpdateVDMEntry)
 
         /* Get the primary DOS record */
         DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
-                                                       VDM_DOS_RECORD,
-                                                       Entry);
+                                                       VDM_DOS_RECORD, Entry);
 
         switch (UpdateVdmEntryRequest->EntryIndex)
         {
@@ -811,10 +863,8 @@ CSR_API(BaseSrvUpdateVDMEntry)
                      */
                     if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
                     {
-                        if (ConsoleRecord->ProcessHandle) NtClose(ConsoleRecord->ProcessHandle);
-                        if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
                         RemoveEntryList(&ConsoleRecord->Entry);
-                        RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
+                        BaseSrvDestroyConsoleRecord(ConsoleRecord);
                     }
                 }
 
@@ -836,6 +886,10 @@ CSR_API(BaseSrvUpdateVDMEntry)
                                            DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
                 if (!NT_SUCCESS(Status)) goto Cleanup;
 
+                //
+                // FIXME! Should we always do the following??
+                //
+
                 /* Create a pair of handles to one event object */
                 Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent,
                                                       &DosRecord->ClientEvent);
@@ -881,7 +935,7 @@ CSR_API(BaseSrvGetNextVDMCommand)
 {
     NTSTATUS Status;
     PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest =
-    &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
+        &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
     PRTL_CRITICAL_SECTION CriticalSection;
     PLIST_ENTRY i = NULL;
     PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
@@ -935,7 +989,14 @@ CSR_API(BaseSrvGetNextVDMCommand)
     /* Enter the critical section */
     RtlEnterCriticalSection(CriticalSection);
 
-    if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
+    if (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
+    {
+        // TODO: WOW SUPPORT NOT IMPLEMENTED
+        UNIMPLEMENTED;
+        Status = STATUS_NOT_IMPLEMENTED;
+        goto Cleanup;
+    }
+    // else if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
     {
         if (GetNextVdmCommandRequest->iTask != 0)
         {
@@ -1018,16 +1079,16 @@ CSR_API(BaseSrvGetNextVDMCommand)
             DosRecord->ServerEvent = NULL;
         }
 
-        /* Search for a DOS record that isn't loaded yet */
+        /* Search for a DOS record that is currently running and has command information */
         for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
         {
             DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
-            if (DosRecord->State == VDM_NOT_LOADED) break;
+            if ((DosRecord->State == VDM_NOT_READY) && (DosRecord->CommandInfo != NULL)) break;
         }
 
+        /* Check if we found any */
         if (i != &ConsoleRecord->DosListHead)
         {
-            /* DOS tasks which haven't been loaded yet should have a command info structure */
             ASSERT(DosRecord->CommandInfo != NULL);
 
             /* Check if the caller only wants environment data */
@@ -1060,22 +1121,22 @@ CSR_API(BaseSrvGetNextVDMCommand)
                 DosRecord->CommandInfo = NULL;
 
                 /* Update the VDM state */
-                GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY;
+                DosRecord->State = VDM_NOT_READY;
             }
 
             Status = STATUS_SUCCESS;
             goto Cleanup;
         }
     }
-    else
-    {
-        // TODO: WOW SUPPORT NOT IMPLEMENTED
-        Status = STATUS_NOT_IMPLEMENTED;
-        goto Cleanup;
-    }
 
-    /* There is no command yet */
-    if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT))
+    GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
+
+    /*
+     * There is no command yet. Prepare for waiting if we asked so,
+     * and if we were not retrying a request.
+     */
+    if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT) ||
+        !(GetNextVdmCommandRequest->VDMState & VDM_FLAG_RETRY))
     {
         if (ConsoleRecord->ServerEvent)
         {
@@ -1122,16 +1183,30 @@ CSR_API(BaseSrvExitVDM)
         Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
         if (!NT_SUCCESS(Status)) goto Cleanup;
 
+        if (ConsoleRecord->ServerEvent)
+            ExitVdmRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
+
+        // NOTE: The following is the same as in BaseSrvCleanupVDMResources.
+
+        if (ConsoleRecord->ServerEvent)
+        {
+            NtClose(ConsoleRecord->ServerEvent);
+            ConsoleRecord->ServerEvent = NULL;
+        }
+
         /* Cleanup the DOS records */
-        while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead)
+        while (!IsListEmpty(&ConsoleRecord->DosListHead))
         {
             DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
-                                          VDM_DOS_RECORD,
-                                          Entry);
+                                          VDM_DOS_RECORD, Entry);
 
             /* Set the event and close it */
-            NtSetEvent(DosRecord->ServerEvent, NULL);
-            NtClose(DosRecord->ServerEvent);
+            if (DosRecord->ServerEvent)
+            {
+                NtSetEvent(DosRecord->ServerEvent, NULL);
+                NtClose(DosRecord->ServerEvent);
+                DosRecord->ServerEvent = NULL;
+            }
 
             /* Remove the DOS entry */
             if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
@@ -1139,20 +1214,9 @@ CSR_API(BaseSrvExitVDM)
             RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
         }
 
-        if (ConsoleRecord->CurrentDirs != NULL)
-        {
-            /* Free the current directories */
-            RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
-            ConsoleRecord->CurrentDirs = NULL;
-            ConsoleRecord->CurDirsLength = 0;
-        }
-
-        /* Close the event handle */
-        if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
-
         /* Remove the console record */
         RemoveEntryList(&ConsoleRecord->Entry);
-        RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
+        BaseSrvDestroyConsoleRecord(ConsoleRecord);
     }
     else
     {
@@ -1220,6 +1284,8 @@ CSR_API(BaseSrvGetVDMExitCode)
     /* Return the exit code */
     GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
 
+    // FIXME: We may just change DosRecord->State to VDM_READY in some cases...
+
     /* Since this is a zombie task record, remove it */
     if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
     RemoveEntryList(&DosRecord->Entry);
@@ -1245,13 +1311,20 @@ CSR_API(BaseSrvSetReenterCount)
     Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
     if (!NT_SUCCESS(Status)) goto Cleanup;
 
-    if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++;
+    if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT)
+    {
+        ConsoleRecord->ReenterCount++;
+    }
     else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
     {
         ConsoleRecord->ReenterCount--;
-        if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL);
+        if (ConsoleRecord->ServerEvent)
+            NtSetEvent(ConsoleRecord->ServerEvent, NULL);
+    }
+    else
+    {
+        Status = STATUS_INVALID_PARAMETER;
     }
-    else Status = STATUS_INVALID_PARAMETER;
 
 Cleanup:
     /* Leave the critical section */
index db11e65..5f07c3e 100644 (file)
@@ -43,18 +43,11 @@ typedef struct _VDM_DOS_RECORD
 
 /* FUNCTIONS ******************************************************************/
 
-NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record);
-NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record);
-ULONG NTAPI GetNextDosSesId(VOID);
-BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID);
-NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent);
-VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo);
-VOID NTAPI BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess);
-BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord);
-NTSTATUS NTAPI BaseSrvFillCommandInfo(
-    PVDM_COMMAND_INFO CommandInfo,
-    PBASE_GET_NEXT_VDM_COMMAND Message
-);
-VOID NTAPI BaseInitializeVDM(VOID);
+NTSTATUS BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record);
+NTSTATUS GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record);
+
+BOOLEAN BaseSrvIsVdmAllowed(VOID);
+VOID BaseInitializeVDM(VOID);
+VOID BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess);
 
 #endif // __VDM_H__