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>
9 /* INCLUDES *******************************************************************/
18 #include "bios/bios.h"
23 /* VARIABLES ******************************************************************/
25 NTVDM_SETTINGS GlobalSettings
;
27 // Command line of NTVDM
31 /* PRIVATE FUNCTIONS **********************************************************/
35 NtVdmConfigureBios(IN PWSTR ValueName
,
40 IN PVOID EntryContext
)
42 PNTVDM_SETTINGS Settings
= (PNTVDM_SETTINGS
)Context
;
43 UNICODE_STRING ValueString
;
45 /* Check for the type of the value */
46 if (ValueType
!= REG_SZ
)
48 RtlInitEmptyAnsiString(&Settings
->BiosFileName
, NULL
, 0);
49 return STATUS_SUCCESS
;
52 /* Convert the UNICODE string to ANSI and store it */
53 RtlInitEmptyUnicodeString(&ValueString
, (PWCHAR
)ValueData
, ValueLength
);
54 ValueString
.Length
= ValueString
.MaximumLength
;
55 RtlUnicodeStringToAnsiString(&Settings
->BiosFileName
, &ValueString
, TRUE
);
57 return STATUS_SUCCESS
;
62 NtVdmConfigureRom(IN PWSTR ValueName
,
67 IN PVOID EntryContext
)
69 PNTVDM_SETTINGS Settings
= (PNTVDM_SETTINGS
)Context
;
70 UNICODE_STRING ValueString
;
72 /* Check for the type of the value */
73 if (ValueType
!= REG_MULTI_SZ
)
75 RtlInitEmptyAnsiString(&Settings
->RomFiles
, NULL
, 0);
76 return STATUS_SUCCESS
;
79 /* Convert the UNICODE string to ANSI and store it */
80 RtlInitEmptyUnicodeString(&ValueString
, (PWCHAR
)ValueData
, ValueLength
);
81 ValueString
.Length
= ValueString
.MaximumLength
;
82 RtlUnicodeStringToAnsiString(&Settings
->RomFiles
, &ValueString
, TRUE
);
84 return STATUS_SUCCESS
;
89 NtVdmConfigureFloppy(IN PWSTR ValueName
,
94 IN PVOID EntryContext
)
97 PNTVDM_SETTINGS Settings
= (PNTVDM_SETTINGS
)Context
;
98 ULONG DiskNumber
= (ULONG
)EntryContext
;
100 ASSERT(DiskNumber
< ARRAYSIZE(Settings
->FloppyDisks
));
102 /* Check whether the Hard Disk entry was not already configured */
103 if (Settings
->FloppyDisks
[DiskNumber
].Buffer
!= NULL
)
105 DPRINT1("Floppy Disk %d -- '%wZ' already configured\n", DiskNumber
, &Settings
->FloppyDisks
[DiskNumber
]);
106 return STATUS_SUCCESS
;
109 /* Check for the type of the value */
110 if (ValueType
!= REG_SZ
)
112 RtlInitEmptyUnicodeString(&Settings
->FloppyDisks
[DiskNumber
], NULL
, 0);
113 return STATUS_SUCCESS
;
116 /* Initialize the string */
117 Success
= RtlCreateUnicodeString(&Settings
->FloppyDisks
[DiskNumber
], (PCWSTR
)ValueData
);
120 return STATUS_SUCCESS
;
125 NtVdmConfigureHDD(IN PWSTR ValueName
,
128 IN ULONG ValueLength
,
130 IN PVOID EntryContext
)
133 PNTVDM_SETTINGS Settings
= (PNTVDM_SETTINGS
)Context
;
134 ULONG DiskNumber
= (ULONG
)EntryContext
;
136 ASSERT(DiskNumber
< ARRAYSIZE(Settings
->HardDisks
));
138 /* Check whether the Hard Disk entry was not already configured */
139 if (Settings
->HardDisks
[DiskNumber
].Buffer
!= NULL
)
141 DPRINT1("Hard Disk %d -- '%wZ' already configured\n", DiskNumber
, &Settings
->HardDisks
[DiskNumber
]);
142 return STATUS_SUCCESS
;
145 /* Check for the type of the value */
146 if (ValueType
!= REG_SZ
)
148 RtlInitEmptyUnicodeString(&Settings
->HardDisks
[DiskNumber
], NULL
, 0);
149 return STATUS_SUCCESS
;
152 /* Initialize the string */
153 Success
= RtlCreateUnicodeString(&Settings
->HardDisks
[DiskNumber
], (PCWSTR
)ValueData
);
156 return STATUS_SUCCESS
;
159 static RTL_QUERY_REGISTRY_TABLE
160 NtVdmConfigurationTable
[] =
174 RTL_QUERY_REGISTRY_NOEXPAND
,
183 NtVdmConfigureFloppy
,
193 NtVdmConfigureFloppy
,
247 LoadGlobalSettings(IN PNTVDM_SETTINGS Settings
)
263 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
265 NtVdmConfigurationTable
,
268 if (!NT_SUCCESS(Status
))
270 DPRINT1("NTVDM registry settings cannot be fully initialized, using default ones. Status = 0x%08lx\n", Status
);
273 return NT_SUCCESS(Status
);
277 FreeGlobalSettings(IN PNTVDM_SETTINGS Settings
)
283 if (Settings
->BiosFileName
.Buffer
)
284 RtlFreeAnsiString(&Settings
->BiosFileName
);
286 if (Settings
->RomFiles
.Buffer
)
287 RtlFreeAnsiString(&Settings
->RomFiles
);
289 for (i
= 0; i
< ARRAYSIZE(Settings
->FloppyDisks
); ++i
)
291 if (Settings
->FloppyDisks
[i
].Buffer
)
292 RtlFreeUnicodeString(&Settings
->FloppyDisks
[i
]);
295 for (i
= 0; i
< ARRAYSIZE(Settings
->HardDisks
); ++i
)
297 if (Settings
->HardDisks
[i
].Buffer
)
298 RtlFreeUnicodeString(&Settings
->HardDisks
[i
]);
303 ConsoleCleanup(VOID
);
306 #include "./console/console.c"
310 VdmShutdown(BOOLEAN Immediate
)
313 * Immediate = TRUE: Immediate shutdown;
314 * FALSE: Delayed shutdown.
316 static BOOLEAN MustShutdown
= FALSE
;
318 /* If a shutdown is ongoing, just return */
321 DPRINT1("Shutdown is ongoing...\n");
326 /* First notify DOS to see whether we can shut down now */
327 MustShutdown
= DosShutdown(Immediate
);
329 * In case we perform an immediate shutdown, or the DOS says
330 * we can shut down, do it now.
332 MustShutdown
= MustShutdown
|| Immediate
;
342 FreeGlobalSettings(&GlobalSettings
);
344 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");
345 /* Some VDDs rely on the fact that NTVDM calls ExitProcess on Windows */
350 /* PUBLIC FUNCTIONS ***********************************************************/
353 DisplayMessage(IN LPCWSTR Format
, ...)
355 #ifndef WIN2K_COMPLIANT
356 WCHAR StaticBuffer
[256];
357 LPWSTR Buffer
= StaticBuffer
; // Use the static buffer by default.
359 WCHAR Buffer
[2048]; // Large enough. If not, increase it by hand.
364 va_start(args
, Format
);
366 #ifndef WIN2K_COMPLIANT
368 * Retrieve the message length and if it is too long, allocate
369 * an auxiliary buffer; otherwise use the static buffer.
370 * The string is built to be NULL-terminated.
372 MsgLen
= _vscwprintf(Format
, args
);
373 if (MsgLen
>= ARRAYSIZE(StaticBuffer
))
375 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, (MsgLen
+ 1) * sizeof(WCHAR
));
378 /* Allocation failed, use the static buffer and display a suitable error message */
379 Buffer
= StaticBuffer
;
380 Format
= L
"DisplayMessage()\nOriginal message is too long and allocating an auxiliary buffer failed.";
381 MsgLen
= wcslen(Format
);
385 MsgLen
= ARRAYSIZE(Buffer
) - 1;
388 RtlZeroMemory(Buffer
, (MsgLen
+ 1) * sizeof(WCHAR
));
389 _vsnwprintf(Buffer
, MsgLen
, Format
, args
);
393 /* Display the message */
394 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
395 MessageBoxW(hConsoleWnd
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
397 #ifndef WIN2K_COMPLIANT
398 /* Free the buffer if needed */
399 if (Buffer
!= StaticBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
404 * This function, derived from DisplayMessage, is used by the BIOS and
405 * the DOS to display messages to an output device. A printer function
406 * is given for printing the characters.
409 PrintMessageAnsi(IN CHAR_PRINT CharPrint
,
410 IN LPCSTR Format
, ...)
412 static CHAR CurChar
= 0;
415 #ifndef WIN2K_COMPLIANT
416 CHAR StaticBuffer
[256];
417 LPSTR Buffer
= StaticBuffer
; // Use the static buffer by default.
419 CHAR Buffer
[2048]; // Large enough. If not, increase it by hand.
424 va_start(args
, Format
);
426 #ifndef WIN2K_COMPLIANT
428 * Retrieve the message length and if it is too long, allocate
429 * an auxiliary buffer; otherwise use the static buffer.
430 * The string is built to be NULL-terminated.
432 MsgLen
= _vscprintf(Format
, args
);
433 if (MsgLen
>= ARRAYSIZE(StaticBuffer
))
435 Buffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, (MsgLen
+ 1) * sizeof(CHAR
));
438 /* Allocation failed, use the static buffer and display a suitable error message */
439 Buffer
= StaticBuffer
;
440 Format
= "DisplayMessageAnsi()\nOriginal message is too long and allocating an auxiliary buffer failed.";
441 MsgLen
= strlen(Format
);
445 MsgLen
= ARRAYSIZE(Buffer
) - 1;
448 RtlZeroMemory(Buffer
, (MsgLen
+ 1) * sizeof(CHAR
));
449 _vsnprintf(Buffer
, MsgLen
, Format
, args
);
453 /* Display the message */
454 // DPRINT1("\n\nNTVDM DOS32\n%s\n\n", Buffer);
456 MsgLen
= strlen(Buffer
);
460 if (*str
== '\n' && CurChar
!= '\r')
467 #ifndef WIN2K_COMPLIANT
468 /* Free the buffer if needed */
469 if (Buffer
!= StaticBuffer
) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer
);
474 wmain(INT argc
, WCHAR
*argv
[])
483 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
484 L
"Usage: NTVDM <executable> [<parameters>]\n");
490 #ifdef ADVANCED_DEBUGGING
494 printf("Waiting for debugger (10 secs)..");
498 if (IsDebuggerPresent())
505 printf("Continue\n");
509 /* Load the global VDM settings */
510 LoadGlobalSettings(&GlobalSettings
);
512 DPRINT1("\n\n\nNTVDM - Starting...\n\n\n");
514 /* Initialize the console */
517 wprintf(L
"FATAL: A problem occurred when trying to initialize the console\n");
521 /* Initialize the emulator */
522 if (!EmulatorInitialize(ConsoleInput
, ConsoleOutput
))
524 wprintf(L
"FATAL: Failed to initialize the emulator\n");
528 /* Initialize the system BIOS and option ROMs */
529 if (!BiosInitialize(GlobalSettings
.BiosFileName
.Buffer
,
530 GlobalSettings
.RomFiles
.Buffer
))
532 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
536 /* Let's go! Start simulation */