#include "resource.h"
/*
- * Activate this line if you want to be able to test NTVDM with:
+ * Activate this line if you want to run NTVDM in standalone mode with:
* ntvdm.exe <program>
*/
-#define TESTING
+// #define STANDALONE
/* VARIABLES ******************************************************************/
static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo;
static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo;
+static BOOLEAN AcceptCommands = TRUE;
+static HANDLE CommandThread = NULL;
static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1;
hConsoleMenu = ConsoleMenuControl(ConsoleOutput,
ID_SHOWHIDE_MOUSE,
ID_VDM_QUIT);
- if (hConsoleMenu != NULL)
- {
- VdmMenuPos = GetMenuItemCount(hConsoleMenu);
- AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
- DrawMenuBar(GetConsoleWindow());
- }
+ if (hConsoleMenu == NULL) return;
+
+ VdmMenuPos = GetMenuItemCount(hConsoleMenu);
+ AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
+ DrawMenuBar(GetConsoleWindow());
}
static VOID
{
WCHAR szMenuString[255] = L"";
- ShowConsoleCursor(ConOutHandle, ShowPtr);
+ 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),
EmulatorInterrupt(0x23);
break;
}
+ case CTRL_LAST_CLOSE_EVENT:
+ {
+ if (!VdmRunning)
+ {
+ /* Exit immediately */
+ if (CommandThread) TerminateThread(CommandThread, 0);
+ }
+ else
+ {
+ /* Stop accepting new commands */
+ AcceptCommands = FALSE;
+ }
+
+ break;
+ }
default:
{
/* Stop the VDM if the user logs out or closes the console */
- VdmRunning = FALSE;
+ EmulatorTerminate();
}
}
return TRUE;
break;
case ID_VDM_QUIT:
- VdmRunning = FALSE;
+ /* Stop the VDM */
+ EmulatorTerminate();
break;
default:
/* 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,
VOID ConsoleCleanup(VOID)
{
SMALL_RECT ConRect;
- CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
/* Restore the old screen buffer */
SetConsoleActiveScreenBuffer(ConsoleOutput);
/* Restore the original console size */
- GetConsoleScreenBufferInfo(ConsoleOutput, &ConsoleInfo);
- ConRect.Left = 0; // OrgConsoleBufferInfo.srWindow.Left;
- // ConRect.Top = ConsoleInfo.dwCursorPosition.Y / (OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top + 1);
- // ConRect.Top *= (OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top + 1);
- ConRect.Top = ConsoleInfo.dwCursorPosition.Y;
+ 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() */
+ /*
+ * See the following trick explanation in vga.c:VgaEnterTextMode() .
+ */
SetConsoleScreenBufferSize(ConsoleOutput, OrgConsoleBufferInfo.dwSize);
SetConsoleWindowInfo(ConsoleOutput, TRUE, &ConRect);
- // SetConsoleWindowInfo(ConsoleOutput, TRUE, &OrgConsoleBufferInfo.srWindow);
SetConsoleScreenBufferSize(ConsoleOutput, OrgConsoleBufferInfo.dwSize);
/* Restore the original cursor shape */
if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
}
+DWORD WINAPI CommandThreadProc(LPVOID Parameter)
+{
+ BOOLEAN First = TRUE;
+ DWORD Result;
+ 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 (AcceptCommands)
+ {
+ /* Clear the structure */
+ ZeroMemory(&CommandInfo, sizeof(CommandInfo));
+
+ /* Initialize the structure members */
+ CommandInfo.VDMState = VDM_FLAG_DOS;
+ 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);
+
+ if (First)
+ {
+ CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
+ First = FALSE;
+ }
+
+ /* Wait for the next available VDM */
+ if (!GetNextVDMCommand(&CommandInfo)) break;
+
+ /* Start the process from the command line */
+ DPRINT1("Starting '%s'...\n", AppName);
+
+ Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
+ if (Result != ERROR_SUCCESS)
+ {
+ DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
+ break;
+ }
+
+ /* Start simulation */
+ EmulatorSimulate();
+
+ /* Perform another screen refresh */
+ VgaRefreshDisplay();
+ }
+
+ return 0;
+}
+
INT wmain(INT argc, WCHAR *argv[])
{
- CHAR CommandLine[DOS_CMDLINE_LENGTH];
+#ifdef STANDALONE
-#ifndef TESTING
- UNREFERENCED_PARAMETER(argc);
- UNREFERENCED_PARAMETER(argv);
+ DWORD Result;
+ CHAR ApplicationName[MAX_PATH];
+ CHAR CommandLine[DOS_CMDLINE_LENGTH];
- /* The DOS command line must be ASCII */
- WideCharToMultiByte(CP_ACP, 0, GetCommandLine(), -1, CommandLine, sizeof(CommandLine), NULL, NULL);
-#else
- if (argc == 2 && argv[1] != NULL)
+ if (argc >= 2)
{
- WideCharToMultiByte(CP_ACP, 0, argv[1], -1, CommandLine, sizeof(CommandLine), NULL, NULL);
+ WideCharToMultiByte(CP_ACP, 0, argv[1], -1, ApplicationName, sizeof(ApplicationName), NULL, NULL);
+
+ 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>\n");
+ L"Usage: NTVDM <executable> [<parameters>]\n");
return 0;
}
+
#endif
- DPRINT1("\n\n\nNTVDM - Starting '%s'...\n\n\n", CommandLine);
+ DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
/* Initialize the console */
if (!ConsoleInit())
}
/* Initialize the system BIOS */
- if (!BiosInitialize(ConsoleInput, ConsoleOutput))
+ if (!BiosInitialize(NULL))
{
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
goto Cleanup;
goto Cleanup;
}
+#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;
+ }
+
+ /* Wait for the command thread to exit */
+ WaitForSingleObject(CommandThread, INFINITE);
+
+ /* Close the thread handle */
+ CloseHandle(CommandThread);
+
+#else
+
/* Start the process from the command line */
- if (!DosCreateProcess(CommandLine, 0))
+ DPRINT1("Starting '%s'...\n", ApplicationName);
+
+ Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE,
+ ApplicationName,
+ CommandLine,
+ GetEnvironmentStrings(),
+ NULL,
+ NULL);
+ if (Result != ERROR_SUCCESS)
{
- DisplayMessage(L"Could not start program: %S", CommandLine);
+ DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
goto Cleanup;
}
- /* Main loop */
- while (VdmRunning) ClockUpdate();
+ /* 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;