[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 PBASE_API_MESSAGE ApiMessage,
75 IN OUT PULONG iTask,
76 IN DWORD CreationFlags,
77 IN LPSTARTUPINFOW StartupInfo,
78 IN HANDLE hUserToken OPTIONAL)
79 {
80 NTSTATUS Status;
81 PBASE_CHECK_VDM CheckVdm = &ApiMessage->Data.CheckVDMRequest;
82 PCSR_CAPTURE_BUFFER CaptureBuffer;
83 PWCHAR CurrentDir = NULL;
84 PWCHAR ShortAppName = NULL;
85 PWCHAR ShortCurrentDir = NULL;
86 ULONG Length;
87 PCHAR AnsiCmdLine = NULL;
88 PCHAR AnsiAppName = NULL;
89 PCHAR AnsiCurDirectory = NULL;
90 PCHAR AnsiDesktop = NULL;
91 PCHAR AnsiTitle = NULL;
92 PCHAR AnsiReserved = NULL;
93 STARTUPINFOA AnsiStartupInfo;
94 ULONG NumStrings = 5;
95
96 if (CurrentDirectory == NULL)
97 {
98 /* Allocate memory for the current directory path */
99 Length = GetCurrentDirectoryW(0, NULL);
100 CurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
101 HEAP_ZERO_MEMORY,
102 Length * sizeof(WCHAR));
103 if (CurrentDir == NULL)
104 {
105 Status = STATUS_NO_MEMORY;
106 goto Cleanup;
107 }
108
109 /* Get the current directory */
110 GetCurrentDirectoryW(Length, CurrentDir);
111 CurrentDirectory = CurrentDir;
112 }
113
114 /* Calculate the size of the short application name */
115 Length = GetShortPathNameW(ApplicationName, NULL, 0);
116
117 /* Allocate memory for the short application name */
118 ShortAppName = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
119 HEAP_ZERO_MEMORY,
120 Length * sizeof(WCHAR));
121 if (!ShortAppName)
122 {
123 Status = STATUS_NO_MEMORY;
124 goto Cleanup;
125 }
126
127 /* Get the short application name */
128 if (!GetShortPathNameW(ApplicationName, ShortAppName, Length))
129 {
130 /* Try to determine which error occurred */
131 switch (GetLastError())
132 {
133 case ERROR_NOT_ENOUGH_MEMORY:
134 {
135 Status = STATUS_NO_MEMORY;
136 break;
137 }
138
139 case ERROR_INVALID_PARAMETER:
140 {
141 Status = STATUS_INVALID_PARAMETER;
142 break;
143 }
144
145 default:
146 {
147 Status = STATUS_OBJECT_PATH_INVALID;
148 }
149 }
150
151 goto Cleanup;
152 }
153
154 /* Calculate the size of the short current directory path */
155 Length = GetShortPathNameW(CurrentDirectory, NULL, 0);
156
157 /* Allocate memory for the short current directory path */
158 ShortCurrentDir = (PWCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
159 HEAP_ZERO_MEMORY,
160 Length * sizeof(WCHAR));
161 if (!ShortCurrentDir)
162 {
163 Status = STATUS_NO_MEMORY;
164 goto Cleanup;
165 }
166
167 /* Get the short current directory path */
168 if (!GetShortPathNameW(CurrentDirectory, ShortCurrentDir, Length))
169 {
170 /* Try to determine which error occurred */
171 switch (GetLastError())
172 {
173 case ERROR_NOT_ENOUGH_MEMORY:
174 {
175 Status = STATUS_NO_MEMORY;
176 break;
177 }
178
179 case ERROR_INVALID_PARAMETER:
180 {
181 Status = STATUS_INVALID_PARAMETER;
182 break;
183 }
184
185 default:
186 {
187 Status = STATUS_OBJECT_PATH_INVALID;
188 }
189 }
190 goto Cleanup;
191 }
192
193 /* Setup the input parameters */
194 CheckVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
195 CheckVdm->BinaryType = BinaryType;
196 CheckVdm->CodePage = CP_ACP;
197 CheckVdm->dwCreationFlags = CreationFlags;
198 CheckVdm->CurDrive = CurrentDirectory[0] - L'A';
199 CheckVdm->CmdLen = wcslen(CommandLine) + 1;
200 CheckVdm->AppLen = wcslen(ShortAppName) + 1;
201 CheckVdm->PifLen = 0; // TODO: PIF file support!
202 CheckVdm->CurDirectoryLen = wcslen(ShortCurrentDir) + 1;
203 CheckVdm->EnvLen = AnsiEnvironment->Length;
204 CheckVdm->DesktopLen = (StartupInfo->lpDesktop != NULL) ? (wcslen(StartupInfo->lpDesktop) + 1) : 0;
205 CheckVdm->TitleLen = (StartupInfo->lpTitle != NULL) ? (wcslen(StartupInfo->lpTitle) + 1) : 0;
206 CheckVdm->ReservedLen = (StartupInfo->lpReserved != NULL) ? (wcslen(StartupInfo->lpReserved) + 1) : 0;
207
208 if (StartupInfo->dwFlags & STARTF_USESTDHANDLES)
209 {
210 /* Set the standard handles */
211 CheckVdm->StdIn = StartupInfo->hStdInput;
212 CheckVdm->StdOut = StartupInfo->hStdOutput;
213 CheckVdm->StdErr = StartupInfo->hStdError;
214 }
215
216 /* Allocate memory for the ANSI strings */
217 AnsiCmdLine = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CmdLen);
218 AnsiAppName = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->AppLen);
219 AnsiCurDirectory = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CheckVdm->CurDirectoryLen);
220 if (StartupInfo->lpDesktop) AnsiDesktop = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
221 HEAP_ZERO_MEMORY,
222 CheckVdm->DesktopLen);
223 if (StartupInfo->lpTitle) AnsiTitle = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
224 HEAP_ZERO_MEMORY,
225 CheckVdm->TitleLen);
226 if (StartupInfo->lpReserved) AnsiReserved = (PCHAR)RtlAllocateHeap(RtlGetProcessHeap(),
227 HEAP_ZERO_MEMORY,
228 CheckVdm->ReservedLen);
229
230 if (!AnsiCmdLine
231 || !AnsiAppName
232 || !AnsiCurDirectory
233 || (StartupInfo->lpDesktop && !AnsiDesktop)
234 || (StartupInfo->lpTitle && !AnsiTitle)
235 || (StartupInfo->lpReserved && !AnsiReserved))
236 {
237 Status = STATUS_NO_MEMORY;
238 goto Cleanup;
239 }
240
241 /* Convert the command line into an ANSI string */
242 WideCharToMultiByte(CP_ACP,
243 0,
244 CommandLine,
245 CheckVdm->CmdLen,
246 AnsiCmdLine,
247 CheckVdm->CmdLen,
248 NULL,
249 NULL);
250
251 /* Convert the short application name into an ANSI string */
252 WideCharToMultiByte(CP_ACP,
253 0,
254 ShortAppName,
255 CheckVdm->AppLen,
256 AnsiAppName,
257 CheckVdm->AppLen,
258 NULL,
259 NULL);
260
261 /* Convert the short current directory path into an ANSI string */
262 WideCharToMultiByte(CP_ACP,
263 0,
264 ShortCurrentDir,
265 CheckVdm->CurDirectoryLen,
266 AnsiCurDirectory,
267 CheckVdm->CurDirectoryLen,
268 NULL,
269 NULL);
270
271 if (StartupInfo->lpDesktop)
272 {
273 /* Convert the desktop name into an ANSI string */
274 WideCharToMultiByte(CP_ACP,
275 0,
276 StartupInfo->lpDesktop,
277 CheckVdm->DesktopLen,
278 AnsiDesktop,
279 CheckVdm->DesktopLen,
280 NULL,
281 NULL);
282 NumStrings++;
283 }
284
285 if (StartupInfo->lpTitle)
286 {
287 /* Convert the title into an ANSI string */
288 WideCharToMultiByte(CP_ACP,
289 0,
290 StartupInfo->lpTitle,
291 CheckVdm->TitleLen,
292 AnsiTitle,
293 CheckVdm->TitleLen,
294 NULL,
295 NULL);
296 NumStrings++;
297 }
298
299 if (StartupInfo->lpReserved)
300 {
301 /* Convert the reserved value into an ANSI string */
302 WideCharToMultiByte(CP_ACP,
303 0,
304 StartupInfo->lpReserved,
305 CheckVdm->ReservedLen,
306 AnsiReserved,
307 CheckVdm->ReservedLen,
308 NULL,
309 NULL);
310 NumStrings++;
311 }
312
313 /* Fill the ANSI startup info structure */
314 RtlCopyMemory(&AnsiStartupInfo, StartupInfo, sizeof(STARTUPINFO));
315 AnsiStartupInfo.lpReserved = AnsiReserved;
316 AnsiStartupInfo.lpDesktop = AnsiDesktop;
317 AnsiStartupInfo.lpTitle = AnsiTitle;
318
319 /* Allocate the capture buffer */
320 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings,
321 CheckVdm->CmdLen
322 + CheckVdm->AppLen
323 + CheckVdm->PifLen
324 + CheckVdm->CurDirectoryLen
325 + CheckVdm->DesktopLen
326 + CheckVdm->TitleLen
327 + CheckVdm->ReservedLen
328 + CheckVdm->EnvLen
329 + sizeof(STARTUPINFOA));
330 if (CaptureBuffer == NULL)
331 {
332 Status = STATUS_NO_MEMORY;
333 goto Cleanup;
334 }
335
336 /* Capture the command line */
337 CsrCaptureMessageBuffer(CaptureBuffer,
338 AnsiCmdLine,
339 CheckVdm->CmdLen,
340 (PVOID*)&CheckVdm->CmdLine);
341
342 /* Capture the application name */
343 CsrCaptureMessageBuffer(CaptureBuffer,
344 AnsiAppName,
345 CheckVdm->AppLen,
346 (PVOID*)&CheckVdm->AppName);
347
348 CheckVdm->PifFile = NULL; // TODO: PIF file support!
349
350 /* Capture the current directory */
351 CsrCaptureMessageBuffer(CaptureBuffer,
352 AnsiCurDirectory,
353 CheckVdm->CurDirectoryLen,
354 (PVOID*)&CheckVdm->CurDirectory);
355
356 /* Capture the environment */
357 CsrCaptureMessageBuffer(CaptureBuffer,
358 AnsiEnvironment->Buffer,
359 CheckVdm->EnvLen,
360 (PVOID*)&CheckVdm->Env);
361
362 /* Capture the startup info structure */
363 CsrCaptureMessageBuffer(CaptureBuffer,
364 &AnsiStartupInfo,
365 sizeof(STARTUPINFOA),
366 (PVOID*)&CheckVdm->StartupInfo);
367
368 if (StartupInfo->lpDesktop)
369 {
370 /* Capture the desktop name */
371 CsrCaptureMessageBuffer(CaptureBuffer,
372 AnsiDesktop,
373 CheckVdm->DesktopLen,
374 (PVOID*)&CheckVdm->Desktop);
375 }
376 else CheckVdm->Desktop = NULL;
377
378 if (StartupInfo->lpTitle)
379 {
380 /* Capture the title */
381 CsrCaptureMessageBuffer(CaptureBuffer,
382 AnsiTitle,
383 CheckVdm->TitleLen,
384 (PVOID*)&CheckVdm->Title);
385 }
386 else CheckVdm->Title = NULL;
387
388 if (StartupInfo->lpReserved)
389 {
390 /* Capture the reserved parameter */
391 CsrCaptureMessageBuffer(CaptureBuffer,
392 AnsiReserved,
393 CheckVdm->ReservedLen,
394 (PVOID*)&CheckVdm->Reserved);
395 }
396 else CheckVdm->Reserved = NULL;
397
398 /* Send the message to CSRSS */
399 Status = CsrClientCallServer((PCSR_API_MESSAGE)ApiMessage,
400 CaptureBuffer,
401 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepCheckVDM),
402 sizeof(BASE_CHECK_VDM));
403
404 /* Write back the task ID */
405 *iTask = CheckVdm->iTask;
406
407 Cleanup:
408
409 /* Free the ANSI strings */
410 if (AnsiCmdLine) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine);
411 if (AnsiAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName);
412 if (AnsiCurDirectory) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory);
413 if (AnsiDesktop) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop);
414 if (AnsiTitle) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle);
415 if (AnsiReserved) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved);
416
417 /* Free the capture buffer */
418 CsrFreeCaptureBuffer(CaptureBuffer);
419
420 /* Free the short paths */
421 if (ShortAppName) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName);
422 if (ShortCurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir);
423
424 /* Free the current directory, if it was allocated here */
425 if (CurrentDir) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir);
426
427 return Status;
428 }
429
430 BOOL
431 WINAPI
432 BaseUpdateVDMEntry(IN ULONG UpdateIndex,
433 IN OUT PHANDLE WaitHandle,
434 IN ULONG IndexInfo,
435 IN ULONG BinaryType)
436 {
437 NTSTATUS Status;
438 BASE_API_MESSAGE ApiMessage;
439 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest;
440
441 /* Check what update is being sent */
442 switch (UpdateIndex)
443 {
444 /* VDM is being undone */
445 case VdmEntryUndo:
446 {
447 /* Tell the server how far we had gotten along */
448 UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle);
449 UpdateVdmEntry->VDMCreationState = IndexInfo;
450 break;
451 }
452
453 /* VDM is ready with a new process handle */
454 case VdmEntryUpdateProcess:
455 {
456 /* Send it the process handle */
457 UpdateVdmEntry->VDMProcessHandle = *WaitHandle;
458 UpdateVdmEntry->iTask = IndexInfo;
459 break;
460 }
461 }
462
463 /* Also check what kind of binary this is for the console handle */
464 if (BinaryType == BINARY_TYPE_WOW)
465 {
466 /* Magic value for 16-bit apps */
467 UpdateVdmEntry->ConsoleHandle = (HANDLE)-1;
468 }
469 else if (UpdateVdmEntry->iTask)
470 {
471 /* No handle for true VDM */
472 UpdateVdmEntry->ConsoleHandle = NULL;
473 }
474 else
475 {
476 /* Otherwise, use the regular console handle */
477 UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
478 }
479
480 /* Finally write the index and binary type */
481 UpdateVdmEntry->EntryIndex = UpdateIndex;
482 UpdateVdmEntry->BinaryType = BinaryType;
483
484 /* Send the message to CSRSS */
485 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
486 NULL,
487 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepUpdateVDMEntry),
488 sizeof(BASE_UPDATE_VDM_ENTRY));
489 if (!NT_SUCCESS(Status))
490 {
491 /* Handle failure */
492 BaseSetLastNTError(Status);
493 return FALSE;
494 }
495
496 /* If this was an update, CSRSS returns a new wait handle */
497 if (UpdateIndex == VdmEntryUpdateProcess)
498 {
499 /* Return it to the caller */
500 *WaitHandle = UpdateVdmEntry->WaitObjectForParent;
501 }
502
503 /* We made it */
504 return TRUE;
505 }
506
507 BOOL
508 WINAPI
509 BaseCheckForVDM(IN HANDLE ProcessHandle,
510 OUT LPDWORD ExitCode)
511 {
512 NTSTATUS Status;
513 EVENT_BASIC_INFORMATION EventBasicInfo;
514 BASE_API_MESSAGE ApiMessage;
515 PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest;
516
517 /* It's VDM if the process is actually a wait handle (an event) */
518 Status = NtQueryEvent(ProcessHandle,
519 EventBasicInformation,
520 &EventBasicInfo,
521 sizeof(EventBasicInfo),
522 NULL);
523 if (!NT_SUCCESS(Status)) return FALSE;
524
525 /* Setup the input parameters */
526 GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
527 GetVdmExitCode->hParent = ProcessHandle;
528
529 /* Call CSRSS */
530 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
531 NULL,
532 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMExitCode),
533 sizeof(BASE_GET_VDM_EXIT_CODE));
534 if (!NT_SUCCESS(Status)) return FALSE;
535
536 /* Get the exit code from the reply */
537 *ExitCode = GetVdmExitCode->ExitCode;
538 return TRUE;
539 }
540
541 BOOL
542 WINAPI
543 BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
544 IN ULONG DosSeqId,
545 IN ULONG BinaryType,
546 IN PUNICODE_STRING CmdLineString,
547 OUT PULONG VdmSize)
548 {
549 WCHAR Buffer[MAX_PATH];
550 WCHAR CommandLine[MAX_PATH * 2];
551 ULONG Length;
552
553 /* Clear the buffer in case we fail */
554 CmdLineString->Buffer = 0;
555
556 /* Always return the same size: 16 Mb */
557 *VdmSize = 0x1000000;
558
559 /* Get the system directory */
560 Length = GetSystemDirectoryW(Buffer, MAX_PATH);
561 if (!(Length) || (Length >= MAX_PATH))
562 {
563 /* Eliminate no path or path too big */
564 SetLastError(ERROR_INVALID_NAME);
565 return FALSE;
566 }
567
568 /* Check if this is VDM with a DOS Sequence ID */
569 if (DosSeqId)
570 {
571 /*
572 * Build the VDM string for it:
573 * -i%lx : Gives the DOS Sequence ID;
574 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
575 */
576 _snwprintf(CommandLine,
577 sizeof(CommandLine),
578 L"\"%s\\ntvdm.exe\" -i%lx %s%c",
579 Buffer,
580 DosSeqId,
581 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
582 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
583 }
584 else
585 {
586 /*
587 * Build the string for it without the DOS Sequence ID:
588 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
589 */
590 _snwprintf(CommandLine,
591 sizeof(CommandLine),
592 L"\"%s\\ntvdm.exe\" %s%c",
593 Buffer,
594 (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
595 (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
596 }
597
598 /* Create the actual string */
599 return RtlCreateUnicodeString(CmdLineString, CommandLine);
600 }
601
602 UINT
603 WINAPI
604 BaseGetEnvNameType_U(IN PWCHAR Name,
605 IN ULONG NameLength)
606 {
607 PENV_INFO EnvInfo;
608 ULONG NameType, i;
609
610 /* Start by assuming unknown type */
611 NameType = 1;
612
613 /* Loop all the environment names */
614 for (i = 0; i < (sizeof(BasepEnvNameType) / sizeof(ENV_INFO)); i++)
615 {
616 /* Get this entry */
617 EnvInfo = &BasepEnvNameType[i];
618
619 /* Check if it matches the name */
620 if ((EnvInfo->NameLength == NameLength) &&
621 !(_wcsnicmp(EnvInfo->Name, Name, NameLength)))
622 {
623 /* It does, return the type */
624 NameType = EnvInfo->NameType;
625 break;
626 }
627 }
628
629 /* Return what we found, or unknown if nothing */
630 return NameType;
631 }
632
633 BOOL
634 NTAPI
635 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv,
636 IN PUNICODE_STRING UnicodeEnv)
637 {
638 ULONG Dummy = 0;
639
640 /* Clear the ASCII buffer since Rtl creates this for us */
641 if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv);
642
643 /* The Unicode buffer is build by hand, though */
644 if (UnicodeEnv->Buffer)
645 {
646 /* So clear it through the API */
647 NtFreeVirtualMemory(NtCurrentProcess(),
648 (PVOID*)&UnicodeEnv->Buffer,
649 &Dummy,
650 MEM_RELEASE);
651 }
652
653 /* All done */
654 return TRUE;
655 }
656
657 BOOL
658 NTAPI
659 BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
660 IN PANSI_STRING AnsiEnv,
661 IN PUNICODE_STRING UnicodeEnv)
662 {
663 BOOL Result;
664 ULONG RegionSize, EnvironmentSize = 0;
665 PWCHAR p, Environment, NewEnvironment = NULL;
666 NTSTATUS Status;
667
668 /* Make sure we have both strings */
669 if (!(AnsiEnv) || !(UnicodeEnv))
670 {
671 /* Fail */
672 SetLastError(ERROR_INVALID_PARAMETER);
673 return FALSE;
674 }
675
676 /* Check if an environment was passed in */
677 if (!lpEnvironment)
678 {
679 /* Nope, create one */
680 Status = RtlCreateEnvironment(TRUE, (PWCHAR*)&Environment);
681 if (!NT_SUCCESS(Status)) goto Quickie;
682 }
683 else
684 {
685 /* Use the one we got */
686 Environment = lpEnvironment;
687 }
688
689 /* Do we have something now ? */
690 if (!Environment)
691 {
692 /* Still not, fail out */
693 SetLastError(ERROR_BAD_ENVIRONMENT);
694 goto Quickie;
695 }
696
697 /* Count how much space the whole environment takes */
698 p = Environment;
699 while ((*p++ != UNICODE_NULL) && (*p != UNICODE_NULL)) EnvironmentSize++;
700 EnvironmentSize += sizeof(UNICODE_NULL);
701
702 /* Allocate a new copy */
703 RegionSize = (EnvironmentSize + MAX_PATH) * sizeof(WCHAR);
704 if (!NT_SUCCESS(NtAllocateVirtualMemory(NtCurrentProcess(),
705 (PVOID*)&NewEnvironment,
706 0,
707 &RegionSize,
708 MEM_COMMIT,
709 PAGE_READWRITE)))
710 {
711 /* We failed, bail out */
712 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
713 NewEnvironment = NULL;
714 goto Quickie;
715 }
716
717 /* Begin parsing the new environment */
718 p = NewEnvironment;
719
720 /* FIXME: Code here */
721
722 /* Terminate it */
723 *p++ = UNICODE_NULL;
724
725 /* Initialize the unicode string to hold it */
726 EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
727 RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
728 UnicodeEnv->Length = (USHORT)EnvironmentSize;
729
730 /* Create the ASCII version of it */
731 Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
732 if (!NT_SUCCESS(Status))
733 {
734 /* Set last error if conversion failure */
735 BaseSetLastNTError(Status);
736 }
737 else
738 {
739 /* Everything went okay, so return success */
740 Result = TRUE;
741 NewEnvironment = NULL;
742 }
743
744 Quickie:
745 /* Cleanup path starts here, start by destroying the envrionment copy */
746 if (!(lpEnvironment) && (Environment)) RtlDestroyEnvironment(Environment);
747
748 /* See if we are here due to failure */
749 if (NewEnvironment)
750 {
751 /* Initialize the paths to be empty */
752 RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0);
753 RtlInitEmptyAnsiString(AnsiEnv, NULL, 0);
754
755 /* Free the environment copy */
756 RegionSize = 0;
757 Status = NtFreeVirtualMemory(NtCurrentProcess(),
758 (PVOID*)&NewEnvironment,
759 &RegionSize,
760 MEM_RELEASE);
761 ASSERT(NT_SUCCESS(Status));
762 }
763
764 /* Return the result */
765 return Result;
766 }
767
768
769 /* Check whether a file is an OS/2 or a very old Windows executable
770 * by testing on import of KERNEL.
771 *
772 * FIXME: is reading the module imports the only way of discerning
773 * old Windows binaries from OS/2 ones ? At least it seems so...
774 */
775 static DWORD WINAPI
776 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
777 {
778 DWORD CurPos;
779 LPWORD modtab = NULL;
780 LPSTR nametab = NULL;
781 DWORD Read, Ret;
782 int i;
783
784 Ret = BINARY_OS216;
785 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
786
787 /* read modref table */
788 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
789 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) ||
790 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) ||
791 (Read != (DWORD)ne->ne_cmod * sizeof(WORD)))
792 {
793 goto broken;
794 }
795
796 /* read imported names table */
797 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
798 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) ||
799 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) ||
800 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab))
801 {
802 goto broken;
803 }
804
805 for(i = 0; i < ne->ne_cmod; i++)
806 {
807 LPSTR module;
808 module = &nametab[modtab[i]];
809 if(!strncmp(&module[1], "KERNEL", module[0]))
810 {
811 /* very old windows file */
812 Ret = BINARY_WIN16;
813 goto done;
814 }
815 }
816
817 broken:
818 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
819
820 done:
821 HeapFree(GetProcessHeap(), 0, modtab);
822 HeapFree(GetProcessHeap(), 0, nametab);
823 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN);
824 return Ret;
825 }
826
827 static DWORD WINAPI
828 InternalGetBinaryType(HANDLE hFile)
829 {
830 union
831 {
832 struct
833 {
834 unsigned char magic[4];
835 unsigned char ignored[12];
836 unsigned short type;
837 } elf;
838 struct
839 {
840 unsigned long magic;
841 unsigned long cputype;
842 unsigned long cpusubtype;
843 unsigned long filetype;
844 } macho;
845 IMAGE_DOS_HEADER mz;
846 } Header;
847 char magic[4];
848 DWORD Read;
849
850 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
851 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) ||
852 (Read != sizeof(Header))))
853 {
854 return BINARY_UNKNOWN;
855 }
856
857 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic)))
858 {
859 /* FIXME: we don't bother to check byte order, architecture, etc. */
860 switch(Header.elf.type)
861 {
862 case 2:
863 return BINARY_UNIX_EXE;
864 case 3:
865 return BINARY_UNIX_LIB;
866 }
867 return BINARY_UNKNOWN;
868 }
869
870 /* Mach-o File with Endian set to Big Endian or Little Endian*/
871 if(Header.macho.magic == 0xFEEDFACE ||
872 Header.macho.magic == 0xCEFAEDFE)
873 {
874 switch(Header.macho.filetype)
875 {
876 case 0x8:
877 /* MH_BUNDLE */
878 return BINARY_UNIX_LIB;
879 }
880 return BINARY_UNKNOWN;
881 }
882
883 /* Not ELF, try DOS */
884 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE)
885 {
886 /* We do have a DOS image so we will now try to seek into
887 * the file by the amount indicated by the field
888 * "Offset to extended header" and read in the
889 * "magic" field information at that location.
890 * This will tell us if there is more header information
891 * to read or not.
892 */
893 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
894 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) ||
895 (Read != sizeof(magic))))
896 {
897 return BINARY_DOS;
898 }
899
900 /* Reading the magic field succeeded so
901 * we will try to determine what type it is.
902 */
903 if(!memcmp(magic, "PE\0\0", sizeof(magic)))
904 {
905 IMAGE_FILE_HEADER FileHeader;
906 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) ||
907 (Read != sizeof(IMAGE_FILE_HEADER)))
908 {
909 return BINARY_DOS;
910 }
911
912 /* FIXME - detect 32/64 bit */
913
914 if(FileHeader.Characteristics & IMAGE_FILE_DLL)
915 return BINARY_PE_DLL32;
916 return BINARY_PE_EXE32;
917 }
918
919 if(!memcmp(magic, "NE", 1))
920 {
921 /* This is a Windows executable (NE) header. This can
922 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
923 * DOS program (running under a DOS extender). To decide
924 * which, we'll have to read the NE header.
925 */
926 IMAGE_OS2_HEADER ne;
927 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) ||
928 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) ||
929 (Read != sizeof(IMAGE_OS2_HEADER)))
930 {
931 /* Couldn't read header, so abort. */
932 return BINARY_DOS;
933 }
934
935 switch(ne.ne_exetyp)
936 {
937 case 2:
938 return BINARY_WIN16;
939 case 5:
940 return BINARY_DOS;
941 default:
942 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne);
943 }
944 }
945 return BINARY_DOS;
946 }
947 return BINARY_UNKNOWN;
948 }
949
950 /*
951 * @implemented
952 */
953 BOOL
954 WINAPI
955 GetBinaryTypeW (
956 LPCWSTR lpApplicationName,
957 LPDWORD lpBinaryType
958 )
959 {
960 HANDLE hFile;
961 DWORD BinType;
962
963 if(!lpApplicationName || !lpBinaryType)
964 {
965 SetLastError(ERROR_INVALID_PARAMETER);
966 return FALSE;
967 }
968
969 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL,
970 OPEN_EXISTING, 0, 0);
971 if(hFile == INVALID_HANDLE_VALUE)
972 {
973 return FALSE;
974 }
975
976 BinType = InternalGetBinaryType(hFile);
977 CloseHandle(hFile);
978
979 switch(BinType)
980 {
981 case BINARY_UNKNOWN:
982 {
983 WCHAR *dot;
984
985 /*
986 * guess from filename
987 */
988 if(!(dot = wcsrchr(lpApplicationName, L'.')))
989 {
990 return FALSE;
991 }
992 if(!lstrcmpiW(dot, L".COM"))
993 {
994 *lpBinaryType = SCS_DOS_BINARY;
995 return TRUE;
996 }
997 if(!lstrcmpiW(dot, L".PIF"))
998 {
999 *lpBinaryType = SCS_PIF_BINARY;
1000 return TRUE;
1001 }
1002 return FALSE;
1003 }
1004 case BINARY_PE_EXE32:
1005 case BINARY_PE_DLL32:
1006 {
1007 *lpBinaryType = SCS_32BIT_BINARY;
1008 return TRUE;
1009 }
1010 case BINARY_PE_EXE64:
1011 case BINARY_PE_DLL64:
1012 {
1013 *lpBinaryType = SCS_64BIT_BINARY;
1014 return TRUE;
1015 }
1016 case BINARY_WIN16:
1017 {
1018 *lpBinaryType = SCS_WOW_BINARY;
1019 return TRUE;
1020 }
1021 case BINARY_OS216:
1022 {
1023 *lpBinaryType = SCS_OS216_BINARY;
1024 return TRUE;
1025 }
1026 case BINARY_DOS:
1027 {
1028 *lpBinaryType = SCS_DOS_BINARY;
1029 return TRUE;
1030 }
1031 case BINARY_UNIX_EXE:
1032 case BINARY_UNIX_LIB:
1033 {
1034 return FALSE;
1035 }
1036 }
1037
1038 DPRINT1("Invalid binary type %lu returned!\n", BinType);
1039 return FALSE;
1040 }
1041
1042 /*
1043 * @implemented
1044 */
1045 BOOL
1046 WINAPI
1047 GetBinaryTypeA(IN LPCSTR lpApplicationName,
1048 OUT LPDWORD lpBinaryType)
1049 {
1050 ANSI_STRING ApplicationNameString;
1051 UNICODE_STRING ApplicationNameW;
1052 BOOL StringAllocated = FALSE, Result;
1053 NTSTATUS Status;
1054
1055 RtlInitAnsiString(&ApplicationNameString, lpApplicationName);
1056
1057 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength)
1058 {
1059 StringAllocated = TRUE;
1060 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE);
1061 }
1062 else
1063 {
1064 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE);
1065 }
1066
1067 if (!NT_SUCCESS(Status))
1068 {
1069 BaseSetLastNTError(Status);
1070 return FALSE;
1071 }
1072
1073 if (StringAllocated)
1074 {
1075 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType);
1076 RtlFreeUnicodeString(&ApplicationNameW);
1077 }
1078 else
1079 {
1080 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
1081 }
1082
1083 return Result;
1084 }
1085
1086 /*
1087 * @unimplemented
1088 */
1089 BOOL
1090 WINAPI
1091 CmdBatNotification (
1092 DWORD Unknown
1093 )
1094 {
1095 STUB;
1096 return FALSE;
1097 }
1098
1099 /*
1100 * @implemented
1101 */
1102 VOID
1103 WINAPI
1104 ExitVDM(BOOL IsWow, ULONG iWowTask)
1105 {
1106 BASE_API_MESSAGE ApiMessage;
1107 PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
1108
1109 /* Setup the input parameters */
1110 ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1111 ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
1112 ExitVdm->WaitObjectForVDM = NULL;
1113
1114 /* Call CSRSS */
1115 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1116 NULL,
1117 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
1118 sizeof(BASE_EXIT_VDM));
1119
1120 /* Close the returned wait object handle, if any */
1121 if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
1122 {
1123 CloseHandle(ExitVdm->WaitObjectForVDM);
1124 }
1125 }
1126
1127 /*
1128 * @implemented
1129 */
1130 BOOL
1131 WINAPI
1132 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
1133 {
1134 NTSTATUS Status;
1135 BOOL Result = FALSE;
1136 BASE_API_MESSAGE ApiMessage;
1137 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest;
1138 PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest;
1139 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
1140 ULONG NumStrings = 1;
1141
1142 if (CommandData != NULL)
1143 {
1144 /* Clear the structure */
1145 ZeroMemory(GetNextVdmCommand, sizeof(GetNextVdmCommand));
1146
1147 /* Setup the input parameters */
1148 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1149 GetNextVdmCommand->CmdLen = CommandData->CmdLen;
1150 GetNextVdmCommand->AppLen = CommandData->AppLen;
1151 GetNextVdmCommand->PifLen = CommandData->PifLen;
1152 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
1153 GetNextVdmCommand->EnvLen = CommandData->EnvLen;
1154 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
1155 GetNextVdmCommand->TitleLen = CommandData->TitleLen;
1156 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
1157
1158 /* Count the number of strings */
1159 if (CommandData->CmdLen) NumStrings++;
1160 if (CommandData->AppLen) NumStrings++;
1161 if (CommandData->PifLen) NumStrings++;
1162 if (CommandData->CurDirectoryLen) NumStrings++;
1163 if (CommandData->EnvLen) NumStrings++;
1164 if (CommandData->DesktopLen) NumStrings++;
1165 if (CommandData->TitleLen) NumStrings++;
1166 if (CommandData->ReservedLen) NumStrings++;
1167
1168 /* Allocate the capture buffer */
1169 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings,
1170 GetNextVdmCommand->CmdLen
1171 + GetNextVdmCommand->AppLen
1172 + GetNextVdmCommand->PifLen
1173 + GetNextVdmCommand->CurDirectoryLen
1174 + GetNextVdmCommand->EnvLen
1175 + GetNextVdmCommand->DesktopLen
1176 + GetNextVdmCommand->TitleLen
1177 + GetNextVdmCommand->ReservedLen
1178 + sizeof(STARTUPINFOA));
1179 if (CaptureBuffer == NULL)
1180 {
1181 BaseSetLastNTError(STATUS_NO_MEMORY);
1182 goto Cleanup;
1183 }
1184
1185 /* Allocate memory for the startup info */
1186 CsrAllocateMessagePointer(CaptureBuffer,
1187 sizeof(STARTUPINFOA),
1188 (PVOID*)&GetNextVdmCommand->StartupInfo);
1189
1190 if (CommandData->CmdLen)
1191 {
1192 /* Allocate memory for the command line */
1193 CsrAllocateMessagePointer(CaptureBuffer,
1194 CommandData->CmdLen,
1195 (PVOID*)&GetNextVdmCommand->CmdLine);
1196 }
1197
1198 if (CommandData->AppLen)
1199 {
1200 /* Allocate memory for the application name */
1201 CsrAllocateMessagePointer(CaptureBuffer,
1202 CommandData->AppLen,
1203 (PVOID*)&GetNextVdmCommand->AppName);
1204 }
1205
1206 if (CommandData->PifLen)
1207 {
1208 /* Allocate memory for the PIF file name */
1209 CsrAllocateMessagePointer(CaptureBuffer,
1210 CommandData->PifLen,
1211 (PVOID*)&GetNextVdmCommand->PifFile);
1212 }
1213
1214 if (CommandData->CurDirectoryLen)
1215 {
1216 /* Allocate memory for the current directory */
1217 CsrAllocateMessagePointer(CaptureBuffer,
1218 CommandData->CurDirectoryLen,
1219 (PVOID*)&GetNextVdmCommand->CurDirectory);
1220 }
1221
1222 if (CommandData->EnvLen)
1223 {
1224 /* Allocate memory for the environment */
1225 CsrAllocateMessagePointer(CaptureBuffer,
1226 CommandData->EnvLen,
1227 (PVOID*)&GetNextVdmCommand->Env);
1228 }
1229
1230 if (CommandData->DesktopLen)
1231 {
1232 /* Allocate memory for the desktop name */
1233 CsrAllocateMessagePointer(CaptureBuffer,
1234 CommandData->DesktopLen,
1235 (PVOID*)&GetNextVdmCommand->Desktop);
1236 }
1237
1238 if (CommandData->TitleLen)
1239 {
1240 /* Allocate memory for the title */
1241 CsrAllocateMessagePointer(CaptureBuffer,
1242 CommandData->TitleLen,
1243 (PVOID*)&GetNextVdmCommand->Title);
1244 }
1245
1246 if (CommandData->ReservedLen)
1247 {
1248 /* Allocate memory for the reserved parameter */
1249 CsrAllocateMessagePointer(CaptureBuffer,
1250 CommandData->ReservedLen,
1251 (PVOID*)&GetNextVdmCommand->Reserved);
1252 }
1253
1254 do
1255 {
1256 /* Call CSRSS */
1257 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1258 CaptureBuffer,
1259 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
1260 sizeof(BASE_GET_NEXT_VDM_COMMAND));
1261
1262 if (!NT_SUCCESS(Status))
1263 {
1264 BaseSetLastNTError(Status);
1265 goto Cleanup;
1266 }
1267
1268 /* Did we receive an event handle? */
1269 if (GetNextVdmCommand->WaitObjectForVDM != NULL)
1270 {
1271 /* Wait for the event to become signaled and try again */
1272 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
1273 FALSE,
1274 NULL);
1275 if (!NT_SUCCESS(Status))
1276 {
1277 BaseSetLastNTError(Status);
1278 goto Cleanup;
1279 }
1280 }
1281 }
1282 while (GetNextVdmCommand->WaitObjectForVDM != NULL);
1283
1284 /* Write back the standard handles */
1285 CommandData->StdIn = GetNextVdmCommand->StdIn;
1286 CommandData->StdOut = GetNextVdmCommand->StdOut;
1287 CommandData->StdErr = GetNextVdmCommand->StdErr;
1288
1289 /* Write back the startup info */
1290 RtlMoveMemory(&CommandData->StartupInfo,
1291 GetNextVdmCommand->StartupInfo,
1292 sizeof(STARTUPINFOA));
1293
1294 if (CommandData->CmdLen)
1295 {
1296 /* Write back the command line */
1297 RtlMoveMemory(CommandData->CmdLine,
1298 GetNextVdmCommand->CmdLine,
1299 GetNextVdmCommand->CmdLen);
1300
1301 /* Set the actual length */
1302 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1303 }
1304
1305 if (CommandData->AppLen)
1306 {
1307 /* Write back the application name */
1308 RtlMoveMemory(CommandData->AppName,
1309 GetNextVdmCommand->AppName,
1310 GetNextVdmCommand->AppLen);
1311
1312 /* Set the actual length */
1313 CommandData->AppLen = GetNextVdmCommand->AppLen;
1314 }
1315
1316 if (CommandData->PifLen)
1317 {
1318 /* Write back the PIF file name */
1319 RtlMoveMemory(CommandData->PifFile,
1320 GetNextVdmCommand->PifFile,
1321 GetNextVdmCommand->PifLen);
1322
1323 /* Set the actual length */
1324 CommandData->PifLen = GetNextVdmCommand->PifLen;
1325 }
1326
1327 if (CommandData->CurDirectoryLen)
1328 {
1329 /* Write back the current directory */
1330 RtlMoveMemory(CommandData->CurDirectory,
1331 GetNextVdmCommand->CurDirectory,
1332 GetNextVdmCommand->CurDirectoryLen);
1333
1334 /* Set the actual length */
1335 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1336 }
1337
1338 if (CommandData->EnvLen)
1339 {
1340 /* Write back the environment */
1341 RtlMoveMemory(CommandData->Env,
1342 GetNextVdmCommand->Env,
1343 GetNextVdmCommand->EnvLen);
1344
1345 /* Set the actual length */
1346 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1347 }
1348
1349 if (CommandData->DesktopLen)
1350 {
1351 /* Write back the desktop name */
1352 RtlMoveMemory(CommandData->Desktop,
1353 GetNextVdmCommand->Desktop,
1354 GetNextVdmCommand->DesktopLen);
1355
1356 /* Set the actual length */
1357 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1358 }
1359
1360 if (CommandData->TitleLen)
1361 {
1362 /* Write back the title */
1363 RtlMoveMemory(CommandData->Title,
1364 GetNextVdmCommand->Title,
1365 GetNextVdmCommand->TitleLen);
1366
1367 /* Set the actual length */
1368 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1369 }
1370
1371 if (CommandData->ReservedLen)
1372 {
1373 /* Write back the reserved parameter */
1374 RtlMoveMemory(CommandData->Reserved,
1375 GetNextVdmCommand->Reserved,
1376 GetNextVdmCommand->ReservedLen);
1377
1378 /* Set the actual length */
1379 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1380 }
1381
1382 /* Write the remaining output parameters */
1383 CommandData->TaskId = GetNextVdmCommand->iTask;
1384 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
1385 CommandData->CodePage = GetNextVdmCommand->CodePage;
1386 CommandData->ExitCode = GetNextVdmCommand->ExitCode;
1387 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
1388 CommandData->VDMState = GetNextVdmCommand->VDMState;
1389 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
1390
1391 /* It was successful */
1392 Result = TRUE;
1393 }
1394 else
1395 {
1396 /* Call CSRSS */
1397 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1398 NULL,
1399 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
1400 sizeof(BASE_IS_FIRST_VDM));
1401 if (!NT_SUCCESS(Status))
1402 {
1403 BaseSetLastNTError(Status);
1404 goto Cleanup;
1405 }
1406
1407 /* Return TRUE if this is the first VDM */
1408 Result = IsFirstVdm->FirstVDM;
1409 }
1410
1411 Cleanup:
1412 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
1413 return Result;
1414 }
1415
1416
1417 /*
1418 * @implemented
1419 */
1420 DWORD
1421 WINAPI
1422 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1423 {
1424 BASE_API_MESSAGE ApiMessage;
1425 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1426 PCSR_CAPTURE_BUFFER CaptureBuffer;
1427
1428 /* Allocate the capture buffer */
1429 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1430 if (CaptureBuffer == NULL)
1431 {
1432 BaseSetLastNTError(STATUS_NO_MEMORY);
1433 return 0;
1434 }
1435
1436 /* Setup the input parameters */
1437 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1438 CsrAllocateMessagePointer(CaptureBuffer,
1439 cchCurDirs,
1440 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1441
1442 /* Call CSRSS */
1443 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1444 CaptureBuffer,
1445 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
1446 sizeof(BASE_GETSET_VDM_CURDIRS));
1447
1448 /* Set the last error */
1449 BaseSetLastNTError(ApiMessage.Status);
1450
1451 if (NT_SUCCESS(ApiMessage.Status))
1452 {
1453 /* Copy the result */
1454 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
1455 }
1456
1457 /* Free the capture buffer */
1458 CsrFreeCaptureBuffer(CaptureBuffer);
1459
1460 /* Return the size if it was successful, or if the buffer was too small */
1461 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
1462 ? VDMCurrentDirsRequest->cchCurDirs : 0;
1463 }
1464
1465
1466 /*
1467 * @unimplemented
1468 */
1469 BOOL
1470 WINAPI
1471 RegisterConsoleVDM (
1472 DWORD Unknown0,
1473 DWORD Unknown1,
1474 DWORD Unknown2,
1475 DWORD Unknown3,
1476 DWORD Unknown4,
1477 DWORD Unknown5,
1478 DWORD Unknown6,
1479 DWORD Unknown7,
1480 DWORD Unknown8,
1481 DWORD Unknown9,
1482 DWORD Unknown10
1483 )
1484 {
1485 STUB;
1486 return FALSE;
1487 }
1488
1489
1490 /*
1491 * @unimplemented
1492 */
1493 BOOL
1494 WINAPI
1495 RegisterWowBaseHandlers (
1496 DWORD Unknown0
1497 )
1498 {
1499 STUB;
1500 return FALSE;
1501 }
1502
1503
1504 /*
1505 * @unimplemented
1506 */
1507 BOOL
1508 WINAPI
1509 RegisterWowExec (
1510 DWORD Unknown0
1511 )
1512 {
1513 STUB;
1514 return FALSE;
1515 }
1516
1517
1518 /*
1519 * @implemented
1520 */
1521 BOOL
1522 WINAPI
1523 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1524 {
1525 BASE_API_MESSAGE ApiMessage;
1526 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1527 PCSR_CAPTURE_BUFFER CaptureBuffer;
1528
1529 /* Allocate the capture buffer */
1530 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1531 if (CaptureBuffer == NULL)
1532 {
1533 BaseSetLastNTError(STATUS_NO_MEMORY);
1534 return FALSE;
1535 }
1536
1537 /* Setup the input parameters */
1538 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1539 CsrCaptureMessageBuffer(CaptureBuffer,
1540 lpszzCurDirs,
1541 cchCurDirs,
1542 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1543
1544 /* Call CSRSS */
1545 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1546 CaptureBuffer,
1547 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs),
1548 sizeof(BASE_GETSET_VDM_CURDIRS));
1549
1550 /* Free the capture buffer */
1551 CsrFreeCaptureBuffer(CaptureBuffer);
1552
1553 /* Set the last error */
1554 BaseSetLastNTError(ApiMessage.Status);
1555
1556 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE;
1557 }
1558
1559 /*
1560 * @unimplemented
1561 */
1562 DWORD
1563 WINAPI
1564 VDMConsoleOperation (
1565 DWORD Unknown0,
1566 DWORD Unknown1
1567 )
1568 {
1569 STUB;
1570 return 0;
1571 }
1572
1573
1574 /*
1575 * @unimplemented
1576 */
1577 DWORD
1578 WINAPI
1579 VDMOperationStarted (
1580 DWORD Unknown0
1581 )
1582 {
1583 STUB;
1584 return 0;
1585 }