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
)
129 VdmMenuPos
= GetMenuItemCount(hConsoleMenu
);
130 AppendMenuItems(hConsoleMenu
, VdmMainMenuItems
);
131 DrawMenuBar(GetConsoleWindow());
139 const VDM_MENUITEM
*Items
= VdmMainMenuItems
;
143 DeleteMenu(hConsoleMenu
, VdmMenuPos
, MF_BYPOSITION
);
145 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
147 DrawMenuBar(GetConsoleWindow());
150 static VOID
ShowHideMousePointer(HANDLE ConOutHandle
, BOOLEAN ShowPtr
)
152 WCHAR szMenuString
[255] = L
"";
154 ShowConsoleCursor(ConOutHandle
, ShowPtr
);
156 if (LoadStringW(GetModuleHandle(NULL
),
157 (!ShowPtr
? IDS_SHOW_MOUSE
: IDS_HIDE_MOUSE
),
159 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
161 ModifyMenu(hConsoleMenu
, ID_SHOWHIDE_MOUSE
,
162 MF_BYCOMMAND
, ID_SHOWHIDE_MOUSE
, szMenuString
);
166 /* PUBLIC FUNCTIONS ***********************************************************/
168 VOID
DisplayMessage(LPCWSTR Format
, ...)
173 va_start(Parameters
, Format
);
174 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
175 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
176 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
180 BOOL WINAPI
ConsoleCtrlHandler(DWORD ControlType
)
185 case CTRL_BREAK_EVENT
:
188 EmulatorInterrupt(0x23);
193 /* Stop the VDM if the user logs out or closes the console */
200 VOID
ConsoleInitUI(VOID
)
202 CreateVdmMenu(ConsoleOutput
);
205 VOID
ConsoleCleanupUI(VOID
)
207 /* Display again properly the mouse pointer */
208 if (ShowPointer
) ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
213 DWORD WINAPI
PumpConsoleInput(LPVOID Parameter
)
215 HANDLE ConsoleInput
= (HANDLE
)Parameter
;
216 INPUT_RECORD InputRecord
;
221 /* Wait for an input record */
222 if (!ReadConsoleInput(ConsoleInput
, &InputRecord
, 1, &Count
))
224 DWORD LastError
= GetLastError();
225 DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput
, Count
, LastError
);
231 /* Check the event type */
232 switch (InputRecord
.EventType
)
236 /* Send it to the PS/2 controller */
237 PS2Dispatch(&InputRecord
);
242 switch (InputRecord
.Event
.MenuEvent
.dwCommandId
)
244 case ID_SHOWHIDE_MOUSE
:
245 ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
246 ShowPointer
= !ShowPointer
;
268 BOOL
ConsoleInit(VOID
)
270 /* Set the handler routine */
271 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
273 /* Get the input handle to the real console, and check for success */
274 ConsoleInput
= CreateFileW(L
"CONIN$",
275 GENERIC_READ
| GENERIC_WRITE
,
276 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
281 if (ConsoleInput
== INVALID_HANDLE_VALUE
)
283 wprintf(L
"FATAL: Cannot retrieve a handle to the console input\n");
287 /* Get the output handle to the real console, and check for success */
288 ConsoleOutput
= CreateFileW(L
"CONOUT$",
289 GENERIC_READ
| GENERIC_WRITE
,
290 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
295 if (ConsoleOutput
== INVALID_HANDLE_VALUE
)
297 CloseHandle(ConsoleInput
);
298 wprintf(L
"FATAL: Cannot retrieve a handle to the console output\n");
302 /* Save the original input and output console modes */
303 if (!GetConsoleMode(ConsoleInput
, &OrgConsoleInputMode
) ||
304 !GetConsoleMode(ConsoleOutput
, &OrgConsoleOutputMode
))
306 CloseHandle(ConsoleOutput
);
307 CloseHandle(ConsoleInput
);
308 wprintf(L
"FATAL: Cannot save console in/out modes\n");
312 /* Save the original cursor and console screen buffer information */
313 if (!GetConsoleCursorInfo(ConsoleOutput
, &OrgConsoleCursorInfo
) ||
314 !GetConsoleScreenBufferInfo(ConsoleOutput
, &OrgConsoleBufferInfo
))
316 CloseHandle(ConsoleOutput
);
317 CloseHandle(ConsoleInput
);
318 wprintf(L
"FATAL: Cannot save console cursor/screen-buffer info\n");
322 /* Initialize the UI */
328 VOID
ConsoleCleanup(VOID
)
331 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
333 /* Restore the old screen buffer */
334 SetConsoleActiveScreenBuffer(ConsoleOutput
);
336 /* Restore the original console size */
337 GetConsoleScreenBufferInfo(ConsoleOutput
, &ConsoleInfo
);
338 ConRect
.Left
= 0; // OrgConsoleBufferInfo.srWindow.Left;
339 // ConRect.Top = ConsoleInfo.dwCursorPosition.Y / (OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top + 1);
340 // ConRect.Top *= (OrgConsoleBufferInfo.srWindow.Bottom - OrgConsoleBufferInfo.srWindow.Top + 1);
341 ConRect
.Top
= ConsoleInfo
.dwCursorPosition
.Y
;
342 ConRect
.Right
= ConRect
.Left
+ OrgConsoleBufferInfo
.srWindow
.Right
- OrgConsoleBufferInfo
.srWindow
.Left
;
343 ConRect
.Bottom
= ConRect
.Top
+ OrgConsoleBufferInfo
.srWindow
.Bottom
- OrgConsoleBufferInfo
.srWindow
.Top
;
344 /* See the following trick explanation in vga.c:VgaEnterTextMode() */
345 SetConsoleScreenBufferSize(ConsoleOutput
, OrgConsoleBufferInfo
.dwSize
);
346 SetConsoleWindowInfo(ConsoleOutput
, TRUE
, &ConRect
);
347 // SetConsoleWindowInfo(ConsoleOutput, TRUE, &OrgConsoleBufferInfo.srWindow);
348 SetConsoleScreenBufferSize(ConsoleOutput
, OrgConsoleBufferInfo
.dwSize
);
350 /* Restore the original cursor shape */
351 SetConsoleCursorInfo(ConsoleOutput
, &OrgConsoleCursorInfo
);
353 /* Restore the original input and output console modes */
354 SetConsoleMode(ConsoleOutput
, OrgConsoleOutputMode
);
355 SetConsoleMode(ConsoleInput
, OrgConsoleInputMode
);
360 /* Close the console handles */
361 if (ConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleOutput
);
362 if (ConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleInput
);
365 INT
wmain(INT argc
, WCHAR
*argv
[])
368 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
369 L
"OS integration (BaseVDM) unimplemented\n");
373 CHAR CommandLine
[DOS_CMDLINE_LENGTH
];
375 if (argc
== 2 && argv
[1] != NULL
)
377 WideCharToMultiByte(CP_ACP
, 0, argv
[1], -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
381 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
382 L
"Usage: NTVDM <executable>\n");
386 DPRINT1("\n\n\nNTVDM - Starting '%s'...\n\n\n", CommandLine
);
388 /* Initialize the console */
391 wprintf(L
"FATAL: A problem occurred when trying to initialize the console\n");
395 /* Initialize the emulator */
396 if (!EmulatorInitialize(ConsoleInput
, ConsoleOutput
))
398 wprintf(L
"FATAL: Failed to initialize the emulator\n");
402 /* Initialize the system BIOS */
403 if (!BiosInitialize(NULL
, ConsoleInput
, ConsoleOutput
))
405 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
409 /* Initialize the VDM DOS kernel */
410 if (!DosInitialize(NULL
))
412 wprintf(L
"FATAL: Failed to initialize the VDM DOS kernel.\n");
416 /* Start the process from the command line */
417 if (!DosCreateProcess(CommandLine
, 0))
419 DisplayMessage(L
"Could not start program: %S", CommandLine
);
424 while (VdmRunning
) ClockUpdate();
426 /* Perform another screen refresh */
434 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");