* added _DISABLE_TIDENTS macro to disable any ANSI/UNICODE ambiguous elements from...
[reactos.git] / reactos / subsys / ntvdm / ntvdm.c
1 /* $Id: ntvdm.c,v 1.3 2003/08/07 04:03:24 royce Exp $
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 }