362e629585c36878bed897d0f9c5d3435c22d999
[reactos.git] / reactos / subsys / ntvdm / ntvdm.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: subsys/ntvdm/ntvdm->c
6 * PURPOSE: Virtual DOS Machine
7 * PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com)
8 * UPDATE HISTORY:
9 * Created 23/10/2002
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntos.h>
15 #include <windows.h>
16 #include <stdio.h>
17 #include <wchar.h>
18 #include "resource.h"
19
20 #define NDEBUG
21 #include <debug.h>
22
23 /* GLOBALS ******************************************************************/
24
25
26 /* FUNCTIONS *****************************************************************/
27
28 void PrintString(char* fmt,...)
29 {
30 char buffer[512];
31 va_list ap;
32
33 va_start(ap, fmt);
34 vsprintf(buffer, fmt, ap);
35 va_end(ap);
36
37 OutputDebugStringA(buffer);
38 }
39
40 /*
41 GetVersion
42 GetVolumeInformationW
43 GetWindowsDirectoryA
44 GlobalMemoryStatus
45 HeapAlloc
46 HeapCreate
47 HeapDestroy
48 HeapFree
49 HeapReAlloc
50
51 GetNextVDMCommand
52 ExitVDM
53 RegisterConsoleVDM
54 SetVDMCurrentDirectories
55 VDMConsoleOperation
56 WriteConsoleInputVDMW
57
58 NtSetLdtEntries
59 NtTerminateProcess
60
61 NtMapViewOfSection
62 NtUnmapViewOfSection
63
64 NtVdmControl
65 */
66 typedef struct tag_VDM_CONFIG {
67 int dos_options;
68 int files;
69 int buffers;
70 WCHAR** device_list;
71 //dos=high, umb
72 //device=%SystemRoot%\system32\himem.sys
73 //files=40
74 } VDM_CONFIG, *PVDM_CONFIG;
75
76 typedef struct tag_VDM_AUTOEXEC {
77 WCHAR** load_list;
78 //lh %SystemRoot%\system32\mscdexnt.exe
79 //lh %SystemRoot%\system32\redir
80 //lh %SystemRoot%\system32\dosx
81 } VDM_AUTOEXEC, *PVDM_AUTOEXEC;
82
83 typedef struct tag_VDM_CONTROL_BLOCK {
84 HANDLE hHeap;
85 PVOID ImageMem;
86 VDM_CONFIG vdmConfig;
87 VDM_AUTOEXEC vdmAutoexec;
88 PROCESS_INFORMATION ProcessInformation;
89 CHAR CommandLine[MAX_PATH];
90 CHAR CurrentDirectory[MAX_PATH];
91
92 } VDM_CONTROL_BLOCK, *PVDM_CONTROL_BLOCK;
93
94
95 BOOL
96 StartVDM(PVDM_CONTROL_BLOCK vdm)
97 {
98 BOOL Result;
99 STARTUPINFOA StartupInfo;
100
101 StartupInfo.cb = sizeof(StartupInfo);
102 StartupInfo.lpReserved = NULL;
103 StartupInfo.lpDesktop = NULL;
104 StartupInfo.lpTitle = NULL;
105 StartupInfo.dwFlags = 0;
106 StartupInfo.cbReserved2 = 0;
107 StartupInfo.lpReserved2 = 0;
108
109 Result = CreateProcessA(vdm->CommandLine,
110 NULL,
111 NULL,
112 NULL,
113 FALSE,
114 DETACHED_PROCESS,
115 NULL,
116 NULL,
117 &StartupInfo,
118 &vdm->ProcessInformation);
119 if (!Result) {
120 PrintString("VDM: Failed to execute target process\n");
121 return FALSE;
122 }
123 WaitForSingleObject(vdm->ProcessInformation.hProcess, INFINITE);
124 CloseHandle(vdm->ProcessInformation.hProcess);
125 CloseHandle(vdm->ProcessInformation.hThread);
126 return TRUE;
127 }
128
129 BOOL
130 ShutdownVDM(PVDM_CONTROL_BLOCK vdm)
131 {
132 BOOL result = TRUE;
133
134 return result;
135 }
136
137 BOOL ReadConfigForVDM(PVDM_CONTROL_BLOCK vdm)
138 {
139 BOOL result = TRUE;
140 DWORD dwError;
141 HANDLE hFile;
142
143 hFile = CreateFileW(L"\\system32\\config.nt",
144 GENERIC_READ,
145 FILE_SHARE_READ,
146 NULL,
147 OPEN_ALWAYS /*OPEN_EXISTING*/,
148 FILE_ATTRIBUTE_NORMAL,
149 0);
150 dwError = GetLastError();
151 if (hFile == INVALID_HANDLE_VALUE) {
152 // error with file path or system problem?
153 } else {
154 if (dwError == 0L) {
155 // we just created a new file, perhaps we should set/write some defaults?
156 }
157 if (dwError == ERROR_ALREADY_EXISTS) {
158 // read the line entries and cache in some struct...
159 }
160 CloseHandle(hFile);
161 }
162
163 hFile = CreateFileW(L"\\system32\\autoexec.nt",
164 GENERIC_READ,
165 FILE_SHARE_READ,
166 NULL,
167 OPEN_ALWAYS,
168 FILE_ATTRIBUTE_NORMAL,
169 0);
170 dwError = GetLastError();
171 if (hFile == INVALID_HANDLE_VALUE) {
172 // error with file path or system problem?
173 } else {
174 if (dwError == 0L) {
175 // we just created a new file, perhaps we should set/write some defaults?
176 }
177 if (dwError == ERROR_ALREADY_EXISTS) {
178 // read the line entries and cache in some struct...
179 }
180 CloseHandle(hFile);
181 }
182
183 return result;
184 }
185
186 BOOL
187 LoadConfigDriversForVDM(PVDM_CONFIG vdmConfig)
188 {
189 BOOL result = TRUE;
190
191 return result;
192 }
193
194 BOOL
195 SetConfigOptionsForVDM(PVDM_AUTOEXEC vdmAutoexec)
196 {
197 BOOL result = TRUE;
198
199 return result;
200 }
201
202 BOOL
203 CreateVDM(PVDM_CONTROL_BLOCK vdm)
204 {
205 // BOOL result = TRUE;
206 SYSTEM_INFO inf;
207 MEMORYSTATUS stat;
208
209
210 GlobalMemoryStatus(&stat);
211 if (stat.dwLength != sizeof(MEMORYSTATUS)) {
212 printf("WARNING: GlobalMemoryStatus() returned unknown structure version, size %ld, expected %d.\n", stat.dwLength, sizeof(stat));
213 } else {
214 printf("Memory Load: %ld percent in use.\n", stat.dwMemoryLoad);
215 printf("\t%ld total bytes physical memory.\n", stat.dwTotalPhys);
216 printf("\t%ld available physical memory.\n", stat.dwAvailPhys);
217 printf("\t%ld total bytes paging file.\n", stat.dwTotalPageFile);
218 printf("\t%ld available paging file.\n", stat.dwAvailPageFile);
219 printf("\t%lx total bytes virtual memory.\n", stat.dwTotalVirtual);
220 printf("\t%lx available bytes virtual memory.\n", stat.dwAvailVirtual);
221
222 #define OUT_OF_HEADROOM 90
223 if (stat.dwMemoryLoad > OUT_OF_HEADROOM) {
224 DPRINT("VDM: system resources deemed to low to start VDM.\n");
225 //SetLastError();
226 return FALSE;
227 }
228
229 }
230
231 GetSystemInfo(&inf);
232 vdm->hHeap = HeapCreate(0, inf.dwAllocationGranularity, 0);
233 if (vdm->hHeap == NULL) {
234 DPRINT("VDM: failed to create heap.\n");
235 return FALSE;
236 }
237
238 #define DEFAULT_VDM_IMAGE_SIZE 2000000
239 vdm->ImageMem = HeapAlloc(vdm->hHeap, 0, DEFAULT_VDM_IMAGE_SIZE);
240 if (vdm->ImageMem == NULL) {
241 DPRINT("VDM: failed to allocate image memory from heap %x.\n", vdm->hHeap);
242 HeapDestroy(vdm->hHeap);
243 vdm->hHeap = NULL;
244 return FALSE;
245 }
246 return TRUE;
247 }
248
249 BOOL
250 DestroyVDM(PVDM_CONTROL_BLOCK vdm)
251 {
252 BOOL result = TRUE;
253
254 if (vdm->ImageMem != NULL) {
255 if (HeapFree(vdm->hHeap, 0, vdm->ImageMem) != FALSE) {
256 DPRINT("VDM: failed to free memory from heap %x.\n", vdm->hHeap);
257 result = FALSE;
258 }
259 vdm->ImageMem = NULL;
260 }
261 if (vdm->hHeap != NULL) {
262 if (!HeapDestroy(vdm->hHeap)) {
263 DPRINT("VDM: failed to destroy heap %x.\n", vdm->hHeap);
264 result = FALSE;
265 }
266 vdm->hHeap = NULL;
267 }
268 return result;
269 }
270
271 int STDCALL
272 WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
273 {
274 VDM_CONTROL_BLOCK VdmCB;
275 DWORD Result;
276 ULONG i;
277 BOOL vdmStarted = FALSE;
278
279 WCHAR WelcomeMsg[RC_STRING_MAX_SIZE];
280 WCHAR PromptMsg[RC_STRING_MAX_SIZE];
281 CHAR InputBuffer[255];
282
283 LoadString( GetModuleHandle(NULL), STRING_WelcomeMsg, (LPTSTR) WelcomeMsg,sizeof(WelcomeMsg) / sizeof(WelcomeMsg[0]));
284 LoadString( GetModuleHandle(NULL), STRING_PromptMsg, (LPTSTR) PromptMsg ,sizeof(PromptMsg) / sizeof(PromptMsg[0]));
285
286 AllocConsole();
287 SetConsoleTitleW(L"ntvdm");
288
289 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
290 WelcomeMsg, lstrlenW(WelcomeMsg), // wcslen(WelcomeMsg),
291 &Result, NULL);
292
293 if (!CreateVDM(&VdmCB)) {
294 DPRINT("VDM: failed to create VDM.\n");
295 //SetLastError();
296 return 2;
297 }
298
299 ReadConfigForVDM(&VdmCB);
300
301 if (!LoadConfigDriversForVDM(&(VdmCB.vdmConfig))) {
302 DPRINT("VDM: failed to load configuration drivers.\n");
303 //SetLastError();
304 return 2;
305 }
306 if (!SetConfigOptionsForVDM(&(VdmCB.vdmAutoexec))) {
307 DPRINT("VDM: failed to set configuration options.\n");
308 //SetLastError();
309 return 3;
310 }
311
312 GetSystemDirectoryA(VdmCB.CommandLine, MAX_PATH);
313 strcat(VdmCB.CommandLine, "\\hello.exe");
314 GetWindowsDirectoryA(VdmCB.CurrentDirectory, MAX_PATH);
315
316 for (;;) {
317 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
318 PromptMsg, lstrlenW(PromptMsg), // wcslen(PromptMsg),
319 &Result, NULL);
320 i = 0;
321 do {
322 ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),
323 &InputBuffer[i], 1,
324 &Result, NULL);
325 if (++i >= (sizeof(InputBuffer) - 1)) {
326 break;
327 }
328 } while (InputBuffer[i - 1] != '\n');
329 InputBuffer[i - 1] = '\0';
330
331 if (InputBuffer[0] == 'r' || InputBuffer[0] == 'R') {
332 if (!vdmStarted) {
333 if (StartVDM(&VdmCB)) {
334 vdmStarted = TRUE;
335 } else {
336 DPRINT("VDM: failed to start.\n");
337 }
338 } else {
339 DPRINT("VDM: already started.\n");
340 }
341 }
342 if (InputBuffer[0] == 's' || InputBuffer[0] == 'S') {
343 if (vdmStarted) {
344 if (ShutdownVDM(&VdmCB)) {
345 vdmStarted = FALSE;
346 } else {
347 DPRINT("VDM: failed to shutdown.\n");
348 }
349 } else {
350 DPRINT("VDM: not started.\n");
351 }
352 }
353 if (InputBuffer[0] == 'q' || InputBuffer[0] == 'Q') {
354 break;
355 }
356 }
357
358 if (!ShutdownVDM(&VdmCB)) {
359 DPRINT("VDM: failed to cleanly shutdown VDM.\n");
360 //SetLastError();
361 return 5;
362 }
363
364 if (!DestroyVDM(&VdmCB)) {
365 DPRINT("VDM: failed to cleanly destroy VDM.\n");
366 //SetLastError();
367 return 6;
368 }
369
370 ExitProcess(0);
371 return 0;
372 }