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 *******************************************************************/
17 #include "hardware/ps2.h"
18 #include "hardware/vga.h"
19 #include "bios/bios.h"
25 * Activate this line if you want to run NTVDM in standalone mode with:
30 /* VARIABLES ******************************************************************/
32 static HANDLE ConsoleInput
= INVALID_HANDLE_VALUE
;
33 static HANDLE ConsoleOutput
= INVALID_HANDLE_VALUE
;
34 static DWORD OrgConsoleInputMode
, OrgConsoleOutputMode
;
35 static CONSOLE_CURSOR_INFO OrgConsoleCursorInfo
;
36 static CONSOLE_SCREEN_BUFFER_INFO OrgConsoleBufferInfo
;
38 static HMENU hConsoleMenu
= NULL
;
39 static INT VdmMenuPos
= -1;
40 static BOOLEAN ShowPointer
= FALSE
;
43 * Those menu helpers were taken from the GUI frontend in winsrv.dll
45 typedef struct _VDM_MENUITEM
48 const struct _VDM_MENUITEM
*SubMenu
;
50 } VDM_MENUITEM
, *PVDM_MENUITEM
;
52 static const VDM_MENUITEM VdmMenuItems
[] =
54 { IDS_VDM_QUIT
, NULL
, ID_VDM_QUIT
},
56 { 0, NULL
, 0 } /* End of list */
59 static const VDM_MENUITEM VdmMainMenuItems
[] =
61 { -1, NULL
, 0 }, /* Separator */
62 { IDS_HIDE_MOUSE
, NULL
, ID_SHOWHIDE_MOUSE
}, /* Hide mouse; can be renamed to Show mouse */
63 { IDS_VDM_MENU
, VdmMenuItems
, 0 }, /* ReactOS VDM Menu */
65 { 0, NULL
, 0 } /* End of list */
69 AppendMenuItems(HMENU hMenu
,
70 const VDM_MENUITEM
*Items
)
73 WCHAR szMenuString
[255];
78 if (Items
[i
].uID
!= (UINT
)-1)
80 if (LoadStringW(GetModuleHandle(NULL
),
83 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
85 if (Items
[i
].SubMenu
!= NULL
)
87 hSubMenu
= CreatePopupMenu();
90 AppendMenuItems(hSubMenu
, Items
[i
].SubMenu
);
92 if (!AppendMenuW(hMenu
,
97 DestroyMenu(hSubMenu
);
118 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
122 CreateVdmMenu(HANDLE ConOutHandle
)
124 hConsoleMenu
= ConsoleMenuControl(ConsoleOutput
,
127 if (hConsoleMenu
== NULL
) return;
129 VdmMenuPos
= GetMenuItemCount(hConsoleMenu
);
130 AppendMenuItems(hConsoleMenu
, VdmMainMenuItems
);
131 DrawMenuBar(GetConsoleWindow());
138 const VDM_MENUITEM
*Items
= VdmMainMenuItems
;
142 DeleteMenu(hConsoleMenu
, VdmMenuPos
, MF_BYPOSITION
);
144 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
146 DrawMenuBar(GetConsoleWindow());
149 static VOID
ShowHideMousePointer(HANDLE ConOutHandle
, BOOLEAN ShowPtr
)
151 WCHAR szMenuString
[255] = L
"";
155 /* Be sure the cursor will be shown */
156 while (ShowConsoleCursor(ConOutHandle
, TRUE
) < 0) ;
160 /* Be sure the cursor will be hidden */
161 while (ShowConsoleCursor(ConOutHandle
, FALSE
) >= 0) ;
164 if (LoadStringW(GetModuleHandle(NULL
),
165 (!ShowPtr
? IDS_SHOW_MOUSE
: IDS_HIDE_MOUSE
),
167 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
169 ModifyMenu(hConsoleMenu
, ID_SHOWHIDE_MOUSE
,
170 MF_BYCOMMAND
, ID_SHOWHIDE_MOUSE
, szMenuString
);
174 /* PUBLIC FUNCTIONS ***********************************************************/
176 VOID
DisplayMessage(LPCWSTR Format
, ...)
181 va_start(Parameters
, Format
);
182 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
183 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
184 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
188 BOOL WINAPI
ConsoleCtrlHandler(DWORD ControlType
)
193 case CTRL_BREAK_EVENT
:
196 EmulatorInterrupt(0x23);
201 /* Stop the VDM if the user logs out or closes the console */
208 VOID
ConsoleInitUI(VOID
)
210 CreateVdmMenu(ConsoleOutput
);
213 VOID
ConsoleCleanupUI(VOID
)
215 /* Display again properly the mouse pointer */
216 if (ShowPointer
) ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
221 DWORD WINAPI
PumpConsoleInput(LPVOID Parameter
)
223 HANDLE ConsoleInput
= (HANDLE
)Parameter
;
224 INPUT_RECORD InputRecord
;
229 /* Wait for an input record */
230 if (!ReadConsoleInput(ConsoleInput
, &InputRecord
, 1, &Count
))
232 DWORD LastError
= GetLastError();
233 DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput
, Count
, LastError
);
239 /* Check the event type */
240 switch (InputRecord
.EventType
)
244 /* Send it to the PS/2 controller */
245 PS2Dispatch(&InputRecord
);
250 switch (InputRecord
.Event
.MenuEvent
.dwCommandId
)
252 case ID_SHOWHIDE_MOUSE
:
253 ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
254 ShowPointer
= !ShowPointer
;
277 BOOL
ConsoleInit(VOID
)
279 /* Set the handler routine */
280 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
282 /* Get the input handle to the real console, and check for success */
283 ConsoleInput
= CreateFileW(L
"CONIN$",
284 GENERIC_READ
| GENERIC_WRITE
,
285 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
290 if (ConsoleInput
== INVALID_HANDLE_VALUE
)
292 wprintf(L
"FATAL: Cannot retrieve a handle to the console input\n");
296 /* Get the output handle to the real console, and check for success */
297 ConsoleOutput
= CreateFileW(L
"CONOUT$",
298 GENERIC_READ
| GENERIC_WRITE
,
299 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
304 if (ConsoleOutput
== INVALID_HANDLE_VALUE
)
306 CloseHandle(ConsoleInput
);
307 wprintf(L
"FATAL: Cannot retrieve a handle to the console output\n");
311 /* Save the original input and output console modes */
312 if (!GetConsoleMode(ConsoleInput
, &OrgConsoleInputMode
) ||
313 !GetConsoleMode(ConsoleOutput
, &OrgConsoleOutputMode
))
315 CloseHandle(ConsoleOutput
);
316 CloseHandle(ConsoleInput
);
317 wprintf(L
"FATAL: Cannot save console in/out modes\n");
321 /* Save the original cursor and console screen buffer information */
322 if (!GetConsoleCursorInfo(ConsoleOutput
, &OrgConsoleCursorInfo
) ||
323 !GetConsoleScreenBufferInfo(ConsoleOutput
, &OrgConsoleBufferInfo
))
325 CloseHandle(ConsoleOutput
);
326 CloseHandle(ConsoleInput
);
327 wprintf(L
"FATAL: Cannot save console cursor/screen-buffer info\n");
331 /* Initialize the UI */
337 VOID
ConsoleCleanup(VOID
)
341 /* Restore the old screen buffer */
342 SetConsoleActiveScreenBuffer(ConsoleOutput
);
344 /* Restore the original console size */
347 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
348 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
350 * See the following trick explanation in vga.c:VgaEnterTextMode() .
352 SetConsoleScreenBufferSize(ConsoleOutput
, OrgConsoleBufferInfo
.dwSize
);
353 SetConsoleWindowInfo(ConsoleOutput
, TRUE
, &ConRect
);
354 SetConsoleScreenBufferSize(ConsoleOutput
, OrgConsoleBufferInfo
.dwSize
);
356 /* Restore the original cursor shape */
357 SetConsoleCursorInfo(ConsoleOutput
, &OrgConsoleCursorInfo
);
359 /* Restore the original input and output console modes */
360 SetConsoleMode(ConsoleOutput
, OrgConsoleOutputMode
);
361 SetConsoleMode(ConsoleInput
, OrgConsoleInputMode
);
366 /* Close the console handles */
367 if (ConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleOutput
);
368 if (ConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleInput
);
371 INT
wmain(INT argc
, WCHAR
*argv
[])
374 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
375 L
"OS integration (BaseVDM) unimplemented\n");
379 CHAR CommandLine
[DOS_CMDLINE_LENGTH
];
381 if (argc
== 2 && argv
[1] != NULL
)
383 WideCharToMultiByte(CP_ACP
, 0, argv
[1], -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
387 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
388 L
"Usage: NTVDM <executable>\n");
392 DPRINT1("\n\n\nNTVDM - Starting '%s'...\n\n\n", CommandLine
);
394 /* Initialize the console */
397 wprintf(L
"FATAL: A problem occurred when trying to initialize the console\n");
401 /* Initialize the emulator */
402 if (!EmulatorInitialize(ConsoleInput
, ConsoleOutput
))
404 wprintf(L
"FATAL: Failed to initialize the emulator\n");
408 /* Initialize the system BIOS */
409 if (!BiosInitialize(NULL
))
411 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
415 /* Initialize the VDM DOS kernel */
416 if (!DosInitialize(NULL
))
418 wprintf(L
"FATAL: Failed to initialize the VDM DOS kernel.\n");
422 /* Start the process from the command line */
423 if (!DosCreateProcess(CommandLine
, 0))
425 DisplayMessage(L
"Could not start program: %S", CommandLine
);
429 /* Start simulation */
432 /* Perform another screen refresh */
440 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");