709c92aeebcbd3893abfd7c569dfd9f7a69ec30e
[reactos.git] / reactos / subsystems / mvdm / ntvdm / ntvdm.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/ntvdm.c
5 * PURPOSE: Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "ntvdm.h"
14 #include "emulator.h"
15
16 #include "bios/bios.h"
17 #include "cpu/cpu.h"
18
19 #include "dos/dem.h"
20
21 #include "resource.h"
22
23 /* VARIABLES ******************************************************************/
24
25 static HANDLE ConsoleInput = INVALID_HANDLE_VALUE;
26 static HANDLE ConsoleOutput = INVALID_HANDLE_VALUE;
27 static DWORD OrgConsoleInputMode, OrgConsoleOutputMode;
28
29 NTVDM_SETTINGS GlobalSettings;
30
31 // Command line of NTVDM
32 INT NtVdmArgc;
33 WCHAR** NtVdmArgv;
34
35 HWND hConsoleWnd = NULL;
36 static HMENU hConsoleMenu = NULL;
37 static INT VdmMenuPos = -1;
38 static BOOLEAN ShowPointer = FALSE;
39
40 /*
41 * Those menu helpers were taken from the GUI frontend in winsrv.dll
42 */
43 typedef struct _VDM_MENUITEM
44 {
45 UINT uID;
46 const struct _VDM_MENUITEM *SubMenu;
47 UINT_PTR uCmdID;
48 } VDM_MENUITEM, *PVDM_MENUITEM;
49
50 static const VDM_MENUITEM VdmMenuItems[] =
51 {
52 { IDS_VDM_DUMPMEM_TXT, NULL, ID_VDM_DUMPMEM_TXT },
53 { IDS_VDM_DUMPMEM_BIN, NULL, ID_VDM_DUMPMEM_BIN },
54 { -1, NULL, 0 }, /* Separator */
55 // { IDS_VDM_MOUNT_FLOPPY, NULL, ID_VDM_DRIVES },
56 // { IDS_VDM_EJECT_FLOPPY, NULL, ID_VDM_DRIVES },
57 { -1, NULL, 0 }, /* Separator */
58 { IDS_VDM_QUIT , NULL, ID_VDM_QUIT },
59
60 { 0, NULL, 0 } /* End of list */
61 };
62
63 static const VDM_MENUITEM VdmMainMenuItems[] =
64 {
65 { -1, NULL, 0 }, /* Separator */
66 { IDS_HIDE_MOUSE, NULL, ID_SHOWHIDE_MOUSE }, /* "Hide mouse"; can be renamed to "Show mouse" */
67 { IDS_VDM_MENU , VdmMenuItems, 0 }, /* ReactOS VDM Menu */
68
69 { 0, NULL, 0 } /* End of list */
70 };
71
72 static VOID
73 AppendMenuItems(HMENU hMenu,
74 const VDM_MENUITEM *Items)
75 {
76 UINT i = 0;
77 WCHAR szMenuString[256];
78 HMENU hSubMenu;
79
80 do
81 {
82 if (Items[i].uID != (UINT)-1)
83 {
84 if (LoadStringW(GetModuleHandle(NULL),
85 Items[i].uID,
86 szMenuString,
87 ARRAYSIZE(szMenuString)) > 0)
88 {
89 if (Items[i].SubMenu != NULL)
90 {
91 hSubMenu = CreatePopupMenu();
92 if (hSubMenu != NULL)
93 {
94 AppendMenuItems(hSubMenu, Items[i].SubMenu);
95
96 if (!AppendMenuW(hMenu,
97 MF_STRING | MF_POPUP,
98 (UINT_PTR)hSubMenu,
99 szMenuString))
100 {
101 DestroyMenu(hSubMenu);
102 }
103 }
104 }
105 else
106 {
107 AppendMenuW(hMenu,
108 MF_STRING,
109 Items[i].uCmdID,
110 szMenuString);
111 }
112 }
113 }
114 else
115 {
116 AppendMenuW(hMenu,
117 MF_SEPARATOR,
118 0,
119 NULL);
120 }
121 i++;
122 } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].uCmdID == 0));
123 }
124
125 BOOL
126 VdmMenuExists(HMENU hConsoleMenu)
127 {
128 INT MenuPos, i;
129 MenuPos = GetMenuItemCount(hConsoleMenu);
130
131 /* Check for the presence of one of the VDM menu items */
132 for (i = 0; i <= MenuPos; i++)
133 {
134 if (GetMenuItemID(hConsoleMenu, i) == ID_SHOWHIDE_MOUSE)
135 {
136 /* Set VdmMenuPos to the position of the existing menu */
137 VdmMenuPos = i - 1;
138 return TRUE;
139 }
140 }
141 return FALSE;
142 }
143
144 /*static*/ VOID
145 CreateVdmMenu(HANDLE ConOutHandle)
146 {
147 HMENU hVdmSubMenu;
148 UINT_PTR ItemID = ID_VDM_DRIVES;
149 UINT Pos;
150 WCHAR szNoMedia[100];
151 WCHAR szMenuString1[256], szMenuString2[256];
152
153 hConsoleMenu = ConsoleMenuControl(ConOutHandle,
154 ID_SHOWHIDE_MOUSE,
155 ID_VDM_DRIVES + 4);
156 if (hConsoleMenu == NULL) return;
157
158 /* Get the position where we are going to insert our menu items */
159 VdmMenuPos = GetMenuItemCount(hConsoleMenu);
160
161 /* Really add the menu if it doesn't already exist (in case eg. NTVDM crashed) */
162 if (!VdmMenuExists(hConsoleMenu))
163 {
164 /* Add all the menu entries */
165 AppendMenuItems(hConsoleMenu, VdmMainMenuItems);
166
167 /* Add the removable drives menu entries */
168 hVdmSubMenu = GetSubMenu(hConsoleMenu, VdmMenuPos + 2); // VdmMenuItems
169 Pos = 3; // After the 2 items and the separator in VdmMenuItems
170
171 LoadStringW(GetModuleHandle(NULL),
172 IDS_NO_MEDIA,
173 szNoMedia,
174 ARRAYSIZE(szNoMedia));
175
176 LoadStringW(GetModuleHandle(NULL),
177 IDS_VDM_MOUNT_FLOPPY,
178 szMenuString1,
179 ARRAYSIZE(szMenuString1));
180
181 /* Drive 0 -- Mount */
182 _snwprintf(szMenuString2, ARRAYSIZE(szMenuString2), szMenuString1, 0, szNoMedia);
183 szMenuString2[ARRAYSIZE(szMenuString2) - 1] = UNICODE_NULL;
184 InsertMenuW(hVdmSubMenu, Pos++, MF_STRING | MF_BYPOSITION, ItemID + 0, szMenuString2);
185
186 /* Drive 1 -- Mount */
187 _snwprintf(szMenuString2, ARRAYSIZE(szMenuString2), szMenuString1, 1, szNoMedia);
188 szMenuString2[ARRAYSIZE(szMenuString2) - 1] = UNICODE_NULL;
189 InsertMenuW(hVdmSubMenu, Pos++, MF_STRING | MF_BYPOSITION, ItemID + 2, szMenuString2);
190
191 LoadStringW(GetModuleHandle(NULL),
192 IDS_VDM_EJECT_FLOPPY,
193 szMenuString1,
194 ARRAYSIZE(szMenuString1));
195
196 /* Drive 0 -- Eject */
197 _snwprintf(szMenuString2, ARRAYSIZE(szMenuString2), szMenuString1, 0);
198 szMenuString2[ARRAYSIZE(szMenuString2) - 1] = UNICODE_NULL;
199 InsertMenuW(hVdmSubMenu, Pos++, MF_STRING | MF_BYPOSITION, ItemID + 1, szMenuString2);
200
201 /* Drive 1 -- Eject */
202 _snwprintf(szMenuString2, ARRAYSIZE(szMenuString2), szMenuString1, 1);
203 szMenuString2[ARRAYSIZE(szMenuString2) - 1] = UNICODE_NULL;
204 InsertMenuW(hVdmSubMenu, Pos++, MF_STRING | MF_BYPOSITION, ItemID + 3, szMenuString2);
205
206 // TODO: Refresh the menu state
207
208 /* Refresh the menu */
209 DrawMenuBar(hConsoleWnd);
210 }
211 }
212
213 /*static*/ VOID
214 DestroyVdmMenu(VOID)
215 {
216 UINT i = 0;
217 const VDM_MENUITEM *Items = VdmMainMenuItems;
218
219 do
220 {
221 DeleteMenu(hConsoleMenu, VdmMenuPos, MF_BYPOSITION);
222 i++;
223 } while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].uCmdID == 0));
224
225 DrawMenuBar(hConsoleWnd);
226 }
227
228 static VOID ShowHideMousePointer(HANDLE ConOutHandle, BOOLEAN ShowPtr)
229 {
230 WCHAR szMenuString[256];
231
232 if (ShowPtr)
233 {
234 /* Be sure the cursor will be shown */
235 while (ShowConsoleCursor(ConOutHandle, TRUE) < 0) ;
236 }
237 else
238 {
239 /* Be sure the cursor will be hidden */
240 while (ShowConsoleCursor(ConOutHandle, FALSE) >= 0) ;
241 }
242
243 if (LoadStringW(GetModuleHandle(NULL),
244 (!ShowPtr ? IDS_SHOW_MOUSE : IDS_HIDE_MOUSE),
245 szMenuString,
246 ARRAYSIZE(szMenuString)) > 0)
247 {
248 ModifyMenu(hConsoleMenu, ID_SHOWHIDE_MOUSE,
249 MF_BYCOMMAND, ID_SHOWHIDE_MOUSE, szMenuString);
250 }
251 }
252
253 static VOID EnableExtraHardware(HANDLE ConsoleInput)
254 {
255 DWORD ConInMode;
256
257 if (GetConsoleMode(ConsoleInput, &ConInMode))
258 {
259 #if 0
260 // GetNumberOfConsoleMouseButtons();
261 // GetSystemMetrics(SM_CMOUSEBUTTONS);
262 // GetSystemMetrics(SM_MOUSEPRESENT);
263 if (MousePresent)
264 {
265 #endif
266 /* Support mouse input events if there is a mouse on the system */
267 ConInMode |= ENABLE_MOUSE_INPUT;
268 #if 0
269 }
270 else
271 {
272 /* Do not support mouse input events if there is no mouse on the system */
273 ConInMode &= ~ENABLE_MOUSE_INPUT;
274 }
275 #endif
276
277 SetConsoleMode(ConsoleInput, ConInMode);
278 }
279 }
280
281
282 static NTSTATUS
283 NTAPI
284 NtVdmConfigureBios(IN PWSTR ValueName,
285 IN ULONG ValueType,
286 IN PVOID ValueData,
287 IN ULONG ValueLength,
288 IN PVOID Context,
289 IN PVOID EntryContext)
290 {
291 PNTVDM_SETTINGS Settings = (PNTVDM_SETTINGS)Context;
292 UNICODE_STRING ValueString;
293
294 /* Check for the type of the value */
295 if (ValueType != REG_SZ)
296 {
297 RtlInitEmptyAnsiString(&Settings->BiosFileName, NULL, 0);
298 return STATUS_SUCCESS;
299 }
300
301 /* Convert the UNICODE string to ANSI and store it */
302 RtlInitEmptyUnicodeString(&ValueString, (PWCHAR)ValueData, ValueLength);
303 ValueString.Length = ValueString.MaximumLength;
304 RtlUnicodeStringToAnsiString(&Settings->BiosFileName, &ValueString, TRUE);
305
306 return STATUS_SUCCESS;
307 }
308
309 static NTSTATUS
310 NTAPI
311 NtVdmConfigureRom(IN PWSTR ValueName,
312 IN ULONG ValueType,
313 IN PVOID ValueData,
314 IN ULONG ValueLength,
315 IN PVOID Context,
316 IN PVOID EntryContext)
317 {
318 PNTVDM_SETTINGS Settings = (PNTVDM_SETTINGS)Context;
319 UNICODE_STRING ValueString;
320
321 /* Check for the type of the value */
322 if (ValueType != REG_MULTI_SZ)
323 {
324 RtlInitEmptyAnsiString(&Settings->RomFiles, NULL, 0);
325 return STATUS_SUCCESS;
326 }
327
328 /* Convert the UNICODE string to ANSI and store it */
329 RtlInitEmptyUnicodeString(&ValueString, (PWCHAR)ValueData, ValueLength);
330 ValueString.Length = ValueString.MaximumLength;
331 RtlUnicodeStringToAnsiString(&Settings->RomFiles, &ValueString, TRUE);
332
333 return STATUS_SUCCESS;
334 }
335
336 static NTSTATUS
337 NTAPI
338 NtVdmConfigureHDD(IN PWSTR ValueName,
339 IN ULONG ValueType,
340 IN PVOID ValueData,
341 IN ULONG ValueLength,
342 IN PVOID Context,
343 IN PVOID EntryContext)
344 {
345 PNTVDM_SETTINGS Settings = (PNTVDM_SETTINGS)Context;
346 UNICODE_STRING ValueString;
347 ULONG DiskNumber = (ULONG)EntryContext;
348
349 ASSERT(DiskNumber < ARRAYSIZE(Settings->HardDisks));
350
351 /* Check whether the Hard Disk entry was not already configured */
352 if (Settings->HardDisks[DiskNumber].Buffer != NULL)
353 {
354 DPRINT1("Hard Disk %d -- '%Z' already configured\n", DiskNumber, &Settings->HardDisks[DiskNumber]);
355 return STATUS_SUCCESS;
356 }
357
358 /* Check for the type of the value */
359 if (ValueType != REG_SZ)
360 {
361 RtlInitEmptyAnsiString(&Settings->HardDisks[DiskNumber], NULL, 0);
362 return STATUS_SUCCESS;
363 }
364
365 /* Convert the UNICODE string to ANSI and store it */
366 RtlInitEmptyUnicodeString(&ValueString, (PWCHAR)ValueData, ValueLength);
367 ValueString.Length = ValueString.MaximumLength;
368 RtlUnicodeStringToAnsiString(&Settings->HardDisks[DiskNumber], &ValueString, TRUE);
369
370 return STATUS_SUCCESS;
371 }
372
373 static RTL_QUERY_REGISTRY_TABLE
374 NtVdmConfigurationTable[] =
375 {
376 {
377 NtVdmConfigureBios,
378 0,
379 L"BiosFile",
380 NULL,
381 REG_NONE,
382 NULL,
383 0
384 },
385
386 {
387 NtVdmConfigureRom,
388 RTL_QUERY_REGISTRY_NOEXPAND,
389 L"RomFiles",
390 NULL,
391 REG_NONE,
392 NULL,
393 0
394 },
395
396 {
397 NtVdmConfigureHDD,
398 0,
399 L"HardDisk0",
400 (PVOID)0,
401 REG_NONE,
402 NULL,
403 0
404 },
405
406 {
407 NtVdmConfigureHDD,
408 0,
409 L"HardDisk1",
410 (PVOID)1,
411 REG_NONE,
412 NULL,
413 0
414 },
415
416 {
417 NtVdmConfigureHDD,
418 0,
419 L"HardDisk2",
420 (PVOID)2,
421 REG_NONE,
422 NULL,
423 0
424 },
425
426 {
427 NtVdmConfigureHDD,
428 0,
429 L"HardDisk3",
430 (PVOID)3,
431 REG_NONE,
432 NULL,
433 0
434 },
435
436 /* End of table */
437 {0}
438 };
439
440 static BOOL
441 LoadGlobalSettings(IN PNTVDM_SETTINGS Settings)
442 {
443 NTSTATUS Status;
444
445 ASSERT(Settings);
446
447 /*
448 * Now we can do:
449 * - CPU core choice
450 * - Video choice
451 * - Sound choice
452 * - Mem?
453 * - ...
454 * - Standalone mode?
455 * - Debug settings
456 */
457 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
458 L"NTVDM",
459 NtVdmConfigurationTable,
460 Settings,
461 NULL);
462 if (!NT_SUCCESS(Status))
463 {
464 DPRINT1("NTVDM registry settings cannot be fully initialized, using default ones. Status = 0x%08lx\n", Status);
465 }
466
467 return NT_SUCCESS(Status);
468 }
469
470 static VOID
471 FreeGlobalSettings(IN PNTVDM_SETTINGS Settings)
472 {
473 USHORT i;
474
475 ASSERT(Settings);
476
477 if (Settings->BiosFileName.Buffer)
478 RtlFreeAnsiString(&Settings->BiosFileName);
479
480 if (Settings->RomFiles.Buffer)
481 RtlFreeAnsiString(&Settings->RomFiles);
482
483 for (i = 0; i < ARRAYSIZE(Settings->HardDisks); ++i)
484 {
485 if (Settings->HardDisks[i].Buffer)
486 RtlFreeAnsiString(&Settings->HardDisks[i]);
487 }
488 }
489
490 /* PUBLIC FUNCTIONS ***********************************************************/
491
492 VOID
493 DisplayMessage(IN LPCWSTR Format, ...)
494 {
495 #ifndef WIN2K_COMPLIANT
496 WCHAR StaticBuffer[256];
497 LPWSTR Buffer = StaticBuffer; // Use the static buffer by default.
498 #else
499 WCHAR Buffer[2048]; // Large enough. If not, increase it by hand.
500 #endif
501 size_t MsgLen;
502 va_list Parameters;
503
504 va_start(Parameters, Format);
505
506 #ifndef WIN2K_COMPLIANT
507 /*
508 * Retrieve the message length and if it is too long, allocate
509 * an auxiliary buffer; otherwise use the static buffer.
510 * The string is built to be NULL-terminated.
511 */
512 MsgLen = _vscwprintf(Format, Parameters);
513 if (MsgLen >= ARRAYSIZE(StaticBuffer))
514 {
515 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, (MsgLen + 1) * sizeof(WCHAR));
516 if (Buffer == NULL)
517 {
518 /* Allocation failed, use the static buffer and display a suitable error message */
519 Buffer = StaticBuffer;
520 Format = L"DisplayMessage()\nOriginal message is too long and allocating an auxiliary buffer failed.";
521 MsgLen = wcslen(Format);
522 }
523 }
524 #else
525 MsgLen = ARRAYSIZE(Buffer) - 1;
526 #endif
527
528 RtlZeroMemory(Buffer, (MsgLen + 1) * sizeof(WCHAR));
529 _vsnwprintf(Buffer, MsgLen, Format, Parameters);
530
531 va_end(Parameters);
532
533 /* Display the message */
534 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer);
535 MessageBoxW(hConsoleWnd, Buffer, L"NTVDM Subsystem", MB_OK);
536
537 #ifndef WIN2K_COMPLIANT
538 /* Free the buffer if needed */
539 if (Buffer != StaticBuffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
540 #endif
541 }
542
543 static VOID
544 ConsoleCleanup(VOID);
545
546 static VOID
547 VdmShutdown(BOOLEAN Immediate)
548 {
549 /*
550 * Immediate = TRUE: Immediate shutdown;
551 * FALSE: Delayed shutdown.
552 */
553 static BOOLEAN MustShutdown = FALSE;
554
555 /* If a shutdown is ongoing, just return */
556 if (MustShutdown)
557 {
558 DPRINT1("Shutdown is ongoing...\n");
559 Sleep(INFINITE);
560 return;
561 }
562
563 /* First notify DOS to see whether we can shut down now */
564 MustShutdown = DosShutdown(Immediate);
565 /*
566 * In case we perform an immediate shutdown, or the DOS says
567 * we can shut down, do it now.
568 */
569 MustShutdown = MustShutdown || Immediate;
570
571 if (MustShutdown)
572 {
573 EmulatorTerminate();
574
575 BiosCleanup();
576 EmulatorCleanup();
577 ConsoleCleanup();
578
579 FreeGlobalSettings(&GlobalSettings);
580
581 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");
582 /* Some VDDs rely on the fact that NTVDM calls ExitProcess on Windows */
583 ExitProcess(0);
584 }
585 }
586
587 static BOOL
588 WINAPI
589 ConsoleCtrlHandler(DWORD ControlType)
590 {
591 switch (ControlType)
592 {
593 case CTRL_LAST_CLOSE_EVENT:
594 {
595 /* Delayed shutdown */
596 DPRINT1("NTVDM delayed killing in the CTRL_LAST_CLOSE_EVENT CtrlHandler!\n");
597 VdmShutdown(FALSE);
598 break;
599 }
600
601 default:
602 {
603 /* Stop the VDM if the user logs out or closes the console */
604 DPRINT1("Killing NTVDM in the 'default' CtrlHandler!\n");
605 VdmShutdown(TRUE);
606 }
607 }
608 return TRUE;
609 }
610
611 static VOID
612 ConsoleInitUI(VOID)
613 {
614 hConsoleWnd = GetConsoleWindow();
615 CreateVdmMenu(ConsoleOutput);
616 }
617
618 static VOID
619 ConsoleCleanupUI(VOID)
620 {
621 /* Display again properly the mouse pointer */
622 if (ShowPointer) ShowHideMousePointer(ConsoleOutput, ShowPointer);
623
624 DestroyVdmMenu();
625 }
626
627 BOOL
628 ConsoleAttach(VOID)
629 {
630 /* Save the original input and output console modes */
631 if (!GetConsoleMode(ConsoleInput , &OrgConsoleInputMode ) ||
632 !GetConsoleMode(ConsoleOutput, &OrgConsoleOutputMode))
633 {
634 CloseHandle(ConsoleOutput);
635 CloseHandle(ConsoleInput);
636 wprintf(L"FATAL: Cannot save console in/out modes\n");
637 return FALSE;
638 }
639
640 /* Set the console input mode */
641 // FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions
642 // upon console window events (screen buffer resize, ...).
643 SetConsoleMode(ConsoleInput, 0 /* | ENABLE_WINDOW_INPUT */);
644 EnableExtraHardware(ConsoleInput);
645
646 /* Set the console output mode */
647 // SetConsoleMode(ConsoleOutput, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
648
649 /* Initialize the UI */
650 ConsoleInitUI();
651
652 return TRUE;
653 }
654
655 VOID
656 ConsoleDetach(VOID)
657 {
658 /* Cleanup the UI */
659 ConsoleCleanupUI();
660
661 /* Restore the original input and output console modes */
662 SetConsoleMode(ConsoleOutput, OrgConsoleOutputMode);
663 SetConsoleMode(ConsoleInput , OrgConsoleInputMode );
664 }
665
666 static BOOL
667 ConsoleInit(VOID)
668 {
669 /* Set the handler routine */
670 SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
671
672 /* Enable the CTRL_LAST_CLOSE_EVENT */
673 SetLastConsoleEventActive();
674
675 /*
676 * NOTE: The CONIN$ and CONOUT$ "virtual" files
677 * always point to non-redirected console handles.
678 */
679
680 /* Get the input handle to the real console, and check for success */
681 ConsoleInput = CreateFileW(L"CONIN$",
682 GENERIC_READ | GENERIC_WRITE,
683 FILE_SHARE_READ | FILE_SHARE_WRITE,
684 NULL,
685 OPEN_EXISTING,
686 0,
687 NULL);
688 if (ConsoleInput == INVALID_HANDLE_VALUE)
689 {
690 wprintf(L"FATAL: Cannot retrieve a handle to the console input\n");
691 return FALSE;
692 }
693
694 /* Get the output handle to the real console, and check for success */
695 ConsoleOutput = CreateFileW(L"CONOUT$",
696 GENERIC_READ | GENERIC_WRITE,
697 FILE_SHARE_READ | FILE_SHARE_WRITE,
698 NULL,
699 OPEN_EXISTING,
700 0,
701 NULL);
702 if (ConsoleOutput == INVALID_HANDLE_VALUE)
703 {
704 CloseHandle(ConsoleInput);
705 wprintf(L"FATAL: Cannot retrieve a handle to the console output\n");
706 return FALSE;
707 }
708
709 /* Effectively attach to the console */
710 return ConsoleAttach();
711 }
712
713 static VOID
714 ConsoleCleanup(VOID)
715 {
716 /* Detach from the console */
717 ConsoleDetach();
718
719 /* Close the console handles */
720 if (ConsoleOutput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleOutput);
721 if (ConsoleInput != INVALID_HANDLE_VALUE) CloseHandle(ConsoleInput);
722 }
723
724 VOID MenuEventHandler(PMENU_EVENT_RECORD MenuEvent)
725 {
726 switch (MenuEvent->dwCommandId)
727 {
728 case ID_SHOWHIDE_MOUSE:
729 ShowHideMousePointer(ConsoleOutput, ShowPointer);
730 ShowPointer = !ShowPointer;
731 break;
732
733 case ID_VDM_DUMPMEM_TXT:
734 DumpMemory(TRUE);
735 break;
736
737 case ID_VDM_DUMPMEM_BIN:
738 DumpMemory(FALSE);
739 break;
740
741 /* Drive 0 -- Mount */
742 /* Drive 1 -- Mount */
743 case ID_VDM_DRIVES + 0:
744 case ID_VDM_DRIVES + 2:
745 {
746 ULONG DiskNumber = (MenuEvent->dwCommandId - ID_VDM_DRIVES) / 2;
747 MountFloppy(DiskNumber);
748 break;
749 }
750
751 /* Drive 0 -- Eject */
752 /* Drive 1 -- Eject */
753 case ID_VDM_DRIVES + 1:
754 case ID_VDM_DRIVES + 3:
755 {
756 ULONG DiskNumber = (MenuEvent->dwCommandId - ID_VDM_DRIVES - 1) / 2;
757 EjectFloppy(DiskNumber);
758 break;
759 }
760
761 case ID_VDM_QUIT:
762 /* Stop the VDM */
763 // EmulatorTerminate();
764
765 /* Nothing runs, so exit immediately */
766 DPRINT1("Killing NTVDM via console menu!\n");
767 VdmShutdown(TRUE);
768 break;
769
770 default:
771 break;
772 }
773 }
774
775 VOID FocusEventHandler(PFOCUS_EVENT_RECORD FocusEvent)
776 {
777 DPRINT1("Focus events not handled\n");
778 }
779
780
781 INT
782 wmain(INT argc, WCHAR *argv[])
783 {
784 NtVdmArgc = argc;
785 NtVdmArgv = argv;
786
787 #ifdef STANDALONE
788
789 if (argc < 2)
790 {
791 wprintf(L"\nReactOS Virtual DOS Machine\n\n"
792 L"Usage: NTVDM <executable> [<parameters>]\n");
793 return 0;
794 }
795
796 #endif
797
798 #ifdef ADVANCED_DEBUGGING
799 {
800 INT i = 20;
801
802 printf("Waiting for debugger (10 secs)..");
803 while (i--)
804 {
805 printf(".");
806 if (IsDebuggerPresent())
807 {
808 DbgBreakPoint();
809 break;
810 }
811 Sleep(500);
812 }
813 printf("Continue\n");
814 }
815 #endif
816
817 /* Load global VDM settings */
818 LoadGlobalSettings(&GlobalSettings);
819
820 DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
821
822 /* Initialize the console */
823 if (!ConsoleInit())
824 {
825 wprintf(L"FATAL: A problem occurred when trying to initialize the console\n");
826 goto Cleanup;
827 }
828
829 /* Initialize the emulator */
830 if (!EmulatorInitialize(ConsoleInput, ConsoleOutput))
831 {
832 wprintf(L"FATAL: Failed to initialize the emulator\n");
833 goto Cleanup;
834 }
835
836 /* Initialize the system BIOS and option ROMs */
837 if (!BiosInitialize(GlobalSettings.BiosFileName.Buffer,
838 GlobalSettings.RomFiles.Buffer))
839 {
840 wprintf(L"FATAL: Failed to initialize the VDM BIOS.\n");
841 goto Cleanup;
842 }
843
844 /* Let's go! Start simulation */
845 CpuSimulate();
846
847 /* Quit the VDM */
848 Cleanup:
849 VdmShutdown(TRUE);
850 return 0;
851 }
852
853 /* EOF */