* Activate this line if you want to run NTVDM in standalone mode with:
* ntvdm.exe <program>
*/
-#define STANDALONE
+// #define STANDALONE
/* VARIABLES ******************************************************************/
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 BOOLEAN AcceptCommands = TRUE;
static HANDLE CommandThread = NULL;
static HMENU hConsoleMenu = NULL;
static INT VdmMenuPos = -1;
static BOOLEAN ShowPointer = FALSE;
+ULONG SessionId = 0;
+HANDLE VdmTaskEvent = NULL;
+
/*
* Those menu helpers were taken from the GUI frontend in winsrv.dll
*/
}
case CTRL_LAST_CLOSE_EVENT:
{
- if (CommandThread) TerminateThread(CommandThread, 0);
+ if (WaitForSingleObject(VdmTaskEvent, 0) == WAIT_TIMEOUT)
+ {
+ /* Exit immediately */
+ if (CommandThread) TerminateThread(CommandThread, 0);
+ EmulatorTerminate();
+ }
+ else
+ {
+ /* Stop accepting new commands */
+ AcceptCommands = FALSE;
+ }
+
break;
}
default:
while (VdmRunning)
{
+ /* Make sure the task event is signaled */
+ WaitForSingleObject(VdmTaskEvent, INFINITE);
+
/* Wait for an input record */
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
{
return FALSE;
}
- /* 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();
VOID ConsoleCleanup(VOID)
{
- 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 );
DWORD WINAPI CommandThreadProc(LPVOID Parameter)
{
+ BOOLEAN First = TRUE;
+ DWORD Result;
VDM_COMMAND_INFO CommandInfo;
CHAR CmdLine[MAX_PATH];
CHAR AppName[MAX_PATH];
UNREFERENCED_PARAMETER(Parameter);
- while (TRUE)
+ while (AcceptCommands)
{
/* Clear the structure */
ZeroMemory(&CommandInfo, sizeof(CommandInfo));
/* Initialize the structure members */
- CommandInfo.VDMState = VDM_NOT_LOADED;
+ CommandInfo.TaskId = SessionId;
+ CommandInfo.VDMState = VDM_FLAG_DOS;
CommandInfo.CmdLine = CmdLine;
CommandInfo.CmdLen = sizeof(CmdLine);
CommandInfo.AppName = AppName;
CommandInfo.Env = Env;
CommandInfo.EnvLen = sizeof(Env);
+ if (First) CommandInfo.VDMState |= VDM_FLAG_FIRST_TASK;
+
/* 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)
+
+ Result = DosLoadExecutable(DOS_LOAD_AND_EXECUTE, AppName, CmdLine, Env, NULL, NULL);
+ if (Result != ERROR_SUCCESS)
{
- DisplayMessage(L"Could not start '%S'", AppName);
+ DisplayMessage(L"Could not start '%S'. Error: %u", AppName, Result);
break;
}
+ /* 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;
}
return 0;
INT wmain(INT argc, WCHAR *argv[])
{
#ifdef STANDALONE
+
+ DWORD Result;
CHAR ApplicationName[MAX_PATH];
CHAR CommandLine[DOS_CMDLINE_LENGTH];
return 0;
}
+#else
+ INT i;
+ WCHAR *endptr;
+
+ /* Parse the command line arguments */
+ for (i = 1; i < argc; i++)
+ {
+ if (wcsncmp(argv[i], L"-i", 2) == 0)
+ {
+ /* This is the session ID */
+ SessionId = wcstoul(argv[i] + 2, &endptr, 10);
+ }
+ }
+
#endif
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
+ /* Create the task event */
+ VdmTaskEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ ASSERT(VdmTaskEvent != NULL);
+
/* Initialize the console */
if (!ConsoleInit())
{
#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)
+ 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 '%S'", ApplicationName);
+ DisplayMessage(L"Could not start '%S'. Error: %u", ApplicationName, Result);
goto Cleanup;
}
/* Start simulation */
+ SetEvent(VdmTaskEvent);
EmulatorSimulate();
/* Perform another screen refresh */