[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / ntvdm.c
index 813a885..9fd9d4a 100644 (file)
 
 #include "resource.h"
 
-/*
- * Activate this line if you want to run NTVDM in standalone mode with:
- * ntvdm.exe <program>
- */
-// #define STANDALONE
-
 /* VARIABLES ******************************************************************/
 
 static HANDLE ConsoleInput  = INVALID_HANDLE_VALUE;
@@ -39,7 +33,10 @@ static HMENU hConsoleMenu  = NULL;
 static INT   VdmMenuPos    = -1;
 static BOOLEAN ShowPointer = FALSE;
 
+#ifndef STANDALONE
 ULONG SessionId = 0;
+#endif
+
 HANDLE VdmTaskEvent = NULL;
 
 /*
@@ -54,7 +51,8 @@ typedef struct _VDM_MENUITEM
 
 static const VDM_MENUITEM VdmMenuItems[] =
 {
-    { IDS_VDM_QUIT, NULL, ID_VDM_QUIT },
+    { IDS_VDM_DUMPMEM, NULL, ID_VDM_DUMPMEM },
+    { IDS_VDM_QUIT   , NULL, ID_VDM_QUIT    },
 
     { 0, NULL, 0 }      /* End of list */
 };
@@ -121,10 +119,10 @@ AppendMenuItems(HMENU hMenu,
     } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
 }
 
-static VOID
+/*static*/ VOID
 CreateVdmMenu(HANDLE ConOutHandle)
 {
-    hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
+    hConsoleMenu = ConsoleMenuControl(ConOutHandle,
                                       ID_SHOWHIDE_MOUSE,
                                       ID_VDM_QUIT);
     if (hConsoleMenu == NULL) return;
@@ -134,7 +132,7 @@ CreateVdmMenu(HANDLE ConOutHandle)
     DrawMenuBar(GetConsoleWindow());
 }
 
-static VOID
+/*static*/ VOID
 DestroyVdmMenu(VOID)
 {
     UINT i = 0;
@@ -176,7 +174,8 @@ static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
-VOID DisplayMessage(LPCWSTR Format, ...)
+VOID
+DisplayMessage(LPCWSTR Format, ...)
 {
     WCHAR Buffer[256];
     va_list Parameters;
@@ -188,7 +187,9 @@ VOID DisplayMessage(LPCWSTR Format, ...)
     va_end(Parameters);
 }
 
-BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
+static BOOL
+WINAPI
+ConsoleCtrlHandler(DWORD ControlType)
 {
     switch (ControlType)
     {
@@ -224,12 +225,14 @@ BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
     return TRUE;
 }
 
-VOID ConsoleInitUI(VOID)
+static VOID
+ConsoleInitUI(VOID)
 {
     CreateVdmMenu(ConsoleOutput);
 }
 
-VOID ConsoleCleanupUI(VOID)
+static VOID
+ConsoleCleanupUI(VOID)
 {
     /* Display again properly the mouse pointer */
     if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
@@ -237,7 +240,97 @@ VOID ConsoleCleanupUI(VOID)
     DestroyVdmMenu();
 }
 
-DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
+static BOOL
+ConsoleAttach(VOID)
+{
+    /* Save the original input and output console modes */
+    if (!GetConsoleMode(ConsoleInput , &OrgConsoleInputMode ) ||
+        !GetConsoleMode(ConsoleOutput, &OrgConsoleOutputMode))
+    {
+        CloseHandle(ConsoleOutput);
+        CloseHandle(ConsoleInput);
+        wprintf(L"FATAL: Cannot save console in/out modes\n");
+        // return FALSE;
+    }
+
+    /* Initialize the UI */
+    ConsoleInitUI();
+
+    return TRUE;
+}
+
+static VOID
+ConsoleDetach(VOID)
+{
+    /* Restore the original input and output console modes */
+    SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
+    SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
+
+    /* Cleanup the UI */
+    ConsoleCleanupUI();
+}
+
+static BOOL
+ConsoleInit(VOID)
+{
+    /* Set the handler routine */
+    SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
+
+    /* Enable the CTRL_LAST_CLOSE_EVENT */
+    SetLastConsoleEventActive();
+
+    /*
+     * NOTE: The CONIN$ and CONOUT$ "virtual" files
+     * always point to non-redirected console handles.
+     */
+
+    /* Get the input handle to the real console, and check for success */
+    ConsoleInput = CreateFileW(L"CONIN$",
+                               GENERIC_READ | GENERIC_WRITE,
+                               FILE_SHARE_READ | FILE_SHARE_WRITE,
+                               NULL,
+                               OPEN_EXISTING,
+                               0,
+                               NULL);
+    if (ConsoleInput == INVALID_HANDLE_VALUE)
+    {
+        wprintf(L"FATAL: Cannot retrieve a handle to the console input\n");
+        return FALSE;
+    }
+
+    /* Get the output handle to the real console, and check for success */
+    ConsoleOutput = CreateFileW(L"CONOUT$",
+                                GENERIC_READ | GENERIC_WRITE,
+                                FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                NULL,
+                                OPEN_EXISTING,
+                                0,
+                                NULL);
+    if (ConsoleOutput == INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(ConsoleInput);
+        wprintf(L"FATAL: Cannot retrieve a handle to the console output\n");
+        return FALSE;
+    }
+
+    /* Effectively attach to the console */
+    return ConsoleAttach();
+}
+
+static VOID
+ConsoleCleanup(VOID)
+{
+    /* Detach from the console */
+    ConsoleDetach();
+
+    /* Close the console handles */
+    if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
+    if (ConsoleInput  != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
+}
+
+DWORD
+WINAPI
+PumpConsoleInput(LPVOID Parameter)
 {
     HANDLE ConsoleInput = (HANDLE)Parameter;
     INPUT_RECORD InputRecord;
@@ -276,6 +369,10 @@ DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
                         ShowPointer = !ShowPointer;
                         break;
 
+                    case ID_VDM_DUMPMEM:
+                        DumpMemory();
+                        break;
+
                     case ID_VDM_QUIT:
                         /* Stop the VDM */
                         EmulatorTerminate();
@@ -296,74 +393,10 @@ DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
     return 0;
 }
 
-BOOL ConsoleInit(VOID)
-{
-    /* Set the handler routine */
-    SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
-
-    /* Enable the CTRL_LAST_CLOSE_EVENT */
-    SetLastConsoleEventActive();
-
-    /* Get the input handle to the real console, and check for success */
-    ConsoleInput = CreateFileW(L"CONIN$",
-                               GENERIC_READ | GENERIC_WRITE,
-                               FILE_SHARE_READ | FILE_SHARE_WRITE,
-                               NULL,
-                               OPEN_EXISTING,
-                               0,
-                               NULL);
-    if (ConsoleInput == INVALID_HANDLE_VALUE)
-    {
-        wprintf(L"FATAL: Cannot retrieve a handle to the console input\n");
-        return FALSE;
-    }
-
-    /* Get the output handle to the real console, and check for success */
-    ConsoleOutput = CreateFileW(L"CONOUT$",
-                                GENERIC_READ | GENERIC_WRITE,
-                                FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                NULL,
-                                OPEN_EXISTING,
-                                0,
-                                NULL);
-    if (ConsoleOutput == INVALID_HANDLE_VALUE)
-    {
-        CloseHandle(ConsoleInput);
-        wprintf(L"FATAL: Cannot retrieve a handle to the console output\n");
-        return FALSE;
-    }
-
-    /* Save the original input and output console modes */
-    if (!GetConsoleMode(ConsoleInput , &OrgConsoleInputMode ) ||
-        !GetConsoleMode(ConsoleOutput, &OrgConsoleOutputMode))
-    {
-        CloseHandle(ConsoleOutput);
-        CloseHandle(ConsoleInput);
-        wprintf(L"FATAL: Cannot save console in/out modes\n");
-        return FALSE;
-    }
-
-    /* Initialize the UI */
-    ConsoleInitUI();
-
-    return TRUE;
-}
-
-VOID ConsoleCleanup(VOID)
-{
-    /* Restore the original input and output console modes */
-    SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
-    SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
-
-    /* Cleanup the UI */
-    ConsoleCleanupUI();
-
-    /* Close the console handles */
-    if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
-    if (ConsoleInput  != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
-}
-
-DWORD WINAPI CommandThreadProc(LPVOID Parameter)
+#ifndef STANDALONE
+static DWORD
+WINAPI
+CommandThreadProc(LPVOID Parameter)
 {
     BOOLEAN First = TRUE;
     DWORD Result;
@@ -373,9 +406,11 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
     CHAR PifFile[MAX_PATH];
     CHAR Desktop[MAX_PATH];
     CHAR Title[MAX_PATH];
-    CHAR Env[MAX_PATH];
+    ULONG EnvSize = 256;
+    PVOID Env = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
 
     UNREFERENCED_PARAMETER(Parameter);
+    ASSERT(Env != NULL);
 
     do
     {
@@ -396,47 +431,47 @@ DWORD WINAPI CommandThreadProc(LPVOID Parameter)
         CommandInfo.Title = Title;
         CommandInfo.TitleLen = sizeof(Title);
         CommandInfo.Env = Env;
-        CommandInfo.EnvLen = sizeof(Env);
+        CommandInfo.EnvLen = EnvSize;
 
         if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
 
-        /* Wait for the next available VDM */
-        if (!GetNextVDMCommand(&CommandInfo)) break;
+Command:
+        if (!GetNextVDMCommand(&CommandInfo))
+        {
+            if (CommandInfo.EnvLen > EnvSize)
+            {
+                /* Expand the environment size */
+                EnvSize = CommandInfo.EnvLen;
+                Env = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Env, EnvSize);
 
-        /* Start the process from the command line */
-        DPRINT1("Starting '%s'...\n", AppName);
+                /* Repeat the request */
+                goto Command;
+            }
 
-        Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
+            break;
+        }
+
+        /* Start the process from the command line */
+        DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine);
+        Result = DosStartProcess(AppName, CmdLine, Env);
         if (Result != ERROR_SUCCESS)
         {
             DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
-            break;
+            // break;
+            continue;
         }
 
-        /* Attach to the console */
-        if (!First) VgaAttachToConsole();
-
-        /* Perform a screen refresh */
-        VgaRefreshDisplay();
-
-        /* Start simulation */
-        SetEvent(VdmTaskEvent);
-        EmulatorSimulate();
-
-        /* Perform another screen refresh */
-        VgaRefreshDisplay();
-
-        /* Detach from the console */
-        VgaDetachFromConsole(FALSE);
-
         First = FALSE;
     }
     while (AcceptCommands);
 
+    HeapFree(GetProcessHeap(), 0, Env);
     return 0;
 }
+#endif
 
-INT wmain(INT argc, WCHAR *argv[])
+INT
+wmain(INT argc, WCHAR *argv[])
 {
 #ifdef STANDALONE
 
@@ -459,6 +494,7 @@ INT wmain(INT argc, WCHAR *argv[])
     }
 
 #else
+
     INT i;
     WCHAR *endptr;
 
@@ -530,27 +566,16 @@ INT wmain(INT argc, WCHAR *argv[])
 #else
 
     /* Start the process from the command line */
-    DPRINT1("Starting '%s'...\n", ApplicationName);
-
-    Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
-                               ApplicationName,
-                               CommandLine,
-                               GetEnvironmentStrings(),
-                               NULL,
-                               NULL);
+    DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine);
+    Result = DosStartProcess(ApplicationName,
+                             CommandLine,
+                             GetEnvironmentStrings());
     if (Result != ERROR_SUCCESS)
     {
         DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
         goto Cleanup;
     }
 
-    /* Start simulation */
-    SetEvent(VdmTaskEvent);
-    EmulatorSimulate();
-
-    /* Perform another screen refresh */
-    VgaRefreshDisplay();
-
 #endif
 
 Cleanup: