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