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