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