[KERNEL32]
[reactos.git] / dll / win32 / kernel32 / client / vdm.c
index d079da9..1bb6acd 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,43 +49,153 @@ 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;
 }
 
+NTSTATUS
+WINAPI
+BaseCheckVDM(IN ULONG BinaryType,
+             IN PCWCH ApplicationName,
+             IN PCWCH CommandLine,
+             IN PCWCH CurrentDirectory,
+             IN PANSI_STRING AnsiEnvironment,
+             IN PCSR_API_MESSAGE ApiMessage,
+             IN OUT PULONG iTask,
+             IN DWORD CreationFlags,
+             IN LPSTARTUPINFOW StartupInfo,
+             IN HANDLE hUserToken OPTIONAL)
+{
+    /* This is not supported */
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+BOOL
+WINAPI
+BaseUpdateVDMEntry(IN ULONG UpdateIndex,
+                   IN OUT PHANDLE WaitHandle,
+                   IN ULONG IndexInfo,
+                   IN ULONG BinaryType)
+{
+    NTSTATUS Status;
+    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 */
+            UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle);
+            UpdateVdmEntry->VDMCreationState = IndexInfo;
+            break;
+        }
+
+        /* VDM is ready with a new process handle */
+        case VdmEntryUpdateProcess:
+        {
+            /* Send it the process handle */
+            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 */
+        UpdateVdmEntry->ConsoleHandle = (HANDLE)-1;
+    }
+    else if (UpdateVdmEntry->iTask)
+    {
+        /* No handle for true VDM */
+        UpdateVdmEntry->ConsoleHandle = NULL;
+    }
+    else
+    {
+        /* Otherwise, use the regular console handle */
+        UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+    }
+
+    /* Finally write the index and binary type */
+    UpdateVdmEntry->EntryIndex = UpdateIndex;
+    UpdateVdmEntry->BinaryType = BinaryType;
+
+    /* Send the message to CSRSS */
+    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(Status);
+        return FALSE;
+    }
+
+    /* If this was an update, CSRSS returns a new wait handle */
+    if (UpdateIndex == VdmEntryUpdateProcess)
+    {
+        /* Return it to the caller */
+        *WaitHandle = UpdateVdmEntry->WaitObjectForParent;
+    }
+
+    /* We made it */
+    return TRUE;
+}
+
 BOOL
 WINAPI
-BaseCheckForVDM(IN HANDLE hProcess,
-                OUT LPDWORD lpExitCode)
+BaseCheckForVDM(IN HANDLE ProcessHandle,
+                OUT LPDWORD ExitCode)
 {
     NTSTATUS Status;
     EVENT_BASIC_INFORMATION EventBasicInfo;
+    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(hProcess,
+    Status = NtQueryEvent(ProcessHandle,
                           EventBasicInformation,
                           &EventBasicInfo,
                           sizeof(EventBasicInfo),
                           NULL);
     if (!NT_SUCCESS(Status)) return FALSE;
 
-    /* FIXME: Send a message to csrss */
-    return FALSE;
+    /* Setup the input parameters */
+    GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+    GetVdmExitCode->hParent = ProcessHandle;
+
+    /* Call CSRSS */
+    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 = GetVdmExitCode->ExitCode;
+    return TRUE;
 }
 
 BOOL
 WINAPI
-BaseGetVdmConfigInfo(IN LPCWSTR Reserved,
+BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
                      IN ULONG DosSeqId,
                      IN ULONG BinaryType,
                      IN PUNICODE_STRING CmdLineString,
@@ -97,8 +207,8 @@ 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 */
@@ -109,30 +219,37 @@ BaseGetVdmConfigInfo(IN LPCWSTR Reserved,
         SetLastError(ERROR_INVALID_NAME);
         return FALSE;
     }
-    
+
     /* 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 */
     return RtlCreateUnicodeString(CmdLineString, CommandLine);
 }
@@ -147,13 +264,13 @@ BaseGetEnvNameType_U(IN PWCHAR Name,
 
     /* Start by assuming unknown type */
     NameType = 1;
-    
+
     /* Loop all the environment names */
     for (i = 0; i < (sizeof(BasepEnvNameType) / sizeof(ENV_INFO)); i++)
     {
         /* Get this entry */
         EnvInfo = &BasepEnvNameType[i];
-        
+
         /* Check if it matches the name */
         if ((EnvInfo->NameLength == NameLength) &&
             !(_wcsnicmp(EnvInfo->Name, Name, NameLength)))
@@ -163,7 +280,7 @@ BaseGetEnvNameType_U(IN PWCHAR Name,
             break;
         }
     }
-    
+
     /* Return what we found, or unknown if nothing */
     return NameType;
 }
@@ -174,10 +291,10 @@ BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv,
                           IN PUNICODE_STRING UnicodeEnv)
 {
     ULONG Dummy = 0;
-    
+
     /* Clear the ASCII buffer since Rtl creates this for us */
     if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv);
-    
+
     /* The Unicode buffer is build by hand, though */
     if (UnicodeEnv->Buffer)
     {
@@ -200,7 +317,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 */
@@ -231,7 +348,7 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
         SetLastError(ERROR_BAD_ENVIRONMENT);
         goto Quickie;
     }
-    
+
     /* Count how much space the whole environment takes */
     p = Environment;
     while ((*p++ != UNICODE_NULL) && (*p != UNICODE_NULL)) EnvironmentSize++;
@@ -251,7 +368,7 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
         NewEnvironment = NULL;
         goto Quickie;
     }
-    
+
     /* Begin parsing the new environment */
     p = NewEnvironment;
 
@@ -259,12 +376,12 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
 
     /* Terminate it */
     *p++ = UNICODE_NULL;
-    
+
     /* 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);
     if (!NT_SUCCESS(Status))
@@ -282,14 +399,14 @@ BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
 Quickie:
     /* Cleanup path starts here, start by destroying the envrionment copy */
     if (!(lpEnvironment) && (Environment)) RtlDestroyEnvironment(Environment);
-    
+
     /* See if we are here due to failure */
     if (NewEnvironment)
     {
         /* Initialize the paths to be empty */
         RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0);
         RtlInitEmptyAnsiString(AnsiEnv, NULL, 0);
-        
+
         /* Free the environment copy */
         RegionSize = 0;
         Status = NtFreeVirtualMemory(NtCurrentProcess(),
@@ -298,7 +415,7 @@ Quickie:
                                      MEM_RELEASE);
         ASSERT(NT_SUCCESS(Status));
     }
-    
+
     /* Return the result */
     return Result;
 }
@@ -573,7 +690,7 @@ GetBinaryTypeW (
     }
   }
 
-  DPRINT1("Invalid binary type returned!\n", BinType);
+  DPRINT1("Invalid binary type %lu returned!\n", BinType);
   return FALSE;
 }
 
@@ -635,17 +752,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);
+    }
 }
 
 
@@ -654,9 +785,7 @@ ExitVDM (
  */
 DWORD
 WINAPI
-GetNextVDMCommand (
-    DWORD   Unknown0
-    )
+GetNextVDMCommand(PGET_NEXT_VDM_COMMAND_DATA CommandData)
 {
     STUB;
     return 0;