/* * 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 #define WIN32_NO_STATUS #include #include #include #include #include #include "resource.h" #define NDEBUG #include /* 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; }