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 "bios/bios.h"
21 /* VARIABLES ******************************************************************/
23 static HANDLE ConsoleInput
= INVALID_HANDLE_VALUE
;
24 static HANDLE ConsoleOutput
= INVALID_HANDLE_VALUE
;
25 static DWORD OrgConsoleInputMode
, OrgConsoleOutputMode
;
29 BOOLEAN AcceptCommands
= TRUE
;
30 HANDLE CommandThread
= NULL
;
34 HANDLE VdmTaskEvent
= NULL
;
36 // Command line of NTVDM
41 static HMENU hConsoleMenu
= NULL
;
42 static INT VdmMenuPos
= -1;
43 static BOOLEAN ShowPointer
= FALSE
;
46 * Those menu helpers were taken from the GUI frontend in winsrv.dll
48 typedef struct _VDM_MENUITEM
51 const struct _VDM_MENUITEM
*SubMenu
;
53 } VDM_MENUITEM
, *PVDM_MENUITEM
;
55 static const VDM_MENUITEM VdmMenuItems
[] =
57 { IDS_VDM_DUMPMEM_TXT
, NULL
, ID_VDM_DUMPMEM_TXT
},
58 { IDS_VDM_DUMPMEM_BIN
, NULL
, ID_VDM_DUMPMEM_BIN
},
59 { IDS_VDM_QUIT
, NULL
, ID_VDM_QUIT
},
61 { 0, NULL
, 0 } /* End of list */
64 static const VDM_MENUITEM VdmMainMenuItems
[] =
66 { -1, NULL
, 0 }, /* Separator */
67 { IDS_HIDE_MOUSE
, NULL
, ID_SHOWHIDE_MOUSE
}, /* Hide mouse; can be renamed to Show mouse */
68 { IDS_VDM_MENU
, VdmMenuItems
, 0 }, /* ReactOS VDM Menu */
70 { 0, NULL
, 0 } /* End of list */
74 AppendMenuItems(HMENU hMenu
,
75 const VDM_MENUITEM
*Items
)
78 WCHAR szMenuString
[255];
83 if (Items
[i
].uID
!= (UINT
)-1)
85 if (LoadStringW(GetModuleHandle(NULL
),
88 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
90 if (Items
[i
].SubMenu
!= NULL
)
92 hSubMenu
= CreatePopupMenu();
95 AppendMenuItems(hSubMenu
, Items
[i
].SubMenu
);
97 if (!AppendMenuW(hMenu
,
102 DestroyMenu(hSubMenu
);
123 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
127 CreateVdmMenu(HANDLE ConOutHandle
)
129 hConsoleMenu
= ConsoleMenuControl(ConOutHandle
,
132 if (hConsoleMenu
== NULL
) return;
134 VdmMenuPos
= GetMenuItemCount(hConsoleMenu
);
135 AppendMenuItems(hConsoleMenu
, VdmMainMenuItems
);
136 DrawMenuBar(GetConsoleWindow());
143 const VDM_MENUITEM
*Items
= VdmMainMenuItems
;
147 DeleteMenu(hConsoleMenu
, VdmMenuPos
, MF_BYPOSITION
);
149 } while (!(Items
[i
].uID
== 0 && Items
[i
].SubMenu
== NULL
&& Items
[i
].wCmdID
== 0));
151 DrawMenuBar(GetConsoleWindow());
154 static VOID
ShowHideMousePointer(HANDLE ConOutHandle
, BOOLEAN ShowPtr
)
156 WCHAR szMenuString
[255] = L
"";
160 /* Be sure the cursor will be shown */
161 while (ShowConsoleCursor(ConOutHandle
, TRUE
) < 0) ;
165 /* Be sure the cursor will be hidden */
166 while (ShowConsoleCursor(ConOutHandle
, FALSE
) >= 0) ;
169 if (LoadStringW(GetModuleHandle(NULL
),
170 (!ShowPtr
? IDS_SHOW_MOUSE
: IDS_HIDE_MOUSE
),
172 sizeof(szMenuString
) / sizeof(szMenuString
[0])) > 0)
174 ModifyMenu(hConsoleMenu
, ID_SHOWHIDE_MOUSE
,
175 MF_BYCOMMAND
, ID_SHOWHIDE_MOUSE
, szMenuString
);
179 static VOID
EnableExtraHardware(HANDLE ConsoleInput
)
183 if (GetConsoleMode(ConsoleInput
, &ConInMode
))
186 // GetNumberOfConsoleMouseButtons();
187 // GetSystemMetrics(SM_CMOUSEBUTTONS);
188 // GetSystemMetrics(SM_MOUSEPRESENT);
192 /* Support mouse input events if there is a mouse on the system */
193 ConInMode
|= ENABLE_MOUSE_INPUT
;
198 /* Do not support mouse input events if there is no mouse on the system */
199 ConInMode
&= ~ENABLE_MOUSE_INPUT
;
203 SetConsoleMode(ConsoleInput
, ConInMode
);
207 /* PUBLIC FUNCTIONS ***********************************************************/
210 DisplayMessage(LPCWSTR Format
, ...)
212 #ifndef WIN2K_COMPLIANT
213 WCHAR StaticBuffer
[256];
214 LPWSTR Buffer
= StaticBuffer
; // Use the static buffer by default.
216 WCHAR Buffer
[2048]; // Large enough. If not, increase it by hand.
221 va_start(Parameters
, Format
);
223 #ifndef WIN2K_COMPLIANT
225 * Retrieve the message length and if it is too long, allocate
226 * an auxiliary buffer; otherwise use the static buffer.
228 MsgLen
= _vscwprintf(Format
, Parameters
) + 1; // NULL-terminated
229 if (MsgLen
> sizeof(StaticBuffer
)/sizeof(StaticBuffer
[0]))
231 Buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MsgLen
* sizeof(WCHAR
));
234 /* Allocation failed, use the static buffer and display a suitable error message */
235 Buffer
= StaticBuffer
;
236 Format
= L
"DisplayMessage()\nOriginal message is too long and allocating an auxiliary buffer failed.";
237 MsgLen
= wcslen(Format
);
241 MsgLen
= sizeof(Buffer
)/sizeof(Buffer
[0]);
244 /* Display the message */
245 _vsnwprintf(Buffer
, MsgLen
, Format
, Parameters
);
246 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
247 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
249 #ifndef WIN2K_COMPLIANT
250 /* Free the buffer if needed */
251 if (Buffer
!= StaticBuffer
) HeapFree(GetProcessHeap(), 0, Buffer
);
259 ConsoleCtrlHandler(DWORD ControlType
)
263 case CTRL_LAST_CLOSE_EVENT
:
265 if (WaitForSingleObject(VdmTaskEvent
, 0) == WAIT_TIMEOUT
)
267 /* Exit immediately */
269 if (CommandThread
) TerminateThread(CommandThread
, 0);
276 /* Stop accepting new commands */
277 AcceptCommands
= FALSE
;
286 /* Stop the VDM if the user logs out or closes the console */
296 CreateVdmMenu(ConsoleOutput
);
300 ConsoleCleanupUI(VOID
)
302 /* Display again properly the mouse pointer */
303 if (ShowPointer
) ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
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 /* Set the console input mode */
322 // FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions
323 // upon console window events (screen buffer resize, ...).
324 SetConsoleMode(ConsoleInput
, 0 /* | ENABLE_WINDOW_INPUT */);
325 EnableExtraHardware(ConsoleInput
);
327 /* Set the console output mode */
328 // SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
330 /* Initialize the UI */
339 /* Restore the original input and output console modes */
340 SetConsoleMode(ConsoleOutput
, OrgConsoleOutputMode
);
341 SetConsoleMode(ConsoleInput
, OrgConsoleInputMode
);
350 /* Set the handler routine */
351 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
353 /* Enable the CTRL_LAST_CLOSE_EVENT */
354 SetLastConsoleEventActive();
357 * NOTE: The CONIN$ and CONOUT$ "virtual" files
358 * always point to non-redirected console handles.
361 /* Get the input handle to the real console, and check for success */
362 ConsoleInput
= CreateFileW(L
"CONIN$",
363 GENERIC_READ
| GENERIC_WRITE
,
364 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
369 if (ConsoleInput
== INVALID_HANDLE_VALUE
)
371 wprintf(L
"FATAL: Cannot retrieve a handle to the console input\n");
375 /* Get the output handle to the real console, and check for success */
376 ConsoleOutput
= CreateFileW(L
"CONOUT$",
377 GENERIC_READ
| GENERIC_WRITE
,
378 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
383 if (ConsoleOutput
== INVALID_HANDLE_VALUE
)
385 CloseHandle(ConsoleInput
);
386 wprintf(L
"FATAL: Cannot retrieve a handle to the console output\n");
390 /* Effectively attach to the console */
391 return ConsoleAttach();
397 /* Detach from the console */
400 /* Close the console handles */
401 if (ConsoleOutput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleOutput
);
402 if (ConsoleInput
!= INVALID_HANDLE_VALUE
) CloseHandle(ConsoleInput
);
405 VOID
MenuEventHandler(PMENU_EVENT_RECORD MenuEvent
)
407 switch (MenuEvent
->dwCommandId
)
409 case ID_SHOWHIDE_MOUSE
:
410 ShowHideMousePointer(ConsoleOutput
, ShowPointer
);
411 ShowPointer
= !ShowPointer
;
414 case ID_VDM_DUMPMEM_TXT
:
418 case ID_VDM_DUMPMEM_BIN
:
432 VOID
FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent
)
434 DPRINT1("Focus events not handled\n");
438 wmain(INT argc
, WCHAR
*argv
[])
444 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
445 L
"Usage: NTVDM <executable> [<parameters>]\n");
454 /* Parse the command line arguments */
455 for (i
= 1; i
< argc
; i
++)
457 if (wcsncmp(argv
[i
], L
"-i", 2) == 0)
459 /* This is the session ID */
460 SessionId
= wcstoul(argv
[i
] + 2, &endptr
, 10);
462 /* The VDM hasn't been started from a console, so quit when the task is done */
463 AcceptCommands
= FALSE
;
472 DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
474 /* Create the task event */
475 VdmTaskEvent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
476 ASSERT(VdmTaskEvent
!= NULL
);
478 /* Initialize the console */
481 wprintf(L
"FATAL: A problem occurred when trying to initialize the console\n");
485 /* Initialize the emulator */
486 if (!EmulatorInitialize(ConsoleInput
, ConsoleOutput
))
488 wprintf(L
"FATAL: Failed to initialize the emulator\n");
492 /* Initialize the system BIOS */
493 if (!BiosInitialize(NULL
))
495 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
499 /* Let's go! Start simulation */
512 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");