2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
18 #include "hardware/ps2.h"
19 #include "hardware/vga.h"
20 #include "bios/bios.h"
25 /* VARIABLES ******************************************************************/
27 static HANDLE ConsoleInput
= INVALID_HANDLE_VALUE
;
28 static HANDLE ConsoleOutput
= INVALID_HANDLE_VALUE
;
29 static DWORD OrgConsoleInputMode
, OrgConsoleOutputMode
;
33 BOOLEAN AcceptCommands
= TRUE
;
34 HANDLE CommandThread
= NULL
;
38 HANDLE VdmTaskEvent
= NULL
;
40 // Command line of NTVDM
45 static HMENU hConsoleMenu
= NULL
;
46 static INT VdmMenuPos
= -1;
47 static BOOLEAN ShowPointer
= FALSE
;
50 * Those menu helpers were taken from the GUI frontend in winsrv.dll
52 typedef struct _VDM_MENUITEM
55 const struct _VDM_MENUITEM
*SubMenu
;
57 } VDM_MENUITEM
, *PVDM_MENUITEM
;
59 static const VDM_MENUITEM VdmMenuItems
[] =
61 { IDS_VDM_DUMPMEM_TXT
, NULL
, ID_VDM_DUMPMEM_TXT
},
62 { IDS_VDM_DUMPMEM_BIN
, NULL
, ID_VDM_DUMPMEM_BIN
},
63 { IDS_VDM_QUIT
, NULL
, ID_VDM_QUIT
},
65 { 0, NULL
, 0 } /* End of list */
68 static const VDM_MENUITEM VdmMainMenuItems
[] =
70 { -1, NULL
, 0 }, /* Separator */
71 { IDS_HIDE_MOUSE
, NULL
, ID_SHOWHIDE_MOUSE
}, /* Hide mouse; can be renamed to Show mouse */
72 { IDS_VDM_MENU
, VdmMenuItems
, 0 }, /* ReactOS VDM Menu */
74 { 0, NULL
, 0 } /* End of list */
78 AppendMenuItems(HMENU hMenu
,
79 const VDM_MENUITEM
*Items
)
82 WCHAR szMenuString
[255];
87 if (Items
[i
].uID
!= (UINT
)-1)
89 if (LoadStringW(GetModuleHandle(NULL
),
92 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
94 if (Items
[i
].SubMenu
!= NULL
)
96 hSubMenu
= CreatePopupMenu();
99 AppendMenuItems(hSubMenu
, Items
[i
].SubMenu
);
101 if (!AppendMenuW(hMenu
,
102 MF_STRING
| MF_POPUP
,
106 DestroyMenu(hSubMenu
);
127 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
131 CreateVdmMenu(HANDLE ConOutHandle
)
133 hConsoleMenu
= ConsoleMenuControl(ConOutHandle
,
136 if (hConsoleMenu
== NULL
) return;
138 VdmMenuPos
= GetMenuItemCount(hConsoleMenu
);
139 AppendMenuItems(hConsoleMenu
, VdmMainMenuItems
);
140 DrawMenuBar(GetConsoleWindow());
147 const VDM_MENUITEM
*Items
= VdmMainMenuItems
;
151 DeleteMenu(hConsoleMenu
, VdmMenuPos
, MF_BYPOSITION
);
153 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
155 DrawMenuBar(GetConsoleWindow());
158 static VOID
ShowHideMousePointer(HANDLE ConOutHandle
, BOOLEAN ShowPtr
)
160 WCHAR szMenuString
[255] = L
"";
164 /* Be sure the cursor will be shown */
165 while (ShowConsoleCursor(ConOutHandle
, TRUE
) < 0) ;
169 /* Be sure the cursor will be hidden */
170 while (ShowConsoleCursor(ConOutHandle
, FALSE
) >= 0) ;
173 if (LoadStringW(GetModuleHandle(NULL
),
174 (!ShowPtr
? IDS_SHOW_MOUSE
: IDS_HIDE_MOUSE
),
176 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
178 ModifyMenu(hConsoleMenu
, ID_SHOWHIDE_MOUSE
,
179 MF_BYCOMMAND
, ID_SHOWHIDE_MOUSE
, szMenuString
);
183 /* PUBLIC FUNCTIONS ***********************************************************/
186 DisplayMessage(LPCWSTR Format
, ...)
191 va_start(Parameters
, Format
);
192 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
193 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
194 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
200 ConsoleCtrlHandler(DWORD ControlType
)
205 case CTRL_BREAK_EVENT
:
208 DPRINT1("Ctrl-C/Break: Call INT 23h\n");
209 EmulatorInterrupt(0x23);
212 case CTRL_LAST_CLOSE_EVENT
:
214 if (WaitForSingleObject(VdmTaskEvent
, 0) == WAIT_TIMEOUT
)
216 /* Exit immediately */
218 if (CommandThread
) TerminateThread(CommandThread
, 0);
225 /* Stop accepting new commands */
226 AcceptCommands
= FALSE
;
234 /* Stop the VDM if the user logs out or closes the console */
244 CreateVdmMenu(ConsoleOutput
);
248 ConsoleCleanupUI(VOID
)
250 /* Display again properly the mouse pointer */
251 if (ShowPointer
) ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
259 /* Save the original input and output console modes */
260 if (!GetConsoleMode(ConsoleInput
, &OrgConsoleInputMode
) ||
261 !GetConsoleMode(ConsoleOutput
, &OrgConsoleOutputMode
))
263 CloseHandle(ConsoleOutput
);
264 CloseHandle(ConsoleInput
);
265 wprintf(L
"FATAL: Cannot save console in/out modes\n");
269 /* Initialize the UI */
278 /* Restore the original input and output console modes */
279 SetConsoleMode(ConsoleOutput
, OrgConsoleOutputMode
);
280 SetConsoleMode(ConsoleInput
, OrgConsoleInputMode
);
289 /* Set the handler routine */
290 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
292 /* Enable the CTRL_LAST_CLOSE_EVENT */
293 SetLastConsoleEventActive();
296 * NOTE: The CONIN$ and CONOUT$ "virtual" files
297 * always point to non-redirected console handles.
300 /* Get the input handle to the real console, and check for success */
301 ConsoleInput
= CreateFileW(L
"CONIN$",
302 GENERIC_READ
| GENERIC_WRITE
,
303 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
308 if (ConsoleInput
== INVALID_HANDLE_VALUE
)
310 wprintf(L
"FATAL: Cannot retrieve a handle to the console input\n");
314 /* Get the output handle to the real console, and check for success */
315 ConsoleOutput
= CreateFileW(L
"CONOUT$",
316 GENERIC_READ
| GENERIC_WRITE
,
317 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
322 if (ConsoleOutput
== INVALID_HANDLE_VALUE
)
324 CloseHandle(ConsoleInput
);
325 wprintf(L
"FATAL: Cannot retrieve a handle to the console output\n");
329 /* Effectively attach to the console */
330 return ConsoleAttach();
336 /* Detach from the console */
339 /* Close the console handles */
340 if (ConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleOutput
);
341 if (ConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleInput
);
344 VOID
MenuEventHandler(PMENU_EVENT_RECORD MenuEvent
)
346 switch (MenuEvent
->dwCommandId
)
348 case ID_SHOWHIDE_MOUSE
:
349 ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
350 ShowPointer
= !ShowPointer
;
353 case ID_VDM_DUMPMEM_TXT
:
357 case ID_VDM_DUMPMEM_BIN
:
371 VOID
FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent
)
373 DPRINT1("Focus events not handled\n");
377 wmain(INT argc
, WCHAR
*argv
[])
383 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
384 L
"Usage: NTVDM <executable> [<parameters>]\n");
393 /* Parse the command line arguments */
394 for (i
= 1; i
< argc
; i
++)
396 if (wcsncmp(argv
[i
], L
"-i", 2) == 0)
398 /* This is the session ID */
399 SessionId
= wcstoul(argv
[i
] + 2, &endptr
, 10);
401 /* The VDM hasn't been started from a console, so quit when the task is done */
402 AcceptCommands
= FALSE
;
411 DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
413 /* Create the task event */
414 VdmTaskEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
415 ASSERT(VdmTaskEvent
!= NULL
);
417 /* Initialize the console */
420 wprintf(L
"FATAL: A problem occurred when trying to initialize the console\n");
424 /* Initialize the emulator */
425 if (!EmulatorInitialize(ConsoleInput
, ConsoleOutput
))
427 wprintf(L
"FATAL: Failed to initialize the emulator\n");
431 /* Initialize the system BIOS */
432 if (!BiosInitialize(NULL
))
434 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
438 /* Let's go! Start simulation */
451 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");