reactos/subsystems/ntvdm/ntvdm.c

376 lines
9.8 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: subsys/ntvdm/ntvdm->c
* PURPOSE: Virtual DOS Machine
* PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com)
* UPDATE HISTORY:
* Created 23/10/2002
*/
/* INCLUDES *****************************************************************/
#include <stdarg.h>
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <wincon.h>
#include <winuser.h>
#include <stdio.h>
#include "resource.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
/* FUNCTIONS *****************************************************************/
void PrintString(char* fmt,...)
{
char buffer[512];
va_list ap;
va_start(ap, fmt);
vsprintf(buffer, fmt, ap);
va_end(ap);
OutputDebugStringA(buffer);
}
/*
GetVersion
GetVolumeInformationW
GetWindowsDirectoryA
GlobalMemoryStatus
HeapAlloc
HeapCreate
HeapDestroy
HeapFree
HeapReAlloc
GetNextVDMCommand
ExitVDM
RegisterConsoleVDM
SetVDMCurrentDirectories
VDMConsoleOperation
WriteConsoleInputVDMW
NtSetLdtEntries
NtTerminateProcess
NtMapViewOfSection
NtUnmapViewOfSection
NtVdmControl
*/
typedef struct tag_VDM_CONFIG {
int dos_options;
int files;
int buffers;
WCHAR** device_list;
//dos=high, umb
//device=%SystemRoot%\system32\himem.sys
//files=40
} VDM_CONFIG, *PVDM_CONFIG;
typedef struct tag_VDM_AUTOEXEC {
WCHAR** load_list;
//lh %SystemRoot%\system32\mscdexnt.exe
//lh %SystemRoot%\system32\redir
//lh %SystemRoot%\system32\dosx
} VDM_AUTOEXEC, *PVDM_AUTOEXEC;
typedef struct tag_VDM_CONTROL_BLOCK {
HANDLE hHeap;
PVOID ImageMem;
VDM_CONFIG vdmConfig;
VDM_AUTOEXEC vdmAutoexec;
PROCESS_INFORMATION ProcessInformation;
CHAR CommandLine[MAX_PATH];
CHAR CurrentDirectory[MAX_PATH];
} VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
BOOL
StartVDM(PVDM_CONTROL_BLOCK vdm)
{
BOOL Result;
STARTUPINFOA StartupInfo;
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.lpReserved = NULL;
StartupInfo.lpDesktop = NULL;
StartupInfo.lpTitle = NULL;
StartupInfo.dwFlags = 0;
StartupInfo.cbReserved2 = 0;
StartupInfo.lpReserved2 = 0;
Result = CreateProcessA(vdm->CommandLine,
NULL,
NULL,
NULL,
FALSE,
DETACHED_PROCESS,
NULL,
NULL,
&StartupInfo,
&vdm->ProcessInformation);
if (!Result) {
PrintString("VDM: Failed to execute target process\n");
return FALSE;
}
WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
CloseHandle(vdm->ProcessInformation.hProcess);
CloseHandle(vdm->ProcessInformation.hThread);
return TRUE;
}
BOOL
ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
{
BOOL result = TRUE;
return result;
}
BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
{
BOOL result = TRUE;
DWORD dwError;
HANDLE hFile;
hFile = CreateFileW(L"\\system32\\config.nt",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS /*OPEN_EXISTING*/,
FILE_ATTRIBUTE_NORMAL,
0);
dwError = GetLastError();
if (hFile == INVALID_HANDLE_VALUE) {
// error with file path or system problem?
} else {
if (dwError == 0L) {
// we just created a new file, perhaps we should set/write some defaults?
}
if (dwError == ERROR_ALREADY_EXISTS) {
// read the line entries and cache in some struct...
}
CloseHandle(hFile);
}
hFile = CreateFileW(L"\\system32\\autoexec.nt",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
dwError = GetLastError();
if (hFile == INVALID_HANDLE_VALUE) {
// error with file path or system problem?
} else {
if (dwError == 0L) {
// we just created a new file, perhaps we should set/write some defaults?
}
if (dwError == ERROR_ALREADY_EXISTS) {
// read the line entries and cache in some struct...
}
CloseHandle(hFile);
}
return result;
}
BOOL
LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
{
BOOL result = TRUE;
return result;
}
BOOL
SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
{
BOOL result = TRUE;
return result;
}
BOOL
CreateVDM(PVDM_CONTROL_BLOCK vdm)
{
// BOOL result = TRUE;
SYSTEM_INFO inf;
MEMORYSTATUS stat;
GlobalMemoryStatus(&stat);
if (stat.dwLength != sizeof(MEMORYSTATUS)) {
printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
} else {
printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
#define OUT_OF_HEADROOM 90
if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
DPRINT("VDM: system resources deemed to low to start VDM.\n");
//SetLastError();
return FALSE;
}
}
GetSystemInfo(&inf);
vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
if (vdm->hHeap == NULL) {
DPRINT("VDM: failed to create heap.\n");
return FALSE;
}
#define DEFAULT_VDM_IMAGE_SIZE 2000000
vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
if (vdm->ImageMem == NULL) {
DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
HeapDestroy(vdm->hHeap);
vdm->hHeap = NULL;
return FALSE;
}
return TRUE;
}
BOOL
DestroyVDM(PVDM_CONTROL_BLOCK vdm)
{
BOOL result = TRUE;
if (vdm->ImageMem != NULL) {
if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
result = FALSE;
}
vdm->ImageMem = NULL;
}
if (vdm->hHeap != NULL) {
if (!HeapDestroy(vdm->hHeap)) {
DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
result = FALSE;
}
vdm->hHeap = NULL;
}
return result;
}
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
VDM_CONTROL_BLOCK VdmCB;
DWORD Result;
ULONG i;
BOOL vdmStarted = FALSE;
WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
WCHAR PromptMsg[RC_STRING_MAX_SIZE];
CHAR InputBuffer[255];
LoadStringW( GetModuleHandle(NULL), STRING_WelcomeMsg, WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
LoadStringW( GetModuleHandle(NULL), STRING_PromptMsg, PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
AllocConsole();
SetConsoleTitleW(L"ntvdm");
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg),
&Result, NULL);
if (!CreateVDM(&VdmCB)) {
DPRINT("VDM: failed to create VDM.\n");
//SetLastError();
return 2;
}
ReadConfigForVDM(&VdmCB);
if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
DPRINT("VDM: failed to load configuration drivers.\n");
//SetLastError();
return 2;
}
if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
DPRINT("VDM: failed to set configuration options.\n");
//SetLastError();
return 3;
}
GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
strcat(VdmCB.CommandLine, "\\hello.exe");
GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
for (;;) {
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg),
&Result, NULL);
i = 0;
do {
ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
&InputBuffer[i], 1,
&Result, NULL);
if (++i >= (sizeof(InputBuffer) - 1)) {
break;
}
} while (InputBuffer[i - 1] != '\n');
InputBuffer[i - 1] = '\0';
if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
if (!vdmStarted) {
if (StartVDM(&VdmCB)) {
vdmStarted = TRUE;
} else {
DPRINT("VDM: failed to start.\n");
}
} else {
DPRINT("VDM: already started.\n");
}
}
if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
if (vdmStarted) {
if (ShutdownVDM(&VdmCB)) {
vdmStarted = FALSE;
} else {
DPRINT("VDM: failed to shutdown.\n");
}
} else {
DPRINT("VDM: not started.\n");
}
}
if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
break;
}
}
if (!ShutdownVDM(&VdmCB)) {
DPRINT("VDM: failed to cleanly shutdown VDM.\n");
//SetLastError();
return 5;
}
if (!DestroyVDM(&VdmCB)) {
DPRINT("VDM: failed to cleanly destroy VDM.\n");
//SetLastError();
return 6;
}
ExitProcess(0);
return 0;
}