/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: subsys/ntvdm/ntvdm->c
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: ntvdm.c
* PURPOSE: Virtual DOS Machine
- * PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com)
- * UPDATE HISTORY:
- * Created 23/10/2002
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES *******************************************************************/
-#include <stdarg.h>
-#define WIN32_NO_STATUS
-#include <windef.h>
-#include <winbase.h>
-#include <wincon.h>
-#include <winuser.h>
-#include <stdio.h>
+#define NDEBUG
+
+#include "ntvdm.h"
+#include "emulator.h"
+
+#include "clock.h"
+#include "hardware/ps2.h"
+#include "hardware/vga.h"
+#include "bios/bios.h"
+#include "dos/dem.h"
#include "resource.h"
-#define NDEBUG
-#include <debug.h>
+/*
+ * Activate this line if you want to run NTVDM in standalone mode with:
+ * ntvdm.exe <program>
+ */
+#define STANDALONE
+
+/* VARIABLES ******************************************************************/
-/* GLOBALS ******************************************************************/
+static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
+static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
+static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
+static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
+static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
+static HANDLE CommandThread = NULL;
+static HMENU hConsoleMenu = NULL;
+static INT VdmMenuPos = -1;
+static BOOLEAN ShowPointer = FALSE;
+
+/*
+ * Those menu helpers were taken from the GUI frontend in winsrv.dll
+ */
+typedef struct _VDM_MENUITEM
+{
+ UINT uID;
+ const struct _VDM_MENUITEM *SubMenu;
+ WORD wCmdID;
+} VDM_MENUITEM, *PVDM_MENUITEM;
+
+static const VDM_MENUITEM VdmMenuItems[] =
+{
+ { IDS_VDM_QUIT, NULL, ID_VDM_QUIT },
-/* FUNCTIONS *****************************************************************/
+ { 0, NULL, 0 } /* End of list */
+};
-void PrintString(char* fmt,...)
+static const VDM_MENUITEM VdmMainMenuItems[] =
{
- char buffer[512];
- va_list ap;
+ { -1, NULL, 0 }, /* Separator */
+ { IDS_HIDE_MOUSE, NULL, ID_SHOWHIDE_MOUSE }, /* Hide mouse; can be renamed to Show mouse */
+ { IDS_VDM_MENU , VdmMenuItems, 0 }, /* ReactOS VDM Menu */
- va_start(ap, fmt);
- vsprintf(buffer, fmt, ap);
- va_end(ap);
+ { 0, NULL, 0 } /* End of list */
+};
- OutputDebugStringA(buffer);
+static VOID
+AppendMenuItems(HMENU hMenu,
+ const VDM_MENUITEM *Items)
+{
+ UINT i = 0;
+ WCHAR szMenuString[255];
+ HMENU hSubMenu;
+
+ do
+ {
+ if (Items[i].uID != (UINT)-1)
+ {
+ if (LoadStringW(GetModuleHandle(NULL),
+ Items[i].uID,
+ szMenuString,
+ sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+ {
+ if (Items[i].SubMenu != NULL)
+ {
+ hSubMenu = CreatePopupMenu();
+ if (hSubMenu != NULL)
+ {
+ AppendMenuItems(hSubMenu, Items[i].SubMenu);
+
+ if (!AppendMenuW(hMenu,
+ MF_STRING | MF_POPUP,
+ (UINT_PTR)hSubMenu,
+ szMenuString))
+ {
+ DestroyMenu(hSubMenu);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_STRING,
+ Items[i].wCmdID,
+ szMenuString);
+ }
+ }
+ }
+ else
+ {
+ AppendMenuW(hMenu,
+ MF_SEPARATOR,
+ 0,
+ NULL);
+ }
+ i++;
+ } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
}
-/*
-GetVersion
-GetVolumeInformationW
-GetWindowsDirectoryA
-GlobalMemoryStatus
-HeapAlloc
-HeapCreate
-HeapDestroy
-HeapFree
-HeapReAlloc
-
-GetNextVDMCommand
-ExitVDM
-RegisterConsoleVDM
-SetVDMCurrentDirectories
-VDMConsoleOperation
-WriteConsoleInputVDMW
-
-NtSetLdtEntries
-NtTerminateProcess
-
-NtMapViewOfSection
-NtUnmapViewOfSection
-
-NtVdmControl
- */
-typedef struct tag_VDM_CONFIG {
- int dos_options;
- int files;
- int buffers;
- WCHAR** device_list;
-//dos=high, umb
-//device=%SystemRoot%\system32\himem.sys
-//files=40
-} VDM_CONFIG, *PVDM_CONFIG;
-
-typedef struct tag_VDM_AUTOEXEC {
- WCHAR** load_list;
-//lh %SystemRoot%\system32\mscdexnt.exe
-//lh %SystemRoot%\system32\redir
-//lh %SystemRoot%\system32\dosx
-} VDM_AUTOEXEC, *PVDM_AUTOEXEC;
-
-typedef struct tag_VDM_CONTROL_BLOCK {
- HANDLE hHeap;
- PVOID ImageMem;
- VDM_CONFIG vdmConfig;
- VDM_AUTOEXEC vdmAutoexec;
- PROCESS_INFORMATION ProcessInformation;
- CHAR CommandLine[MAX_PATH];
- CHAR CurrentDirectory[MAX_PATH];
-
-} VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
-
-
-BOOL
-StartVDM(PVDM_CONTROL_BLOCK vdm)
+static VOID
+CreateVdmMenu(HANDLE ConOutHandle)
{
- BOOL Result;
- STARTUPINFOA StartupInfo;
-
- StartupInfo.cb = sizeof(StartupInfo);
- StartupInfo.lpReserved = NULL;
- StartupInfo.lpDesktop = NULL;
- StartupInfo.lpTitle = NULL;
- StartupInfo.dwFlags = 0;
- StartupInfo.cbReserved2 = 0;
- StartupInfo.lpReserved2 = 0;
-
- Result = CreateProcessA(vdm->CommandLine,
- NULL,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS,
- NULL,
- NULL,
- &StartupInfo,
- &vdm->ProcessInformation);
- if (!Result) {
- PrintString("VDM: Failed to execute target process\n");
- return FALSE;
- }
- WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
- CloseHandle(vdm->ProcessInformation.hProcess);
- CloseHandle(vdm->ProcessInformation.hThread);
- return TRUE;
+ hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
+ ID_SHOWHIDE_MOUSE,
+ ID_VDM_QUIT);
+ if (hConsoleMenu == NULL) return;
+
+ VdmMenuPos = GetMenuItemCount(hConsoleMenu);
+ AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
+ DrawMenuBar(GetConsoleWindow());
}
-BOOL
-ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
+static VOID
+DestroyVdmMenu(VOID)
{
- BOOL result = TRUE;
+ UINT i = 0;
+ const VDM_MENUITEM *Items = VdmMainMenuItems;
+
+ do
+ {
+ DeleteMenu(hConsoleMenu, VdmMenuPos, MF_BYPOSITION);
+ i++;
+ } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
- return result;
+ DrawMenuBar(GetConsoleWindow());
}
-BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
+static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
{
- BOOL result = TRUE;
- DWORD dwError;
- HANDLE hFile;
-
- hFile = CreateFileW(L"\\system32\\config.nt",
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS /*OPEN_EXISTING*/,
- FILE_ATTRIBUTE_NORMAL,
- 0);
- dwError = GetLastError();
- if (hFile == INVALID_HANDLE_VALUE) {
- // error with file path or system problem?
- } else {
- if (dwError == 0L) {
- // we just created a new file, perhaps we should set/write some defaults?
- }
- if (dwError == ERROR_ALREADY_EXISTS) {
- // read the line entries and cache in some struct...
- }
- CloseHandle(hFile);
+ WCHAR szMenuString[255] = L"";
+
+ if (ShowPtr)
+ {
+ /* Be sure the cursor will be shown */
+ while (ShowConsoleCursor(ConOutHandle, TRUE) < 0) ;
}
+ else
+ {
+ /* Be sure the cursor will be hidden */
+ while (ShowConsoleCursor(ConOutHandle, FALSE) >= 0) ;
+ }
+
+ if (LoadStringW(GetModuleHandle(NULL),
+ (!ShowPtr ? IDS_SHOW_MOUSE : IDS_HIDE_MOUSE),
+ szMenuString,
+ sizeof(szMenuString) / sizeof(szMenuString[0])) > 0)
+ {
+ ModifyMenu(hConsoleMenu, ID_SHOWHIDE_MOUSE,
+ MF_BYCOMMAND, ID_SHOWHIDE_MOUSE, szMenuString);
+ }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+VOID DisplayMessage(LPCWSTR Format, ...)
+{
+ WCHAR Buffer[256];
+ va_list Parameters;
+
+ va_start(Parameters, Format);
+ _vsnwprintf(Buffer, 256, Format, Parameters);
+ DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
+ MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
+ va_end(Parameters);
+}
- hFile = CreateFileW(L"\\system32\\autoexec.nt",
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- 0);
- dwError = GetLastError();
- if (hFile == INVALID_HANDLE_VALUE) {
- // error with file path or system problem?
- } else {
- if (dwError == 0L) {
- // we just created a new file, perhaps we should set/write some defaults?
+BOOL WINAPI ConsoleCtrlHandler(DWORD ControlType)
+{
+ switch (ControlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ {
+ /* Call INT 23h */
+ EmulatorInterrupt(0x23);
+ break;
}
- if (dwError == ERROR_ALREADY_EXISTS) {
- // read the line entries and cache in some struct...
+ case CTRL_LAST_CLOSE_EVENT:
+ {
+ if (CommandThread) TerminateThread(CommandThread, 0);
+ break;
+ }
+ default:
+ {
+ /* Stop the VDM if the user logs out or closes the console */
+ EmulatorTerminate();
}
- CloseHandle(hFile);
}
+ return TRUE;
+}
- return result;
+VOID ConsoleInitUI(VOID)
+{
+ CreateVdmMenu(ConsoleOutput);
}
-BOOL
-LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
+VOID ConsoleCleanupUI(VOID)
{
- BOOL result = TRUE;
+ /* Display again properly the mouse pointer */
+ if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
- return result;
+ DestroyVdmMenu();
}
-BOOL
-SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
+DWORD WINAPI PumpConsoleInput(LPVOID Parameter)
{
- BOOL result = TRUE;
+ HANDLE ConsoleInput = (HANDLE)Parameter;
+ INPUT_RECORD InputRecord;
+ DWORD Count;
+
+ while (VdmRunning)
+ {
+ /* Wait for an input record */
+ if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
+ {
+ DWORD LastError = GetLastError();
+ DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, Count, LastError);
+ return LastError;
+ }
+
+ ASSERT(Count != 0);
+
+ /* Check the event type */
+ switch (InputRecord.EventType)
+ {
+ case KEY_EVENT:
+ case MOUSE_EVENT:
+ /* Send it to the PS/2 controller */
+ PS2Dispatch(&InputRecord);
+ break;
- return result;
+ case MENU_EVENT:
+ {
+ switch (InputRecord.Event.MenuEvent.dwCommandId)
+ {
+ case ID_SHOWHIDE_MOUSE:
+ ShowHideMousePointer(ConsoleOutput, ShowPointer);
+ ShowPointer = !ShowPointer;
+ break;
+
+ case ID_VDM_QUIT:
+ /* Stop the VDM */
+ EmulatorTerminate();
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
}
-BOOL
-CreateVDM(PVDM_CONTROL_BLOCK vdm)
+BOOL ConsoleInit(VOID)
{
-// BOOL result = TRUE;
- SYSTEM_INFO inf;
- MEMORYSTATUS stat;
-
-
- GlobalMemoryStatus(&stat);
- if (stat.dwLength != sizeof(MEMORYSTATUS)) {
- printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
- } else {
- printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
- printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
- printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
- printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
- printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
- printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
- printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
-
-#define OUT_OF_HEADROOM 90
- if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
- DPRINT("VDM: system resources deemed to low to start VDM.\n");
- //SetLastError();
- return FALSE;
- }
+ /* 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;
}
- GetSystemInfo(&inf);
- vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
- if (vdm->hHeap == NULL) {
- DPRINT("VDM: failed to create heap.\n");
+ /* 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;
}
-#define DEFAULT_VDM_IMAGE_SIZE 2000000
- vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
- if (vdm->ImageMem == NULL) {
- DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
- HeapDestroy(vdm->hHeap);
- vdm->hHeap = NULL;
+ /* Save the original cursor and console screen buffer information */
+ if (!GetConsoleCursorInfo(ConsoleOutput, &OrgConsoleCursorInfo) ||
+ !GetConsoleScreenBufferInfo(ConsoleOutput, &OrgConsoleBufferInfo))
+ {
+ CloseHandle(ConsoleOutput);
+ CloseHandle(ConsoleInput);
+ wprintf(L"FATAL: Cannot save console cursor/screen-buffer info\n");
return FALSE;
}
+
+ /* Initialize the UI */
+ ConsoleInitUI();
+
return TRUE;
}
-BOOL
-DestroyVDM(PVDM_CONTROL_BLOCK vdm)
+VOID ConsoleCleanup(VOID)
{
- BOOL result = TRUE;
+ SMALL_RECT ConRect;
+
+ /* Restore the old screen buffer */
+ SetConsoleActiveScreenBuffer(ConsoleOutput);
+
+ /* Restore the original console size */
+ ConRect.Left = 0;
+ ConRect.Top = 0;
+ ConRect.Right = ConRect.Left + OrgConsoleBufferInfo.srWindow.Right - OrgConsoleBufferInfo.srWindow.Left;
+ ConRect.Bottom = ConRect.Top + OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top ;
+ /*
+ * See the following trick explanation in vga.c:VgaEnterTextMode() .
+ */
+ SetConsoleScreenBufferSize(ConsoleOutput, OrgConsoleBufferInfo.dwSize);
+ SetConsoleWindowInfo(ConsoleOutput, TRUE, &ConRect);
+ SetConsoleScreenBufferSize(ConsoleOutput, OrgConsoleBufferInfo.dwSize);
+
+ /* Restore the original cursor shape */
+ SetConsoleCursorInfo(ConsoleOutput, &OrgConsoleCursorInfo);
+
+ /* 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);
+}
- if (vdm->ImageMem != NULL) {
- if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
- DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
- result = FALSE;
- }
- vdm->ImageMem = NULL;
- }
- if (vdm->hHeap != NULL) {
- if (!HeapDestroy(vdm->hHeap)) {
- DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
- result = FALSE;
+DWORD WINAPI CommandThreadProc(LPVOID Parameter)
+{
+ VDM_COMMAND_INFO CommandInfo;
+ CHAR CmdLine[MAX_PATH];
+ CHAR AppName[MAX_PATH];
+ CHAR PifFile[MAX_PATH];
+ CHAR Desktop[MAX_PATH];
+ CHAR Title[MAX_PATH];
+ CHAR Env[MAX_PATH];
+
+ UNREFERENCED_PARAMETER(Parameter);
+
+ while (TRUE)
+ {
+ /* Clear the structure */
+ ZeroMemory(&CommandInfo, sizeof(CommandInfo));
+
+ /* Initialize the structure members */
+ CommandInfo.VDMState = VDM_NOT_LOADED;
+ CommandInfo.CmdLine = CmdLine;
+ CommandInfo.CmdLen = sizeof(CmdLine);
+ CommandInfo.AppName = AppName;
+ CommandInfo.AppLen = sizeof(AppName);
+ CommandInfo.PifFile = PifFile;
+ CommandInfo.PifLen = sizeof(PifFile);
+ CommandInfo.Desktop = Desktop;
+ CommandInfo.DesktopLen = sizeof(Desktop);
+ CommandInfo.Title = Title;
+ CommandInfo.TitleLen = sizeof(Title);
+ CommandInfo.Env = Env;
+ CommandInfo.EnvLen = sizeof(Env);
+
+ /* Wait for the next available VDM */
+ if (!GetNextVDMCommand(&CommandInfo)) break;
+
+ /* Start the process from the command line */
+ DPRINT1("Starting '%s'...\n", AppName);
+ if (DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ AppName,
+ CmdLine,
+ Env,
+ NULL,
+ NULL) != ERROR_SUCCESS)
+ {
+ DisplayMessage(L"Could not start '%S'", AppName);
+ break;
}
- vdm->hHeap = NULL;
+
+ /* Start simulation */
+ EmulatorSimulate();
+
+ /* Perform another screen refresh */
+ VgaRefreshDisplay();
}
- return result;
+
+ return 0;
}
-int WINAPI
-WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+INT wmain(INT argc, WCHAR *argv[])
{
- VDM_CONTROL_BLOCK VdmCB;
- DWORD Result;
- ULONG i;
- BOOL vdmStarted = FALSE;
+#ifdef STANDALONE
+ CHAR ApplicationName[MAX_PATH];
+ CHAR CommandLine[DOS_CMDLINE_LENGTH];
- WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
- WCHAR PromptMsg[RC_STRING_MAX_SIZE];
- CHAR InputBuffer[255];
+ if (argc >= 2)
+ {
+ WideCharToMultiByte(CP_ACP, 0, argv[1], -1, ApplicationName, sizeof(ApplicationName), NULL, NULL);
- LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
- LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
+ if (argc >= 3) WideCharToMultiByte(CP_ACP, 0, argv[2], -1, CommandLine, sizeof(CommandLine), NULL, NULL);
+ else strcpy(CommandLine, "");
+ }
+ else
+ {
+ wprintf(L"\nReactOS Virtual DOS Machine\n\n"
+ L"Usage: NTVDM <executable> [<parameters>]\n");
+ return 0;
+ }
- AllocConsole();
- SetConsoleTitleW(L"ntvdm");
+#endif
- WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
- WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg),
- &Result, NULL);
+ DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
- if (!CreateVDM(&VdmCB)) {
- DPRINT("VDM: failed to create VDM.\n");
- //SetLastError();
- return 2;
+ /* Initialize the console */
+ if (!ConsoleInit())
+ {
+ wprintf(L"FATAL: A problem occurred when trying to initialize the console\n");
+ goto Cleanup;
}
- ReadConfigForVDM(&VdmCB);
-
- if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
- DPRINT("VDM: failed to load configuration drivers.\n");
- //SetLastError();
- return 2;
+ /* Initialize the emulator */
+ if (!EmulatorInitialize(ConsoleInput, ConsoleOutput))
+ {
+ wprintf(L"FATAL: Failed to initialize the emulator\n");
+ goto Cleanup;
}
- if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
- DPRINT("VDM: failed to set configuration options.\n");
- //SetLastError();
- return 3;
+
+ /* Initialize the system BIOS */
+ if (!BiosInitialize(NULL))
+ {
+ wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
+ goto Cleanup;
}
- GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
- strcat(VdmCB.CommandLine, "\\hello.exe");
- GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
-
- for (;;) {
- WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
- PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg),
- &Result, NULL);
- i = 0;
- do {
- ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
- &InputBuffer[i], 1,
- &Result, NULL);
- if (++i >= (sizeof(InputBuffer) - 1)) {
- break;
- }
- } while (InputBuffer[i - 1] != '\n');
- InputBuffer[i - 1] = '\0';
-
- if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
- if (!vdmStarted) {
- if (StartVDM(&VdmCB)) {
- vdmStarted = TRUE;
- } else {
- DPRINT("VDM: failed to start.\n");
- }
- } else {
- DPRINT("VDM: already started.\n");
- }
- }
- if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
- if (vdmStarted) {
- if (ShutdownVDM(&VdmCB)) {
- vdmStarted = FALSE;
- } else {
- DPRINT("VDM: failed to shutdown.\n");
- }
- } else {
- DPRINT("VDM: not started.\n");
- }
- }
- if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
- break;
- }
+ /* Initialize the VDM DOS kernel */
+ if (!DosInitialize(NULL))
+ {
+ wprintf(L"FATAL: Failed to initialize the VDM DOS kernel.\n");
+ goto Cleanup;
}
- if (!ShutdownVDM(&VdmCB)) {
- DPRINT("VDM: failed to cleanly shutdown VDM.\n");
- //SetLastError();
- return 5;
+#ifndef STANDALONE
+
+ /* Create the GetNextVDMCommand thread */
+ CommandThread = CreateThread(NULL, 0, &CommandThreadProc, NULL, 0, NULL);
+ if (CommandThread == NULL)
+ {
+ wprintf(L"FATAL: Failed to create the command processing thread: %d\n", GetLastError());
+ goto Cleanup;
}
- if (!DestroyVDM(&VdmCB)) {
- DPRINT("VDM: failed to cleanly destroy VDM.\n");
- //SetLastError();
- return 6;
+ /* Wait for the command thread to exit */
+ WaitForSingleObject(CommandThread, INFINITE);
+
+ /* Close the thread handle */
+ CloseHandle(CommandThread);
+
+#else
+
+ /* Start the process from the command line */
+ DPRINT1("Starting '%s'...\n", CommandLine);
+ if (DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ ApplicationName,
+ CommandLine,
+ GetEnvironmentStrings(),
+ NULL,
+ NULL) != ERROR_SUCCESS)
+ {
+ DisplayMessage(L"Could not start '%S'", ApplicationName);
+ goto Cleanup;
}
- ExitProcess(0);
+ /* Start simulation */
+ EmulatorSimulate();
+
+ /* Perform another screen refresh */
+ VgaRefreshDisplay();
+
+#endif
+
+Cleanup:
+ BiosCleanup();
+ EmulatorCleanup();
+ ConsoleCleanup();
+
+#ifndef STANDALONE
+ ExitVDM(FALSE, 0);
+#endif
+
+ /* Quit the VDM */
+ DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");
+
return 0;
}
+
+/* EOF */