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