2013-03-14 21:04:13 +00:00
|
|
|
/*
|
2013-06-17 00:00:36 +00:00
|
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS Virtual DOS Machine
|
|
|
|
* FILE: ntvdm.c
|
2002-10-28 13:59:59 +00:00
|
|
|
* PURPOSE: Virtual DOS Machine
|
2013-06-17 00:00:36 +00:00
|
|
|
* PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
|
2002-10-28 13:59:59 +00:00
|
|
|
*/
|
|
|
|
|
2013-06-26 22:58:41 +00:00
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
|
2013-07-22 13:51:26 +00:00
|
|
|
#define NDEBUG
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
#include "ntvdm.h"
|
2013-06-26 22:58:41 +00:00
|
|
|
#include "emulator.h"
|
2014-01-11 15:27:18 +00:00
|
|
|
|
2014-02-01 16:32:20 +00:00
|
|
|
#include "bios/bios.h"
|
2015-04-19 00:01:03 +00:00
|
|
|
#include "cpu/cpu.h"
|
2014-02-01 16:32:20 +00:00
|
|
|
|
|
|
|
#include "resource.h"
|
2013-06-26 22:58:41 +00:00
|
|
|
|
2014-02-01 16:32:20 +00:00
|
|
|
/* VARIABLES ******************************************************************/
|
2013-01-24 23:00:42 +00:00
|
|
|
|
2014-01-11 20:59:27 +00:00
|
|
|
static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
|
|
|
|
static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
|
|
|
|
static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
|
2014-02-01 16:32:20 +00:00
|
|
|
|
2014-05-02 18:24:40 +00:00
|
|
|
HANDLE VdmTaskEvent = NULL;
|
|
|
|
|
2014-10-04 13:36:17 +00:00
|
|
|
// Command line of NTVDM
|
|
|
|
INT NtVdmArgc;
|
|
|
|
WCHAR** NtVdmArgv;
|
|
|
|
|
|
|
|
|
|
|
|
static HMENU hConsoleMenu = NULL;
|
|
|
|
static INT VdmMenuPos = -1;
|
|
|
|
static BOOLEAN ShowPointer = FALSE;
|
|
|
|
|
2014-02-01 16:32:20 +00:00
|
|
|
/*
|
|
|
|
* 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[] =
|
|
|
|
{
|
2014-09-28 16:27:30 +00:00
|
|
|
{ IDS_VDM_DUMPMEM_TXT, NULL, ID_VDM_DUMPMEM_TXT },
|
|
|
|
{ IDS_VDM_DUMPMEM_BIN, NULL, ID_VDM_DUMPMEM_BIN },
|
|
|
|
{ IDS_VDM_QUIT , NULL, ID_VDM_QUIT },
|
2014-02-01 16:32:20 +00:00
|
|
|
|
|
|
|
{ 0, NULL, 0 } /* End of list */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const VDM_MENUITEM VdmMainMenuItems[] =
|
|
|
|
{
|
|
|
|
{ -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 */
|
|
|
|
|
|
|
|
{ 0, NULL, 0 } /* End of list */
|
|
|
|
};
|
|
|
|
|
|
|
|
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,
|
2015-04-19 00:01:03 +00:00
|
|
|
ARRAYSIZE(szMenuString)) > 0)
|
2014-02-01 16:32:20 +00:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:51:18 +00:00
|
|
|
BOOL
|
|
|
|
VdmMenuExists(HMENU hConsoleMenu)
|
|
|
|
{
|
|
|
|
INT MenuPos, i;
|
|
|
|
MenuPos = GetMenuItemCount(hConsoleMenu);
|
|
|
|
|
|
|
|
/* Check for the presence of one of the VDM menu items */
|
|
|
|
for (i = 0; i <= MenuPos; i++)
|
|
|
|
{
|
|
|
|
if (GetMenuItemID(hConsoleMenu, i) == ID_SHOWHIDE_MOUSE)
|
2015-05-30 16:05:10 +00:00
|
|
|
{
|
2015-07-13 01:21:46 +00:00
|
|
|
/* Set VdmMenuPos to the position of the existing menu */
|
2015-05-30 16:05:10 +00:00
|
|
|
VdmMenuPos = i - 1;
|
2015-05-30 15:51:18 +00:00
|
|
|
return TRUE;
|
2015-05-30 16:05:10 +00:00
|
|
|
}
|
2015-05-30 15:51:18 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-09-14 00:43:43 +00:00
|
|
|
/*static*/ VOID
|
2014-02-01 16:32:20 +00:00
|
|
|
CreateVdmMenu(HANDLE ConOutHandle)
|
|
|
|
{
|
2014-05-11 19:25:09 +00:00
|
|
|
hConsoleMenu = ConsoleMenuControl(ConOutHandle,
|
2014-02-01 16:32:20 +00:00
|
|
|
ID_SHOWHIDE_MOUSE,
|
|
|
|
ID_VDM_QUIT);
|
2014-03-02 14:37:51 +00:00
|
|
|
if (hConsoleMenu == NULL) return;
|
|
|
|
|
2015-05-30 15:51:18 +00:00
|
|
|
/* Get the position where we are going to insert our menu items */
|
2014-03-02 14:37:51 +00:00
|
|
|
VdmMenuPos = GetMenuItemCount(hConsoleMenu);
|
2015-05-30 15:51:18 +00:00
|
|
|
|
|
|
|
/* Really add the menu if it doesn't already exist (in case eg. NTVDM crashed) */
|
|
|
|
if (!VdmMenuExists(hConsoleMenu))
|
|
|
|
{
|
|
|
|
AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
|
|
|
|
DrawMenuBar(GetConsoleWindow());
|
|
|
|
}
|
2014-02-01 16:32:20 +00:00
|
|
|
}
|
|
|
|
|
2014-09-14 00:43:43 +00:00
|
|
|
/*static*/ VOID
|
2014-02-01 16:32:20 +00:00
|
|
|
DestroyVdmMenu(VOID)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
|
|
|
|
DrawMenuBar(GetConsoleWindow());
|
|
|
|
}
|
|
|
|
|
|
|
|
static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
|
|
|
|
{
|
|
|
|
WCHAR szMenuString[255] = L"";
|
|
|
|
|
2014-03-02 01:45:57 +00:00
|
|
|
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) ;
|
|
|
|
}
|
2014-02-01 16:32:20 +00:00
|
|
|
|
|
|
|
if (LoadStringW(GetModuleHandle(NULL),
|
|
|
|
(!ShowPtr ? IDS_SHOW_MOUSE : IDS_HIDE_MOUSE),
|
|
|
|
szMenuString,
|
2015-04-19 00:01:03 +00:00
|
|
|
ARRAYSIZE(szMenuString)) > 0)
|
2014-02-01 16:32:20 +00:00
|
|
|
{
|
|
|
|
ModifyMenu(hConsoleMenu, ID_SHOWHIDE_MOUSE,
|
|
|
|
MF_BYCOMMAND, ID_SHOWHIDE_MOUSE, szMenuString);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-31 21:28:40 +00:00
|
|
|
static VOID EnableExtraHardware(HANDLE ConsoleInput)
|
|
|
|
{
|
|
|
|
DWORD ConInMode;
|
|
|
|
|
|
|
|
if (GetConsoleMode(ConsoleInput, &ConInMode))
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
// GetNumberOfConsoleMouseButtons();
|
|
|
|
// GetSystemMetrics(SM_CMOUSEBUTTONS);
|
|
|
|
// GetSystemMetrics(SM_MOUSEPRESENT);
|
|
|
|
if (MousePresent)
|
|
|
|
{
|
|
|
|
#endif
|
|
|
|
/* Support mouse input events if there is a mouse on the system */
|
|
|
|
ConInMode |= ENABLE_MOUSE_INPUT;
|
|
|
|
#if 0
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Do not support mouse input events if there is no mouse on the system */
|
|
|
|
ConInMode &= ~ENABLE_MOUSE_INPUT;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SetConsoleMode(ConsoleInput, ConInMode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-26 22:58:41 +00:00
|
|
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
|
|
|
|
2014-05-11 19:25:09 +00:00
|
|
|
VOID
|
2015-07-13 01:21:46 +00:00
|
|
|
DisplayMessage(IN LPCWSTR Format, ...)
|
2003-01-12 01:54:40 +00:00
|
|
|
{
|
2014-11-09 01:46:31 +00:00
|
|
|
#ifndef WIN2K_COMPLIANT
|
|
|
|
WCHAR StaticBuffer[256];
|
|
|
|
LPWSTR Buffer = StaticBuffer; // Use the static buffer by default.
|
|
|
|
#else
|
|
|
|
WCHAR Buffer[2048]; // Large enough. If not, increase it by hand.
|
|
|
|
#endif
|
|
|
|
size_t MsgLen;
|
2013-06-17 00:00:36 +00:00
|
|
|
va_list Parameters;
|
2003-01-12 01:54:40 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
va_start(Parameters, Format);
|
2014-11-09 01:46:31 +00:00
|
|
|
|
|
|
|
#ifndef WIN2K_COMPLIANT
|
|
|
|
/*
|
|
|
|
* Retrieve the message length and if it is too long, allocate
|
|
|
|
* an auxiliary buffer; otherwise use the static buffer.
|
2015-07-13 01:21:46 +00:00
|
|
|
* The string is built to be NULL-terminated.
|
2014-11-09 01:46:31 +00:00
|
|
|
*/
|
2015-07-13 01:21:46 +00:00
|
|
|
MsgLen = _vscwprintf(Format, Parameters);
|
|
|
|
if (MsgLen >= ARRAYSIZE(StaticBuffer))
|
2014-11-09 01:46:31 +00:00
|
|
|
{
|
2015-07-13 01:21:46 +00:00
|
|
|
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(WCHAR));
|
2014-11-09 01:46:31 +00:00
|
|
|
if (Buffer == NULL)
|
|
|
|
{
|
|
|
|
/* Allocation failed, use the static buffer and display a suitable error message */
|
|
|
|
Buffer = StaticBuffer;
|
|
|
|
Format = L"DisplayMessage()\nOriginal message is too long and allocating an auxiliary buffer failed.";
|
|
|
|
MsgLen = wcslen(Format);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2015-07-13 01:21:46 +00:00
|
|
|
MsgLen = ARRAYSIZE(Buffer) - 1;
|
2014-11-09 01:46:31 +00:00
|
|
|
#endif
|
|
|
|
|
2015-07-13 01:21:46 +00:00
|
|
|
RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
|
2014-11-09 01:46:31 +00:00
|
|
|
_vsnwprintf(Buffer, MsgLen, Format, Parameters);
|
2015-07-13 01:21:46 +00:00
|
|
|
|
|
|
|
va_end(Parameters);
|
|
|
|
|
|
|
|
/* Display the message */
|
2013-11-09 15:53:52 +00:00
|
|
|
DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
|
2013-08-06 20:01:05 +00:00
|
|
|
MessageBoxW(NULL, Buffer, L"NTVDM Subsystem", MB_OK);
|
2014-11-09 01:46:31 +00:00
|
|
|
|
|
|
|
#ifndef WIN2K_COMPLIANT
|
|
|
|
/* Free the buffer if needed */
|
2015-04-19 00:01:03 +00:00
|
|
|
if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
|
2014-11-09 01:46:31 +00:00
|
|
|
#endif
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
|
|
|
|
2014-05-11 19:25:09 +00:00
|
|
|
static BOOL
|
|
|
|
WINAPI
|
|
|
|
ConsoleCtrlHandler(DWORD ControlType)
|
2003-01-12 01:54:40 +00:00
|
|
|
{
|
2015-05-07 01:23:33 +00:00
|
|
|
// HACK: Should be removed!
|
|
|
|
#ifndef STANDALONE
|
|
|
|
extern BOOLEAN AcceptCommands;
|
|
|
|
extern HANDLE CommandThread;
|
|
|
|
#endif
|
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
switch (ControlType)
|
|
|
|
{
|
2014-04-22 20:46:50 +00:00
|
|
|
case CTRL_LAST_CLOSE_EVENT:
|
|
|
|
{
|
2014-05-02 18:24:40 +00:00
|
|
|
if (WaitForSingleObject(VdmTaskEvent, 0) == WAIT_TIMEOUT)
|
2014-04-27 22:38:54 +00:00
|
|
|
{
|
2015-05-07 01:23:33 +00:00
|
|
|
/* Nothing runs, so exit immediately */
|
2014-10-04 13:36:17 +00:00
|
|
|
#ifndef STANDALONE
|
2014-04-27 22:38:54 +00:00
|
|
|
if (CommandThread) TerminateThread(CommandThread, 0);
|
2014-10-04 13:36:17 +00:00
|
|
|
#endif
|
2014-05-02 18:24:40 +00:00
|
|
|
EmulatorTerminate();
|
2014-04-27 22:38:54 +00:00
|
|
|
}
|
2014-10-04 13:36:17 +00:00
|
|
|
#ifndef STANDALONE
|
2014-04-27 22:38:54 +00:00
|
|
|
else
|
|
|
|
{
|
2015-05-07 01:23:33 +00:00
|
|
|
/* A command is running, let it run, but stop accepting new commands */
|
2014-04-27 22:38:54 +00:00
|
|
|
AcceptCommands = FALSE;
|
|
|
|
}
|
2014-10-04 13:36:17 +00:00
|
|
|
#endif
|
2014-04-27 22:38:54 +00:00
|
|
|
|
2014-04-22 20:46:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-03-31 21:28:40 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
/* Stop the VDM if the user logs out or closes the console */
|
2014-03-02 14:37:51 +00:00
|
|
|
EmulatorTerminate();
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
2002-10-28 13:59:59 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-05-11 19:25:09 +00:00
|
|
|
static VOID
|
|
|
|
ConsoleInitUI(VOID)
|
2014-02-01 16:32:20 +00:00
|
|
|
{
|
|
|
|
CreateVdmMenu(ConsoleOutput);
|
|
|
|
}
|
|
|
|
|
2014-05-11 19:25:09 +00:00
|
|
|
static VOID
|
|
|
|
ConsoleCleanupUI(VOID)
|
2014-02-01 16:32:20 +00:00
|
|
|
{
|
|
|
|
/* Display again properly the mouse pointer */
|
|
|
|
if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
|
|
|
|
|
|
|
DestroyVdmMenu();
|
|
|
|
}
|
|
|
|
|
2015-03-31 21:28:40 +00:00
|
|
|
BOOL
|
2014-05-11 19:25:09 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-03-31 21:28:40 +00:00
|
|
|
/* Set the console input mode */
|
|
|
|
// FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions
|
|
|
|
// upon console window events (screen buffer resize, ...).
|
|
|
|
SetConsoleMode(ConsoleInput, 0 /* | ENABLE_WINDOW_INPUT */);
|
|
|
|
EnableExtraHardware(ConsoleInput);
|
|
|
|
|
|
|
|
/* Set the console output mode */
|
|
|
|
// SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
|
|
|
|
|
2014-05-11 19:25:09 +00:00
|
|
|
/* Initialize the UI */
|
|
|
|
ConsoleInitUI();
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2015-03-31 21:28:40 +00:00
|
|
|
VOID
|
2014-05-11 19:25:09 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-09-16 00:51:15 +00:00
|
|
|
VOID MenuEventHandler(PMENU_EVENT_RECORD MenuEvent)
|
2014-02-01 16:32:20 +00:00
|
|
|
{
|
2014-09-16 00:51:15 +00:00
|
|
|
switch (MenuEvent->dwCommandId)
|
2014-02-01 16:32:20 +00:00
|
|
|
{
|
2014-09-16 00:51:15 +00:00
|
|
|
case ID_SHOWHIDE_MOUSE:
|
|
|
|
ShowHideMousePointer(ConsoleOutput, ShowPointer);
|
|
|
|
ShowPointer = !ShowPointer;
|
|
|
|
break;
|
2014-02-01 16:32:20 +00:00
|
|
|
|
2014-09-28 16:27:30 +00:00
|
|
|
case ID_VDM_DUMPMEM_TXT:
|
|
|
|
DumpMemory(TRUE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_VDM_DUMPMEM_BIN:
|
|
|
|
DumpMemory(FALSE);
|
2014-09-16 00:51:15 +00:00
|
|
|
break;
|
2014-02-01 16:32:20 +00:00
|
|
|
|
2014-09-16 00:51:15 +00:00
|
|
|
case ID_VDM_QUIT:
|
|
|
|
/* Stop the VDM */
|
|
|
|
EmulatorTerminate();
|
|
|
|
break;
|
2014-02-01 16:32:20 +00:00
|
|
|
|
2014-09-16 00:51:15 +00:00
|
|
|
default:
|
|
|
|
break;
|
2014-02-01 16:32:20 +00:00
|
|
|
}
|
2014-09-16 00:51:15 +00:00
|
|
|
}
|
2014-02-01 16:32:20 +00:00
|
|
|
|
2014-09-16 00:51:15 +00:00
|
|
|
VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent)
|
|
|
|
{
|
|
|
|
DPRINT1("Focus events not handled\n");
|
2014-02-01 16:32:20 +00:00
|
|
|
}
|
|
|
|
|
2015-05-07 01:23:33 +00:00
|
|
|
static BOOL
|
|
|
|
LoadGlobalSettings(VOID)
|
|
|
|
{
|
|
|
|
// FIXME: These strings should be localized.
|
|
|
|
#define ERROR_MEMORYVDD L"Insufficient memory to load installable Virtual Device Drivers."
|
|
|
|
#define ERROR_REGVDD L"Virtual Device Driver format in the registry is invalid."
|
|
|
|
#define ERROR_LOADVDD L"An installable Virtual Device Driver failed Dll initialization."
|
|
|
|
|
|
|
|
BOOL Success = TRUE;
|
|
|
|
LONG Error = 0;
|
|
|
|
|
|
|
|
HKEY hNTVDMKey;
|
|
|
|
LPCWSTR NTVDMKeyName = L"SYSTEM\\CurrentControlSet\\Control\\NTVDM";
|
|
|
|
|
|
|
|
/* Try to open the NTVDM registry key */
|
|
|
|
Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
|
|
NTVDMKeyName,
|
|
|
|
0,
|
|
|
|
KEY_QUERY_VALUE,
|
|
|
|
&hNTVDMKey);
|
|
|
|
if (Error == ERROR_FILE_NOT_FOUND)
|
|
|
|
{
|
|
|
|
/* If the key just doesn't exist, don't do anything else */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (Error != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
/* The key exists but there was an access error: display an error and quit */
|
|
|
|
DisplayMessage(ERROR_REGVDD);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we can do:
|
|
|
|
* - CPU core choice
|
|
|
|
* - Video choice
|
|
|
|
* - Sound choice
|
|
|
|
* - Mem?
|
|
|
|
* - ...
|
|
|
|
* - Standalone mode?
|
|
|
|
* - Debug settings
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Quit:
|
|
|
|
RegCloseKey(hNTVDMKey);
|
|
|
|
return Success;
|
|
|
|
}
|
|
|
|
|
2014-05-11 19:25:09 +00:00
|
|
|
INT
|
|
|
|
wmain(INT argc, WCHAR *argv[])
|
2014-04-22 20:46:50 +00:00
|
|
|
{
|
2015-05-07 01:23:33 +00:00
|
|
|
NtVdmArgc = argc;
|
|
|
|
NtVdmArgv = argv;
|
|
|
|
|
2014-04-22 20:46:50 +00:00
|
|
|
#ifdef STANDALONE
|
2014-04-27 22:38:54 +00:00
|
|
|
|
2014-10-04 13:36:17 +00:00
|
|
|
if (argc < 2)
|
2013-07-18 00:17:04 +00:00
|
|
|
{
|
|
|
|
wprintf(L"\nReactOS Virtual DOS Machine\n\n"
|
2014-04-26 08:57:17 +00:00
|
|
|
L"Usage: NTVDM <executable> [<parameters>]\n");
|
2013-07-18 00:17:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2005-05-08 04:07:56 +00:00
|
|
|
|
2014-04-08 00:28:49 +00:00
|
|
|
#endif
|
|
|
|
|
[NTVDM]
- Add some level of "Advanced debugging" (see ntvdm.h) which one can adjust to enable/disable debugging features inside NTVDM (this can be useful as long as NTVDM is under heavy bugfixing. When it will be more perfect, this stuff will be removed).
- Add the possibility to load option ROMs at a given segment. Currently their list should be specified from inside ntvdm.c (in the BiosInitialize call), but I plan to make it available from a registry option (or via command-line for NTVDM-standalone mode).
- Start to separate the initialization of "static" BIOS data (stuff that lives in ROM space) and initialization of "dynamic" BIOS data (eg. initializing the interrupt vector table, the BIOS data area at segment 40h, ...) so that we may be able to reuse part of our code to be able to more-or-less run external (16-bit) BIOSes, or the Windows NTVDM BIOS that uses BOPs to run some of its stuff in ntvdm in 32-bit (as we do for our 32-bit BIOS, except that *all* of our bios is 32-bit, not just some parts). Also, some file reorganization will be in order there soon...
- Add video BIOS version information in memory so that tools such as Microsoft Diagnostics can correctly recognize our video BIOS (btw, we try to emulate the functionality of Cirrus' CL-GD5434).
- Correctly put video BIOS ROM header (+ checksum) in memory so that it is recognized as such by diagnostics tools.
- During BIOS POST, scan for ROMs starting segment 0xC000 (where video ROMs reside).
- Store statically the BIOS configuration table.
- Fix INT 16h, AH=12h "Get extended shift states" so that it correctly returns the state of right Ctrl and Alt keys.
- Fix bit-setting state; report that our keyboard is 101/102 enhanced keyboard.
- Correctly set the error return values (AH=86h and CF set) when a function of INT 15h is unsupported.
- Implement INT 15h, AH=C9h "Get CPU Type and Mask Revision"; INT 1Ah, AH=02h "Get Real-Time Clock Time" and Ah=04h "Get Real-Time Clock Date" by reading the CMOS.
- Implement CMOS century register support.
svn path=/trunk/; revision=68598
2015-08-04 20:17:05 +00:00
|
|
|
#ifdef ADVANCED_DEBUGGING
|
|
|
|
{
|
|
|
|
INT i = 20;
|
|
|
|
|
|
|
|
printf("Waiting for debugger (10 secs)..");
|
|
|
|
while (i--)
|
|
|
|
{
|
|
|
|
printf(".");
|
|
|
|
if (IsDebuggerPresent())
|
|
|
|
{
|
|
|
|
DbgBreakPoint();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Sleep(500);
|
|
|
|
}
|
|
|
|
printf("Continue\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-05-07 01:23:33 +00:00
|
|
|
/* Load global VDM settings */
|
|
|
|
LoadGlobalSettings();
|
2014-10-04 13:36:17 +00:00
|
|
|
|
2014-04-08 14:57:24 +00:00
|
|
|
DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
|
|
|
|
|
2014-05-02 18:24:40 +00:00
|
|
|
/* Create the task event */
|
|
|
|
VdmTaskEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
ASSERT(VdmTaskEvent != NULL);
|
|
|
|
|
2014-01-11 20:59:27 +00:00
|
|
|
/* Initialize the console */
|
|
|
|
if (!ConsoleInit())
|
|
|
|
{
|
|
|
|
wprintf(L"FATAL: A problem occurred when trying to initialize the console\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2013-11-26 20:20:51 +00:00
|
|
|
/* Initialize the emulator */
|
2014-01-25 00:21:51 +00:00
|
|
|
if (!EmulatorInitialize(ConsoleInput, ConsoleOutput))
|
2013-07-02 21:40:11 +00:00
|
|
|
{
|
2014-01-11 20:59:27 +00:00
|
|
|
wprintf(L"FATAL: Failed to initialize the emulator\n");
|
2013-07-05 00:08:18 +00:00
|
|
|
goto Cleanup;
|
2013-07-02 21:40:11 +00:00
|
|
|
}
|
2013-11-17 20:44:23 +00:00
|
|
|
|
[NTVDM]
- Add some level of "Advanced debugging" (see ntvdm.h) which one can adjust to enable/disable debugging features inside NTVDM (this can be useful as long as NTVDM is under heavy bugfixing. When it will be more perfect, this stuff will be removed).
- Add the possibility to load option ROMs at a given segment. Currently their list should be specified from inside ntvdm.c (in the BiosInitialize call), but I plan to make it available from a registry option (or via command-line for NTVDM-standalone mode).
- Start to separate the initialization of "static" BIOS data (stuff that lives in ROM space) and initialization of "dynamic" BIOS data (eg. initializing the interrupt vector table, the BIOS data area at segment 40h, ...) so that we may be able to reuse part of our code to be able to more-or-less run external (16-bit) BIOSes, or the Windows NTVDM BIOS that uses BOPs to run some of its stuff in ntvdm in 32-bit (as we do for our 32-bit BIOS, except that *all* of our bios is 32-bit, not just some parts). Also, some file reorganization will be in order there soon...
- Add video BIOS version information in memory so that tools such as Microsoft Diagnostics can correctly recognize our video BIOS (btw, we try to emulate the functionality of Cirrus' CL-GD5434).
- Correctly put video BIOS ROM header (+ checksum) in memory so that it is recognized as such by diagnostics tools.
- During BIOS POST, scan for ROMs starting segment 0xC000 (where video ROMs reside).
- Store statically the BIOS configuration table.
- Fix INT 16h, AH=12h "Get extended shift states" so that it correctly returns the state of right Ctrl and Alt keys.
- Fix bit-setting state; report that our keyboard is 101/102 enhanced keyboard.
- Correctly set the error return values (AH=86h and CF set) when a function of INT 15h is unsupported.
- Implement INT 15h, AH=C9h "Get CPU Type and Mask Revision"; INT 1Ah, AH=02h "Get Real-Time Clock Time" and Ah=04h "Get Real-Time Clock Date" by reading the CMOS.
- Implement CMOS century register support.
svn path=/trunk/; revision=68598
2015-08-04 20:17:05 +00:00
|
|
|
/* Initialize the system BIOS and option ROMs */
|
|
|
|
if (!BiosInitialize(NULL, NULL))
|
2013-06-17 00:00:36 +00:00
|
|
|
{
|
|
|
|
wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
|
|
|
|
goto Cleanup;
|
2003-01-12 01:54:40 +00:00
|
|
|
}
|
2002-10-28 13:59:59 +00:00
|
|
|
|
2014-10-04 13:36:17 +00:00
|
|
|
/* Let's go! Start simulation */
|
|
|
|
CpuSimulate();
|
2014-04-08 14:57:24 +00:00
|
|
|
|
2013-06-17 00:00:36 +00:00
|
|
|
Cleanup:
|
2013-07-05 01:31:50 +00:00
|
|
|
BiosCleanup();
|
2013-06-17 00:00:36 +00:00
|
|
|
EmulatorCleanup();
|
2014-01-11 20:59:27 +00:00
|
|
|
ConsoleCleanup();
|
2003-01-12 01:54:40 +00:00
|
|
|
|
2014-04-08 14:57:24 +00:00
|
|
|
#ifndef STANDALONE
|
|
|
|
ExitVDM(FALSE, 0);
|
|
|
|
#endif
|
|
|
|
|
2014-04-08 00:28:49 +00:00
|
|
|
/* Quit the VDM */
|
2013-11-04 00:22:29 +00:00
|
|
|
DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");
|
2015-05-14 21:13:07 +00:00
|
|
|
/* Some VDDs rely on the fact that NTVDM calls ExitProcess on Windows */
|
|
|
|
ExitProcess(0);
|
2002-10-28 13:59:59 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-06-17 00:00:36 +00:00
|
|
|
|
|
|
|
/* EOF */
|