[KERNEL32]: Implement Wow64Enable/Disable/RevertWow64Direction, document the Rtl...
[reactos.git] / reactos / dll / win32 / kernel32 / client / vdm.c
1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/client/vdm.c
5 * PURPOSE: Virtual Dos Machine (VDM) Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <k32.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* TYPES **********************************************************************/
17
18 /* FUNCTIONS ******************************************************************/
19
20
21 /* Check whether a file is an OS/2 or a very old Windows executable
22 * by testing on import of KERNEL.
23 *
24 * FIXME: is reading the module imports the only way of discerning
25 * old Windows binaries from OS/2 ones ? At least it seems so...
26 */
27 static DWORD WINAPI
28 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
29 {
30 DWORD CurPos;
31 LPWORD modtab = NULL;
32 LPSTR nametab = NULL;
33 DWORD Read, Ret;
34 int i;
35
36 Ret = BINARY_OS216;
37 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
38
39 /* read modref table */
40 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
41 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) ||
42 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) ||
43 (Read != (DWORD)ne->ne_cmod * sizeof(WORD)))
44 {
45 goto broken;
46 }
47
48 /* read imported names table */
49 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
50 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) ||
51 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) ||
52 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab))
53 {
54 goto broken;
55 }
56
57 for(i = 0; i < ne->ne_cmod; i++)
58 {
59 LPSTR module;
60 module = &nametab[modtab[i]];
61 if(!strncmp(&module[1], "KERNEL", module[0]))
62 {
63 /* very old windows file */
64 Ret = BINARY_WIN16;
65 goto done;
66 }
67 }
68
69 broken:
70 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
71
72 done:
73 HeapFree(GetProcessHeap(), 0, modtab);
74 HeapFree(GetProcessHeap(), 0, nametab);
75 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN);
76 return Ret;
77 }
78
79 static DWORD WINAPI
80 InternalGetBinaryType(HANDLE hFile)
81 {
82 union
83 {
84 struct
85 {
86 unsigned char magic[4];
87 unsigned char ignored[12];
88 unsigned short type;
89 } elf;
90 struct
91 {
92 unsigned long magic;
93 unsigned long cputype;
94 unsigned long cpusubtype;
95 unsigned long filetype;
96 } macho;
97 IMAGE_DOS_HEADER mz;
98 } Header;
99 char magic[4];
100 DWORD Read;
101
102 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
103 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) ||
104 (Read != sizeof(Header))))
105 {
106 return BINARY_UNKNOWN;
107 }
108
109 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic)))
110 {
111 /* FIXME: we don't bother to check byte order, architecture, etc. */
112 switch(Header.elf.type)
113 {
114 case 2:
115 return BINARY_UNIX_EXE;
116 case 3:
117 return BINARY_UNIX_LIB;
118 }
119 return BINARY_UNKNOWN;
120 }
121
122 /* Mach-o File with Endian set to Big Endian or Little Endian*/
123 if(Header.macho.magic == 0xFEEDFACE ||
124 Header.macho.magic == 0xCEFAEDFE)
125 {
126 switch(Header.macho.filetype)
127 {
128 case 0x8:
129 /* MH_BUNDLE */
130 return BINARY_UNIX_LIB;
131 }
132 return BINARY_UNKNOWN;
133 }
134
135 /* Not ELF, try DOS */
136 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE)
137 {
138 /* We do have a DOS image so we will now try to seek into
139 * the file by the amount indicated by the field
140 * "Offset to extended header" and read in the
141 * "magic" field information at that location.
142 * This will tell us if there is more header information
143 * to read or not.
144 */
145 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
146 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) ||
147 (Read != sizeof(magic))))
148 {
149 return BINARY_DOS;
150 }
151
152 /* Reading the magic field succeeded so
153 * we will try to determine what type it is.
154 */
155 if(!memcmp(magic, "PE\0\0", sizeof(magic)))
156 {
157 IMAGE_FILE_HEADER FileHeader;
158 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) ||
159 (Read != sizeof(IMAGE_FILE_HEADER)))
160 {
161 return BINARY_DOS;
162 }
163
164 /* FIXME - detect 32/64 bit */
165
166 if(FileHeader.Characteristics & IMAGE_FILE_DLL)
167 return BINARY_PE_DLL32;
168 return BINARY_PE_EXE32;
169 }
170
171 if(!memcmp(magic, "NE", 1))
172 {
173 /* This is a Windows executable (NE) header. This can
174 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
175 * DOS program (running under a DOS extender). To decide
176 * which, we'll have to read the NE header.
177 */
178 IMAGE_OS2_HEADER ne;
179 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) ||
180 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) ||
181 (Read != sizeof(IMAGE_OS2_HEADER)))
182 {
183 /* Couldn't read header, so abort. */
184 return BINARY_DOS;
185 }
186
187 switch(ne.ne_exetyp)
188 {
189 case 2:
190 return BINARY_WIN16;
191 case 5:
192 return BINARY_DOS;
193 default:
194 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne);
195 }
196 }
197 return BINARY_DOS;
198 }
199 return BINARY_UNKNOWN;
200 }
201
202 /*
203 * @implemented
204 */
205 BOOL
206 WINAPI
207 GetBinaryTypeW (
208 LPCWSTR lpApplicationName,
209 LPDWORD lpBinaryType
210 )
211 {
212 HANDLE hFile;
213 DWORD BinType;
214
215 if(!lpApplicationName || !lpBinaryType)
216 {
217 SetLastError(ERROR_INVALID_PARAMETER);
218 return FALSE;
219 }
220
221 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL,
222 OPEN_EXISTING, 0, 0);
223 if(hFile == INVALID_HANDLE_VALUE)
224 {
225 return FALSE;
226 }
227
228 BinType = InternalGetBinaryType(hFile);
229 CloseHandle(hFile);
230
231 switch(BinType)
232 {
233 case BINARY_UNKNOWN:
234 {
235 WCHAR *dot;
236
237 /*
238 * guess from filename
239 */
240 if(!(dot = wcsrchr(lpApplicationName, L'.')))
241 {
242 return FALSE;
243 }
244 if(!lstrcmpiW(dot, L".COM"))
245 {
246 *lpBinaryType = SCS_DOS_BINARY;
247 return TRUE;
248 }
249 if(!lstrcmpiW(dot, L".PIF"))
250 {
251 *lpBinaryType = SCS_PIF_BINARY;
252 return TRUE;
253 }
254 return FALSE;
255 }
256 case BINARY_PE_EXE32:
257 case BINARY_PE_DLL32:
258 {
259 *lpBinaryType = SCS_32BIT_BINARY;
260 return TRUE;
261 }
262 case BINARY_PE_EXE64:
263 case BINARY_PE_DLL64:
264 {
265 *lpBinaryType = SCS_64BIT_BINARY;
266 return TRUE;
267 }
268 case BINARY_WIN16:
269 {
270 *lpBinaryType = SCS_WOW_BINARY;
271 return TRUE;
272 }
273 case BINARY_OS216:
274 {
275 *lpBinaryType = SCS_OS216_BINARY;
276 return TRUE;
277 }
278 case BINARY_DOS:
279 {
280 *lpBinaryType = SCS_DOS_BINARY;
281 return TRUE;
282 }
283 case BINARY_UNIX_EXE:
284 case BINARY_UNIX_LIB:
285 {
286 return FALSE;
287 }
288 }
289
290 DPRINT1("Invalid binary type returned!\n", BinType);
291 return FALSE;
292 }
293
294 /*
295 * @implemented
296 */
297 BOOL
298 WINAPI
299 GetBinaryTypeA(IN LPCSTR lpApplicationName,
300 OUT LPDWORD lpBinaryType)
301 {
302 ANSI_STRING ApplicationNameString;
303 UNICODE_STRING ApplicationNameW;
304 BOOL StringAllocated = FALSE, Result;
305 NTSTATUS Status;
306
307 RtlInitAnsiString(&ApplicationNameString, lpApplicationName);
308
309 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength)
310 {
311 StringAllocated = TRUE;
312 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE);
313 }
314 else
315 {
316 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE);
317 }
318
319 if (!NT_SUCCESS(Status))
320 {
321 BaseSetLastNTError(Status);
322 return FALSE;
323 }
324
325 if (StringAllocated)
326 {
327 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType);
328 RtlFreeUnicodeString(&ApplicationNameW);
329 }
330 else
331 {
332 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
333 }
334
335 return Result;
336 }
337
338 /*
339 * @unimplemented
340 */
341 BOOL
342 WINAPI
343 CmdBatNotification (
344 DWORD Unknown
345 )
346 {
347 STUB;
348 return FALSE;
349 }
350
351 /*
352 * @unimplemented
353 */
354 DWORD
355 WINAPI
356 ExitVDM (
357 DWORD Unknown0,
358 DWORD Unknown1
359 )
360 {
361 STUB;
362 return 0;
363 }
364
365
366 /*
367 * @unimplemented
368 */
369 DWORD
370 WINAPI
371 GetNextVDMCommand (
372 DWORD Unknown0
373 )
374 {
375 STUB;
376 return 0;
377 }
378
379
380 /*
381 * @unimplemented
382 */
383 DWORD
384 WINAPI
385 GetVDMCurrentDirectories (
386 DWORD Unknown0,
387 DWORD Unknown1
388 )
389 {
390 STUB;
391 return 0;
392 }
393
394
395 /*
396 * @unimplemented
397 */
398 BOOL
399 WINAPI
400 RegisterConsoleVDM (
401 DWORD Unknown0,
402 DWORD Unknown1,
403 DWORD Unknown2,
404 DWORD Unknown3,
405 DWORD Unknown4,
406 DWORD Unknown5,
407 DWORD Unknown6,
408 DWORD Unknown7,
409 DWORD Unknown8,
410 DWORD Unknown9,
411 DWORD Unknown10
412 )
413 {
414 STUB;
415 return FALSE;
416 }
417
418
419 /*
420 * @unimplemented
421 */
422 BOOL
423 WINAPI
424 RegisterWowBaseHandlers (
425 DWORD Unknown0
426 )
427 {
428 STUB;
429 return FALSE;
430 }
431
432
433 /*
434 * @unimplemented
435 */
436 BOOL
437 WINAPI
438 RegisterWowExec (
439 DWORD Unknown0
440 )
441 {
442 STUB;
443 return FALSE;
444 }
445
446
447 /*
448 * @unimplemented
449 */
450 BOOL
451 WINAPI
452 SetVDMCurrentDirectories (
453 DWORD Unknown0,
454 DWORD Unknown1
455 )
456 {
457 STUB;
458 return FALSE;
459 }
460
461 /*
462 * @unimplemented
463 */
464 DWORD
465 WINAPI
466 VDMConsoleOperation (
467 DWORD Unknown0,
468 DWORD Unknown1
469 )
470 {
471 STUB;
472 return 0;
473 }
474
475
476 /*
477 * @unimplemented
478 */
479 DWORD
480 WINAPI
481 VDMOperationStarted (
482 DWORD Unknown0
483 )
484 {
485 STUB;
486 return 0;
487 }