[NTVDM]: Implement and export VDDTerminateVDM.
[reactos.git] / subsystems / ntvdm / dos.c
index 05747d4..e478070 100644 (file)
@@ -14,6 +14,7 @@
 #include "dos.h"
 
 #include "bios.h"
+#include "bop.h"
 #include "int32.h"
 #include "registers.h"
 
@@ -31,6 +32,10 @@ static BYTE DosAllocStrategy = DOS_ALLOC_BEST_FIT;
 static BOOLEAN DosUmbLinked = FALSE;
 static WORD DosErrorLevel = 0x0000;
 
+/* BOP Identifiers */
+#define BOP_DOS 0x50    // DOS System BOP (for NTIO.SYS and NTDOS.SYS)
+#define BOP_CMD 0x54    // DOS Command Interpreter BOP (for COMMAND.COM)
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
 /* Taken from base/shell/cmd/console.c */
@@ -1402,6 +1407,94 @@ BOOLEAN DosHandleIoctl(BYTE ControlCode, WORD FileHandle)
     }
 }
 
+VOID WINAPI DosSystemBop(LPWORD Stack)
+{
+    /* Get the Function Number and skip it */
+    BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
+    setIP(getIP() + 1);
+
+    DPRINT1("Unknown DOS System BOP Function: 0x%02X\n", FuncNum);
+}
+
+VOID WINAPI DosCmdInterpreterBop(LPWORD Stack)
+{
+    /* Get the Function Number and skip it */
+    BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
+    setIP(getIP() + 1);
+
+    switch (FuncNum)
+    {
+        case 0x08: // Launch external command
+        {
+#define CMDLINE_LENGTH  1024
+
+            BOOL Result;
+            DWORD dwExitCode;
+
+            LPSTR Command = (LPSTR)SEG_OFF_TO_PTR(getDS(), getSI());
+            CHAR CommandLine[CMDLINE_LENGTH] = "";
+            STARTUPINFOA StartupInfo;
+            PROCESS_INFORMATION ProcessInformation;
+            DPRINT1("CMD Run Command '%s'\n", Command);
+
+            Command[strlen(Command)-1] = 0;
+            
+            strcpy(CommandLine, "cmd.exe /c ");
+            strcat(CommandLine, Command);
+
+            ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+            ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
+
+            StartupInfo.cb = sizeof(StartupInfo);
+
+            DosPrintCharacter('\n');
+
+            Result = CreateProcessA(NULL,
+                                    CommandLine,
+                                    NULL,
+                                    NULL,
+                                    TRUE,
+                                    0,
+                                    NULL,
+                                    NULL,
+                                    &StartupInfo,
+                                    &ProcessInformation);
+            if (Result)
+            {
+                DPRINT1("Command '%s' launched successfully\n");
+
+                /* Wait for process termination */
+                WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
+
+                /* Get the exit code */
+                GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
+
+                /* Close handles */
+                CloseHandle(ProcessInformation.hThread);
+                CloseHandle(ProcessInformation.hProcess);
+            }
+            else
+            {
+                DPRINT1("Failed when launched command '%s'\n");
+                dwExitCode = GetLastError();
+            }
+            
+            DosPrintCharacter('\n');
+
+            setAL((UCHAR)dwExitCode);
+
+            break;
+        }
+
+        default:
+        {
+            DPRINT1("Unknown DOS CMD Interpreter BOP Function: 0x%02X\n", FuncNum);
+            // setCF(1); // Disable, otherwise we enter an infinite loop
+            break;
+        }
+    }
+}
+
 VOID WINAPI DosInt20h(LPWORD Stack)
 {
     /* This is the exit interrupt */
@@ -2479,9 +2572,28 @@ VOID WINAPI DosBreakInterrupt(LPWORD Stack)
 {
     UNREFERENCED_PARAMETER(Stack);
 
+    /* Stop the VDM */
     VdmRunning = FALSE;
 }
 
+VOID WINAPI DosFastConOut(LPWORD Stack)
+{
+    /*
+     * This is the DOS 2+ Fast Console Output Interrupt.
+     * See Ralf Brown: http://www.ctyme.com/intr/rb-4124.htm
+     * for more information.
+     */
+    UNREFERENCED_PARAMETER(Stack);
+
+    /*
+     * The default handler under DOS 2.x and 3.x simply calls INT 10/AH=0Eh.
+     * Do better and call directly BiosPrintCharacter: it's what INT 10/AH=0Eh
+     * does. Otherwise we would have to set BL to DOS_CHAR_ATTRIBUTE and
+     * BH to Bda->VideoPage.
+     */
+    BiosPrintCharacter(getAL(), DOS_CHAR_ATTRIBUTE, Bda->VideoPage);
+}
+
 VOID WINAPI DosInt2Fh(LPWORD Stack)
 {
     DPRINT1("DOS System Function INT 0x2F, AH = %xh, AL = %xh NOT IMPLEMENTED!\n",
@@ -2628,12 +2740,17 @@ BOOLEAN DosInitialize(VOID)
     DosSystemFileTable[1] = GetStdHandle(STD_OUTPUT_HANDLE);
     DosSystemFileTable[2] = GetStdHandle(STD_ERROR_HANDLE);
 
+    /* Register the DOS BOPs */
+    RegisterBop(BOP_DOS, DosSystemBop        );
+    RegisterBop(BOP_CMD, DosCmdInterpreterBop);
+
     /* Register the DOS 32-bit Interrupts */
     RegisterInt32(0x20, DosInt20h        );
     RegisterInt32(0x21, DosInt21h        );
 //  RegisterInt32(0x22, DosInt22h        ); // Termination
     RegisterInt32(0x23, DosBreakInterrupt); // Ctrl-C / Ctrl-Break
 //  RegisterInt32(0x24, DosInt24h        ); // Critical Error
+    RegisterInt32(0x29, DosFastConOut    ); // DOS 2+ Fast Console Output
     RegisterInt32(0x2F, DosInt2Fh        );
 
     return TRUE;