[KERNEL32]
[reactos.git] / 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 Machines (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 typedef struct _ENV_INFO
19 {
20 ULONG NameType;
21 ULONG NameLength;
22 PWCHAR Name;
23 } ENV_INFO, *PENV_INFO;
24
25 /* GLOBALS ********************************************************************/
26
27 ENV_INFO BasepEnvNameType[] =
28 {
29 {3, sizeof(L"PATH") , L"PATH" },
30 {2, sizeof(L"WINDIR") , L"WINDIR" },
31 {2, sizeof(L"SYSTEMROOT"), L"SYSTEMROOT"},
32 {3, sizeof(L"TEMP") , L"TEMP" },
33 {3, sizeof(L"TMP") , L"TMP" },
34 };
35
36 UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com");
37 UNICODE_STRING BaseDotPifSuffixName = RTL_CONSTANT_STRING(L".pif");
38 UNICODE_STRING BaseDotExeSuffixName = RTL_CONSTANT_STRING(L".exe");
39
40 /* FUNCTIONS ******************************************************************/
41
42 ULONG
43 WINAPI
44 BaseIsDosApplication(IN PUNICODE_STRING PathName,
45 IN NTSTATUS Status)
46 {
47 UNICODE_STRING String;
48
49 /* Is it a .com? */
50 String.Length = BaseDotComSuffixName.Length;
51 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
52 if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return BINARY_TYPE_COM;
53
54 /* Is it a .pif? */
55 String.Length = BaseDotPifSuffixName.Length;
56 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
57 if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return BINARY_TYPE_PIF;
58
59 /* Is it an exe? */
60 String.Length = BaseDotExeSuffixName.Length;
61 String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
62 if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return BINARY_TYPE_EXE;
63
64 return 0;
65 }
66
67 NTSTATUS
68 WINAPI
69 BaseCheckVDM(IN ULONG BinaryType,
70 IN PCWCH ApplicationName,
71 IN PCWCH CommandLine,
72 IN PCWCH CurrentDirectory,
73 IN PANSI_STRING AnsiEnvironment,
74 IN PCSR_API_MESSAGE ApiMessage,
75 IN OUT PULONG iTask,
76 IN DWORD CreationFlags,
77 IN LPSTARTUPINFOW StartupInfo,
78 IN HANDLE hUserToken OPTIONAL)
79 {
80 /* This is not supported */
81 UNIMPLEMENTED;
82 return STATUS_NOT_IMPLEMENTED;
83 }
84
85 BOOL
86 WINAPI
87 BaseUpdateVDMEntry(IN ULONG UpdateIndex,
88 IN OUT PHANDLE WaitHandle,
89 IN ULONG IndexInfo,
90 IN ULONG BinaryType)
91 {
92 NTSTATUS Status;
93 BASE_API_MESSAGE ApiMessage;
94 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest;
95
96 /* Check what update is being sent */
97 switch (UpdateIndex)
98 {
99 /* VDM is being undone */
100 case VdmEntryUndo:
101 {
102 /* Tell the server how far we had gotten along */
103 UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle);
104 UpdateVdmEntry->VDMCreationState = IndexInfo;
105 break;
106 }
107
108 /* VDM is ready with a new process handle */
109 case VdmEntryUpdateProcess:
110 {
111 /* Send it the process handle */
112 UpdateVdmEntry->VDMProcessHandle = *WaitHandle;
113 UpdateVdmEntry->iTask = IndexInfo;
114 break;
115 }
116 }
117
118 /* Also check what kind of binary this is for the console handle */
119 if (BinaryType == BINARY_TYPE_WOW)
120 {
121 /* Magic value for 16-bit apps */
122 UpdateVdmEntry->ConsoleHandle = (HANDLE)-1;
123 }
124 else if (UpdateVdmEntry->iTask)
125 {
126 /* No handle for true VDM */
127 UpdateVdmEntry->ConsoleHandle = NULL;
128 }
129 else
130 {
131 /* Otherwise, use the regular console handle */
132 UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
133 }
134
135 /* Finally write the index and binary type */
136 UpdateVdmEntry->EntryIndex = UpdateIndex;
137 UpdateVdmEntry->BinaryType = BinaryType;
138
139 /* Send the message to CSRSS */
140 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
141 NULL,
142 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepUpdateVDMEntry),
143 sizeof(BASE_UPDATE_VDM_ENTRY));
144 if (!NT_SUCCESS(Status))
145 {
146 /* Handle failure */
147 BaseSetLastNTError(Status);
148 return FALSE;
149 }
150
151 /* If this was an update, CSRSS returns a new wait handle */
152 if (UpdateIndex == VdmEntryUpdateProcess)
153 {
154 /* Return it to the caller */
155 *WaitHandle = UpdateVdmEntry->WaitObjectForParent;
156 }
157
158 /* We made it */
159 return TRUE;
160 }
161
162 BOOL
163 WINAPI
164 BaseCheckForVDM(IN HANDLE ProcessHandle,
165 OUT LPDWORD ExitCode)
166 {
167 NTSTATUS Status;
168 EVENT_BASIC_INFORMATION EventBasicInfo;
169 BASE_API_MESSAGE ApiMessage;
170 PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest;
171
172 /* It's VDM if the process is actually a wait handle (an event) */
173 Status = NtQueryEvent(ProcessHandle,
174 EventBasicInformation,
175 &EventBasicInfo,
176 sizeof(EventBasicInfo),
177 NULL);
178 if (!NT_SUCCESS(Status)) return FALSE;
179
180 /* Setup the input parameters */
181 GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
182 GetVdmExitCode->hParent = ProcessHandle;
183
184 /* Call CSRSS */
185 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
186 NULL,
187 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMExitCode),
188 sizeof(BASE_GET_VDM_EXIT_CODE));
189 if (!NT_SUCCESS(Status)) return FALSE;
190
191 /* Get the exit code from the reply */
192 *ExitCode = GetVdmExitCode->ExitCode;
193 return TRUE;
194 }
195
196 BOOL
197 WINAPI
198 BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
199 IN ULONG DosSeqId,
200 IN ULONG BinaryType,
201 IN PUNICODE_STRING CmdLineString,
202 OUT PULONG VdmSize)
203 {
204 WCHAR Buffer[MAX_PATH];
205 WCHAR CommandLine[MAX_PATH * 2];
206 ULONG Length;
207
208 /* Clear the buffer in case we fail */
209 CmdLineString->Buffer = 0;
210
211 /* Always return the same size: 16 Mb */
212 *VdmSize = 0x1000000;
213
214 /* Get the system directory */
215 Length = GetSystemDirectoryW(Buffer, MAX_PATH);
216 if (!(Length) || (Length >= MAX_PATH))
217 {
218 /* Eliminate no path or path too big */
219 SetLastError(ERROR_INVALID_NAME);
220 return FALSE;
221 }
222
223 /* Check if this is VDM with a DOS Sequence ID */
224 if (DosSeqId)
225 {
226 /*
227 * Build the VDM string for it:
228 * -i%lx : Gives the DOS Sequence ID;
229 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
230 */
231 _snwprintf(CommandLine,
232 sizeof(CommandLine),
233 L"\"%s\\ntvdm.exe\" -i%lx %s%c",
234 Buffer,
235 DosSeqId,
236 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
237 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
238 }
239 else
240 {
241 /*
242 * Build the string for it without the DOS Sequence ID:
243 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
244 */
245 _snwprintf(CommandLine,
246 sizeof(CommandLine),
247 L"\"%s\\ntvdm.exe\" %s%c",
248 Buffer,
249 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
250 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
251 }
252
253 /* Create the actual string */
254 return RtlCreateUnicodeString(CmdLineString, CommandLine);
255 }
256
257 UINT
258 WINAPI
259 BaseGetEnvNameType_U(IN PWCHAR Name,
260 IN ULONG NameLength)
261 {
262 PENV_INFO EnvInfo;
263 ULONG NameType, i;
264
265 /* Start by assuming unknown type */
266 NameType = 1;
267
268 /* Loop all the environment names */
269 for (i = 0; i < (sizeof(BasepEnvNameType) / sizeof(ENV_INFO)); i++)
270 {
271 /* Get this entry */
272 EnvInfo = &BasepEnvNameType[i];
273
274 /* Check if it matches the name */
275 if ((EnvInfo->NameLength == NameLength) &&
276 !(_wcsnicmp(EnvInfo->Name, Name, NameLength)))
277 {
278 /* It does, return the type */
279 NameType = EnvInfo->NameType;
280 break;
281 }
282 }
283
284 /* Return what we found, or unknown if nothing */
285 return NameType;
286 }
287
288 BOOL
289 NTAPI
290 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv,
291 IN PUNICODE_STRING UnicodeEnv)
292 {
293 ULONG Dummy = 0;
294
295 /* Clear the ASCII buffer since Rtl creates this for us */
296 if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv);
297
298 /* The Unicode buffer is build by hand, though */
299 if (UnicodeEnv->Buffer)
300 {
301 /* So clear it through the API */
302 NtFreeVirtualMemory(NtCurrentProcess(),
303 (PVOID*)&UnicodeEnv->Buffer,
304 &Dummy,
305 MEM_RELEASE);
306 }
307
308 /* All done */
309 return TRUE;
310 }
311
312 BOOL
313 NTAPI
314 BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
315 IN PANSI_STRING AnsiEnv,
316 IN PUNICODE_STRING UnicodeEnv)
317 {
318 BOOL Result;
319 ULONG RegionSize, EnvironmentSize = 0;
320 PWCHAR p, Environment, NewEnvironment = NULL;
321 NTSTATUS Status;
322
323 /* Make sure we have both strings */
324 if (!(AnsiEnv) || !(UnicodeEnv))
325 {
326 /* Fail */
327 SetLastError(ERROR_INVALID_PARAMETER);
328 return FALSE;
329 }
330
331 /* Check if an environment was passed in */
332 if (!lpEnvironment)
333 {
334 /* Nope, create one */
335 Status = RtlCreateEnvironment(TRUE, (PWCHAR*)&Environment);
336 if (!NT_SUCCESS(Status)) goto Quickie;
337 }
338 else
339 {
340 /* Use the one we got */
341 Environment = lpEnvironment;
342 }
343
344 /* Do we have something now ? */
345 if (!Environment)
346 {
347 /* Still not, fail out */
348 SetLastError(ERROR_BAD_ENVIRONMENT);
349 goto Quickie;
350 }
351
352 /* Count how much space the whole environment takes */
353 p = Environment;
354 while ((*p++ != UNICODE_NULL) && (*p != UNICODE_NULL)) EnvironmentSize++;
355 EnvironmentSize += sizeof(UNICODE_NULL);
356
357 /* Allocate a new copy */
358 RegionSize = (EnvironmentSize + MAX_PATH) * sizeof(WCHAR);
359 if (!NT_SUCCESS(NtAllocateVirtualMemory(NtCurrentProcess(),
360 (PVOID*)&NewEnvironment,
361 0,
362 &RegionSize,
363 MEM_COMMIT,
364 PAGE_READWRITE)))
365 {
366 /* We failed, bail out */
367 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
368 NewEnvironment = NULL;
369 goto Quickie;
370 }
371
372 /* Begin parsing the new environment */
373 p = NewEnvironment;
374
375 /* FIXME: Code here */
376
377 /* Terminate it */
378 *p++ = UNICODE_NULL;
379
380 /* Initialize the unicode string to hold it */
381 EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
382 RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
383 UnicodeEnv->Length = (USHORT)EnvironmentSize;
384
385 /* Create the ASCII version of it */
386 Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
387 if (!NT_SUCCESS(Status))
388 {
389 /* Set last error if conversion failure */
390 BaseSetLastNTError(Status);
391 }
392 else
393 {
394 /* Everything went okay, so return success */
395 Result = TRUE;
396 NewEnvironment = NULL;
397 }
398
399 Quickie:
400 /* Cleanup path starts here, start by destroying the envrionment copy */
401 if (!(lpEnvironment) && (Environment)) RtlDestroyEnvironment(Environment);
402
403 /* See if we are here due to failure */
404 if (NewEnvironment)
405 {
406 /* Initialize the paths to be empty */
407 RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0);
408 RtlInitEmptyAnsiString(AnsiEnv, NULL, 0);
409
410 /* Free the environment copy */
411 RegionSize = 0;
412 Status = NtFreeVirtualMemory(NtCurrentProcess(),
413 (PVOID*)&NewEnvironment,
414 &RegionSize,
415 MEM_RELEASE);
416 ASSERT(NT_SUCCESS(Status));
417 }
418
419 /* Return the result */
420 return Result;
421 }
422
423
424 /* Check whether a file is an OS/2 or a very old Windows executable
425 * by testing on import of KERNEL.
426 *
427 * FIXME: is reading the module imports the only way of discerning
428 * old Windows binaries from OS/2 ones ? At least it seems so...
429 */
430 static DWORD WINAPI
431 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
432 {
433 DWORD CurPos;
434 LPWORD modtab = NULL;
435 LPSTR nametab = NULL;
436 DWORD Read, Ret;
437 int i;
438
439 Ret = BINARY_OS216;
440 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
441
442 /* read modref table */
443 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
444 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) ||
445 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) ||
446 (Read != (DWORD)ne->ne_cmod * sizeof(WORD)))
447 {
448 goto broken;
449 }
450
451 /* read imported names table */
452 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
453 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) ||
454 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) ||
455 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab))
456 {
457 goto broken;
458 }
459
460 for(i = 0; i < ne->ne_cmod; i++)
461 {
462 LPSTR module;
463 module = &nametab[modtab[i]];
464 if(!strncmp(&module[1], "KERNEL", module[0]))
465 {
466 /* very old windows file */
467 Ret = BINARY_WIN16;
468 goto done;
469 }
470 }
471
472 broken:
473 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
474
475 done:
476 HeapFree(GetProcessHeap(), 0, modtab);
477 HeapFree(GetProcessHeap(), 0, nametab);
478 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN);
479 return Ret;
480 }
481
482 static DWORD WINAPI
483 InternalGetBinaryType(HANDLE hFile)
484 {
485 union
486 {
487 struct
488 {
489 unsigned char magic[4];
490 unsigned char ignored[12];
491 unsigned short type;
492 } elf;
493 struct
494 {
495 unsigned long magic;
496 unsigned long cputype;
497 unsigned long cpusubtype;
498 unsigned long filetype;
499 } macho;
500 IMAGE_DOS_HEADER mz;
501 } Header;
502 char magic[4];
503 DWORD Read;
504
505 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
506 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) ||
507 (Read != sizeof(Header))))
508 {
509 return BINARY_UNKNOWN;
510 }
511
512 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic)))
513 {
514 /* FIXME: we don't bother to check byte order, architecture, etc. */
515 switch(Header.elf.type)
516 {
517 case 2:
518 return BINARY_UNIX_EXE;
519 case 3:
520 return BINARY_UNIX_LIB;
521 }
522 return BINARY_UNKNOWN;
523 }
524
525 /* Mach-o File with Endian set to Big Endian or Little Endian*/
526 if(Header.macho.magic == 0xFEEDFACE ||
527 Header.macho.magic == 0xCEFAEDFE)
528 {
529 switch(Header.macho.filetype)
530 {
531 case 0x8:
532 /* MH_BUNDLE */
533 return BINARY_UNIX_LIB;
534 }
535 return BINARY_UNKNOWN;
536 }
537
538 /* Not ELF, try DOS */
539 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE)
540 {
541 /* We do have a DOS image so we will now try to seek into
542 * the file by the amount indicated by the field
543 * "Offset to extended header" and read in the
544 * "magic" field information at that location.
545 * This will tell us if there is more header information
546 * to read or not.
547 */
548 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
549 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) ||
550 (Read != sizeof(magic))))
551 {
552 return BINARY_DOS;
553 }
554
555 /* Reading the magic field succeeded so
556 * we will try to determine what type it is.
557 */
558 if(!memcmp(magic, "PE\0\0", sizeof(magic)))
559 {
560 IMAGE_FILE_HEADER FileHeader;
561 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) ||
562 (Read != sizeof(IMAGE_FILE_HEADER)))
563 {
564 return BINARY_DOS;
565 }
566
567 /* FIXME - detect 32/64 bit */
568
569 if(FileHeader.Characteristics & IMAGE_FILE_DLL)
570 return BINARY_PE_DLL32;
571 return BINARY_PE_EXE32;
572 }
573
574 if(!memcmp(magic, "NE", 1))
575 {
576 /* This is a Windows executable (NE) header. This can
577 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
578 * DOS program (running under a DOS extender). To decide
579 * which, we'll have to read the NE header.
580 */
581 IMAGE_OS2_HEADER ne;
582 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) ||
583 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) ||
584 (Read != sizeof(IMAGE_OS2_HEADER)))
585 {
586 /* Couldn't read header, so abort. */
587 return BINARY_DOS;
588 }
589
590 switch(ne.ne_exetyp)
591 {
592 case 2:
593 return BINARY_WIN16;
594 case 5:
595 return BINARY_DOS;
596 default:
597 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne);
598 }
599 }
600 return BINARY_DOS;
601 }
602 return BINARY_UNKNOWN;
603 }
604
605 /*
606 * @implemented
607 */
608 BOOL
609 WINAPI
610 GetBinaryTypeW (
611 LPCWSTR lpApplicationName,
612 LPDWORD lpBinaryType
613 )
614 {
615 HANDLE hFile;
616 DWORD BinType;
617
618 if(!lpApplicationName || !lpBinaryType)
619 {
620 SetLastError(ERROR_INVALID_PARAMETER);
621 return FALSE;
622 }
623
624 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL,
625 OPEN_EXISTING, 0, 0);
626 if(hFile == INVALID_HANDLE_VALUE)
627 {
628 return FALSE;
629 }
630
631 BinType = InternalGetBinaryType(hFile);
632 CloseHandle(hFile);
633
634 switch(BinType)
635 {
636 case BINARY_UNKNOWN:
637 {
638 WCHAR *dot;
639
640 /*
641 * guess from filename
642 */
643 if(!(dot = wcsrchr(lpApplicationName, L'.')))
644 {
645 return FALSE;
646 }
647 if(!lstrcmpiW(dot, L".COM"))
648 {
649 *lpBinaryType = SCS_DOS_BINARY;
650 return TRUE;
651 }
652 if(!lstrcmpiW(dot, L".PIF"))
653 {
654 *lpBinaryType = SCS_PIF_BINARY;
655 return TRUE;
656 }
657 return FALSE;
658 }
659 case BINARY_PE_EXE32:
660 case BINARY_PE_DLL32:
661 {
662 *lpBinaryType = SCS_32BIT_BINARY;
663 return TRUE;
664 }
665 case BINARY_PE_EXE64:
666 case BINARY_PE_DLL64:
667 {
668 *lpBinaryType = SCS_64BIT_BINARY;
669 return TRUE;
670 }
671 case BINARY_WIN16:
672 {
673 *lpBinaryType = SCS_WOW_BINARY;
674 return TRUE;
675 }
676 case BINARY_OS216:
677 {
678 *lpBinaryType = SCS_OS216_BINARY;
679 return TRUE;
680 }
681 case BINARY_DOS:
682 {
683 *lpBinaryType = SCS_DOS_BINARY;
684 return TRUE;
685 }
686 case BINARY_UNIX_EXE:
687 case BINARY_UNIX_LIB:
688 {
689 return FALSE;
690 }
691 }
692
693 DPRINT1("Invalid binary type %lu returned!\n", BinType);
694 return FALSE;
695 }
696
697 /*
698 * @implemented
699 */
700 BOOL
701 WINAPI
702 GetBinaryTypeA(IN LPCSTR lpApplicationName,
703 OUT LPDWORD lpBinaryType)
704 {
705 ANSI_STRING ApplicationNameString;
706 UNICODE_STRING ApplicationNameW;
707 BOOL StringAllocated = FALSE, Result;
708 NTSTATUS Status;
709
710 RtlInitAnsiString(&ApplicationNameString, lpApplicationName);
711
712 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength)
713 {
714 StringAllocated = TRUE;
715 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE);
716 }
717 else
718 {
719 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE);
720 }
721
722 if (!NT_SUCCESS(Status))
723 {
724 BaseSetLastNTError(Status);
725 return FALSE;
726 }
727
728 if (StringAllocated)
729 {
730 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType);
731 RtlFreeUnicodeString(&ApplicationNameW);
732 }
733 else
734 {
735 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
736 }
737
738 return Result;
739 }
740
741 /*
742 * @unimplemented
743 */
744 BOOL
745 WINAPI
746 CmdBatNotification (
747 DWORD Unknown
748 )
749 {
750 STUB;
751 return FALSE;
752 }
753
754 /*
755 * @implemented
756 */
757 VOID
758 WINAPI
759 ExitVDM(BOOL IsWow, ULONG iWowTask)
760 {
761 BASE_API_MESSAGE ApiMessage;
762 PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
763
764 /* Setup the input parameters */
765 ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
766 ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
767 ExitVdm->WaitObjectForVDM = NULL;
768
769 /* Call CSRSS */
770 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
771 NULL,
772 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
773 sizeof(BASE_EXIT_VDM));
774
775 /* Close the returned wait object handle, if any */
776 if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
777 {
778 CloseHandle(ExitVdm->WaitObjectForVDM);
779 }
780 }
781
782
783 /*
784 * @unimplemented
785 */
786 DWORD
787 WINAPI
788 GetNextVDMCommand(PGET_NEXT_VDM_COMMAND_DATA CommandData)
789 {
790 STUB;
791 return 0;
792 }
793
794
795 /*
796 * @unimplemented
797 */
798 DWORD
799 WINAPI
800 GetVDMCurrentDirectories (
801 DWORD Unknown0,
802 DWORD Unknown1
803 )
804 {
805 STUB;
806 return 0;
807 }
808
809
810 /*
811 * @unimplemented
812 */
813 BOOL
814 WINAPI
815 RegisterConsoleVDM (
816 DWORD Unknown0,
817 DWORD Unknown1,
818 DWORD Unknown2,
819 DWORD Unknown3,
820 DWORD Unknown4,
821 DWORD Unknown5,
822 DWORD Unknown6,
823 DWORD Unknown7,
824 DWORD Unknown8,
825 DWORD Unknown9,
826 DWORD Unknown10
827 )
828 {
829 STUB;
830 return FALSE;
831 }
832
833
834 /*
835 * @unimplemented
836 */
837 BOOL
838 WINAPI
839 RegisterWowBaseHandlers (
840 DWORD Unknown0
841 )
842 {
843 STUB;
844 return FALSE;
845 }
846
847
848 /*
849 * @unimplemented
850 */
851 BOOL
852 WINAPI
853 RegisterWowExec (
854 DWORD Unknown0
855 )
856 {
857 STUB;
858 return FALSE;
859 }
860
861
862 /*
863 * @unimplemented
864 */
865 BOOL
866 WINAPI
867 SetVDMCurrentDirectories (
868 DWORD Unknown0,
869 DWORD Unknown1
870 )
871 {
872 STUB;
873 return FALSE;
874 }
875
876 /*
877 * @unimplemented
878 */
879 DWORD
880 WINAPI
881 VDMConsoleOperation (
882 DWORD Unknown0,
883 DWORD Unknown1
884 )
885 {
886 STUB;
887 return 0;
888 }
889
890
891 /*
892 * @unimplemented
893 */
894 DWORD
895 WINAPI
896 VDMOperationStarted (
897 DWORD Unknown0
898 )
899 {
900 STUB;
901 return 0;
902 }