[BASESRV][KERNEL32][NTVDM]
[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) / sizeof(CommandLine[0]),
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) / sizeof(CommandLine[0]),
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 PBASE_SET_REENTER_COUNT SetReenterCount = &ApiMessage.Data.SetReenterCountRequest;
1140 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
1141 ULONG NumStrings = 0;
1142
1143 if (CommandData != NULL)
1144 {
1145 if (CommandData->VDMState & (VDM_NOT_LOADED | VDM_NOT_READY | VDM_READY))
1146 {
1147 /* Clear the structure */
1148 ZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
1149
1150 /* Setup the input parameters */
1151 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1152 GetNextVdmCommand->CmdLen = CommandData->CmdLen;
1153 GetNextVdmCommand->AppLen = CommandData->AppLen;
1154 GetNextVdmCommand->PifLen = CommandData->PifLen;
1155 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
1156 GetNextVdmCommand->EnvLen = CommandData->EnvLen;
1157 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
1158 GetNextVdmCommand->TitleLen = CommandData->TitleLen;
1159 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
1160 GetNextVdmCommand->VDMState = CommandData->VDMState;
1161
1162 /* Count the number of strings */
1163 if (CommandData->CmdLen) NumStrings++;
1164 if (CommandData->AppLen) NumStrings++;
1165 if (CommandData->PifLen) NumStrings++;
1166 if (CommandData->CurDirectoryLen) NumStrings++;
1167 if (CommandData->EnvLen) NumStrings++;
1168 if (CommandData->DesktopLen) NumStrings++;
1169 if (CommandData->TitleLen) NumStrings++;
1170 if (CommandData->ReservedLen) NumStrings++;
1171
1172 /* Allocate the capture buffer */
1173 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
1174 GetNextVdmCommand->CmdLen
1175 + GetNextVdmCommand->AppLen
1176 + GetNextVdmCommand->PifLen
1177 + GetNextVdmCommand->CurDirectoryLen
1178 + GetNextVdmCommand->EnvLen
1179 + GetNextVdmCommand->DesktopLen
1180 + GetNextVdmCommand->TitleLen
1181 + GetNextVdmCommand->ReservedLen
1182 + sizeof(STARTUPINFOA));
1183 if (CaptureBuffer == NULL)
1184 {
1185 BaseSetLastNTError(STATUS_NO_MEMORY);
1186 goto Cleanup;
1187 }
1188
1189 /* Allocate memory for the startup info */
1190 CsrAllocateMessagePointer(CaptureBuffer,
1191 sizeof(STARTUPINFOA),
1192 (PVOID*)&GetNextVdmCommand->StartupInfo);
1193
1194 if (CommandData->CmdLen)
1195 {
1196 /* Allocate memory for the command line */
1197 CsrAllocateMessagePointer(CaptureBuffer,
1198 CommandData->CmdLen,
1199 (PVOID*)&GetNextVdmCommand->CmdLine);
1200 }
1201
1202 if (CommandData->AppLen)
1203 {
1204 /* Allocate memory for the application name */
1205 CsrAllocateMessagePointer(CaptureBuffer,
1206 CommandData->AppLen,
1207 (PVOID*)&GetNextVdmCommand->AppName);
1208 }
1209
1210 if (CommandData->PifLen)
1211 {
1212 /* Allocate memory for the PIF file name */
1213 CsrAllocateMessagePointer(CaptureBuffer,
1214 CommandData->PifLen,
1215 (PVOID*)&GetNextVdmCommand->PifFile);
1216 }
1217
1218 if (CommandData->CurDirectoryLen)
1219 {
1220 /* Allocate memory for the current directory */
1221 CsrAllocateMessagePointer(CaptureBuffer,
1222 CommandData->CurDirectoryLen,
1223 (PVOID*)&GetNextVdmCommand->CurDirectory);
1224 }
1225
1226 if (CommandData->EnvLen)
1227 {
1228 /* Allocate memory for the environment */
1229 CsrAllocateMessagePointer(CaptureBuffer,
1230 CommandData->EnvLen,
1231 (PVOID*)&GetNextVdmCommand->Env);
1232 }
1233
1234 if (CommandData->DesktopLen)
1235 {
1236 /* Allocate memory for the desktop name */
1237 CsrAllocateMessagePointer(CaptureBuffer,
1238 CommandData->DesktopLen,
1239 (PVOID*)&GetNextVdmCommand->Desktop);
1240 }
1241
1242 if (CommandData->TitleLen)
1243 {
1244 /* Allocate memory for the title */
1245 CsrAllocateMessagePointer(CaptureBuffer,
1246 CommandData->TitleLen,
1247 (PVOID*)&GetNextVdmCommand->Title);
1248 }
1249
1250 if (CommandData->ReservedLen)
1251 {
1252 /* Allocate memory for the reserved parameter */
1253 CsrAllocateMessagePointer(CaptureBuffer,
1254 CommandData->ReservedLen,
1255 (PVOID*)&GetNextVdmCommand->Reserved);
1256 }
1257
1258 do
1259 {
1260 /* Call CSRSS */
1261 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1262 CaptureBuffer,
1263 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
1264 sizeof(BASE_GET_NEXT_VDM_COMMAND));
1265
1266 if (!NT_SUCCESS(Status))
1267 {
1268 BaseSetLastNTError(Status);
1269 goto Cleanup;
1270 }
1271
1272 /* Did we receive an event handle? */
1273 if (GetNextVdmCommand->WaitObjectForVDM != NULL)
1274 {
1275 /* Wait for the event to become signaled and try again */
1276 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
1277 FALSE,
1278 NULL);
1279 if (!NT_SUCCESS(Status))
1280 {
1281 BaseSetLastNTError(Status);
1282 goto Cleanup;
1283 }
1284
1285 /* Set the retry flag and clear the exit code */
1286 GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
1287 GetNextVdmCommand->ExitCode = 0;
1288 }
1289 }
1290 while (GetNextVdmCommand->WaitObjectForVDM != NULL);
1291
1292 /* Write back the standard handles */
1293 CommandData->StdIn = GetNextVdmCommand->StdIn;
1294 CommandData->StdOut = GetNextVdmCommand->StdOut;
1295 CommandData->StdErr = GetNextVdmCommand->StdErr;
1296
1297 /* Write back the startup info */
1298 RtlMoveMemory(&CommandData->StartupInfo,
1299 GetNextVdmCommand->StartupInfo,
1300 sizeof(STARTUPINFOA));
1301
1302 if (CommandData->CmdLen)
1303 {
1304 /* Write back the command line */
1305 RtlMoveMemory(CommandData->CmdLine,
1306 GetNextVdmCommand->CmdLine,
1307 GetNextVdmCommand->CmdLen);
1308
1309 /* Set the actual length */
1310 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1311 }
1312
1313 if (CommandData->AppLen)
1314 {
1315 /* Write back the application name */
1316 RtlMoveMemory(CommandData->AppName,
1317 GetNextVdmCommand->AppName,
1318 GetNextVdmCommand->AppLen);
1319
1320 /* Set the actual length */
1321 CommandData->AppLen = GetNextVdmCommand->AppLen;
1322 }
1323
1324 if (CommandData->PifLen)
1325 {
1326 /* Write back the PIF file name */
1327 RtlMoveMemory(CommandData->PifFile,
1328 GetNextVdmCommand->PifFile,
1329 GetNextVdmCommand->PifLen);
1330
1331 /* Set the actual length */
1332 CommandData->PifLen = GetNextVdmCommand->PifLen;
1333 }
1334
1335 if (CommandData->CurDirectoryLen)
1336 {
1337 /* Write back the current directory */
1338 RtlMoveMemory(CommandData->CurDirectory,
1339 GetNextVdmCommand->CurDirectory,
1340 GetNextVdmCommand->CurDirectoryLen);
1341
1342 /* Set the actual length */
1343 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1344 }
1345
1346 if (CommandData->EnvLen)
1347 {
1348 /* Write back the environment */
1349 RtlMoveMemory(CommandData->Env,
1350 GetNextVdmCommand->Env,
1351 GetNextVdmCommand->EnvLen);
1352
1353 /* Set the actual length */
1354 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1355 }
1356
1357 if (CommandData->DesktopLen)
1358 {
1359 /* Write back the desktop name */
1360 RtlMoveMemory(CommandData->Desktop,
1361 GetNextVdmCommand->Desktop,
1362 GetNextVdmCommand->DesktopLen);
1363
1364 /* Set the actual length */
1365 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1366 }
1367
1368 if (CommandData->TitleLen)
1369 {
1370 /* Write back the title */
1371 RtlMoveMemory(CommandData->Title,
1372 GetNextVdmCommand->Title,
1373 GetNextVdmCommand->TitleLen);
1374
1375 /* Set the actual length */
1376 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1377 }
1378
1379 if (CommandData->ReservedLen)
1380 {
1381 /* Write back the reserved parameter */
1382 RtlMoveMemory(CommandData->Reserved,
1383 GetNextVdmCommand->Reserved,
1384 GetNextVdmCommand->ReservedLen);
1385
1386 /* Set the actual length */
1387 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1388 }
1389
1390 /* Write the remaining output parameters */
1391 CommandData->TaskId = GetNextVdmCommand->iTask;
1392 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
1393 CommandData->CodePage = GetNextVdmCommand->CodePage;
1394 CommandData->ExitCode = GetNextVdmCommand->ExitCode;
1395 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
1396 CommandData->VDMState = GetNextVdmCommand->VDMState;
1397 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
1398
1399 /* It was successful */
1400 Result = TRUE;
1401 }
1402 else if ((CommandData->VDMState == VDM_INC_REENTER_COUNT)
1403 || (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
1404 {
1405 /* Setup the input parameters */
1406 SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1407 SetReenterCount->fIncDec = CommandData->VDMState;
1408
1409 /* Call CSRSS */
1410 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1411 NULL,
1412 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
1413 sizeof(BASE_SET_REENTER_COUNT));
1414 BaseSetLastNTError(Status);
1415 Result = NT_SUCCESS(Status);
1416 }
1417 else
1418 {
1419 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1420 Result = FALSE;
1421 }
1422 }
1423 else
1424 {
1425 /* Call CSRSS */
1426 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1427 NULL,
1428 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
1429 sizeof(BASE_IS_FIRST_VDM));
1430 if (!NT_SUCCESS(Status))
1431 {
1432 BaseSetLastNTError(Status);
1433 goto Cleanup;
1434 }
1435
1436 /* Return TRUE if this is the first VDM */
1437 Result = IsFirstVdm->FirstVDM;
1438 }
1439
1440 Cleanup:
1441 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
1442 return Result;
1443 }
1444
1445
1446 /*
1447 * @implemented
1448 */
1449 DWORD
1450 WINAPI
1451 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1452 {
1453 BASE_API_MESSAGE ApiMessage;
1454 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1455 PCSR_CAPTURE_BUFFER CaptureBuffer;
1456
1457 /* Allocate the capture buffer */
1458 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1459 if (CaptureBuffer == NULL)
1460 {
1461 BaseSetLastNTError(STATUS_NO_MEMORY);
1462 return 0;
1463 }
1464
1465 /* Setup the input parameters */
1466 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1467 CsrAllocateMessagePointer(CaptureBuffer,
1468 cchCurDirs,
1469 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1470
1471 /* Call CSRSS */
1472 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1473 CaptureBuffer,
1474 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
1475 sizeof(BASE_GETSET_VDM_CURDIRS));
1476
1477 /* Set the last error */
1478 BaseSetLastNTError(ApiMessage.Status);
1479
1480 if (NT_SUCCESS(ApiMessage.Status))
1481 {
1482 /* Copy the result */
1483 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
1484 }
1485
1486 /* Free the capture buffer */
1487 CsrFreeCaptureBuffer(CaptureBuffer);
1488
1489 /* Return the size if it was successful, or if the buffer was too small */
1490 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
1491 ? VDMCurrentDirsRequest->cchCurDirs : 0;
1492 }
1493
1494
1495 /*
1496 * @unimplemented
1497 */
1498 BOOL
1499 WINAPI
1500 RegisterConsoleVDM (
1501 DWORD Unknown0,
1502 DWORD Unknown1,
1503 DWORD Unknown2,
1504 DWORD Unknown3,
1505 DWORD Unknown4,
1506 DWORD Unknown5,
1507 DWORD Unknown6,
1508 DWORD Unknown7,
1509 DWORD Unknown8,
1510 DWORD Unknown9,
1511 DWORD Unknown10
1512 )
1513 {
1514 STUB;
1515 return FALSE;
1516 }
1517
1518
1519 /*
1520 * @unimplemented
1521 */
1522 BOOL
1523 WINAPI
1524 RegisterWowBaseHandlers (
1525 DWORD Unknown0
1526 )
1527 {
1528 STUB;
1529 return FALSE;
1530 }
1531
1532
1533 /*
1534 * @unimplemented
1535 */
1536 BOOL
1537 WINAPI
1538 RegisterWowExec (
1539 DWORD Unknown0
1540 )
1541 {
1542 STUB;
1543 return FALSE;
1544 }
1545
1546
1547 /*
1548 * @implemented
1549 */
1550 BOOL
1551 WINAPI
1552 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1553 {
1554 BASE_API_MESSAGE ApiMessage;
1555 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1556 PCSR_CAPTURE_BUFFER CaptureBuffer;
1557
1558 /* Allocate the capture buffer */
1559 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1560 if (CaptureBuffer == NULL)
1561 {
1562 BaseSetLastNTError(STATUS_NO_MEMORY);
1563 return FALSE;
1564 }
1565
1566 /* Setup the input parameters */
1567 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1568 CsrCaptureMessageBuffer(CaptureBuffer,
1569 lpszzCurDirs,
1570 cchCurDirs,
1571 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1572
1573 /* Call CSRSS */
1574 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1575 CaptureBuffer,
1576 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs),
1577 sizeof(BASE_GETSET_VDM_CURDIRS));
1578
1579 /* Free the capture buffer */
1580 CsrFreeCaptureBuffer(CaptureBuffer);
1581
1582 /* Set the last error */
1583 BaseSetLastNTError(ApiMessage.Status);
1584
1585 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE;
1586 }
1587
1588 /*
1589 * @unimplemented
1590 */
1591 DWORD
1592 WINAPI
1593 VDMConsoleOperation (
1594 DWORD Unknown0,
1595 DWORD Unknown1
1596 )
1597 {
1598 STUB;
1599 return 0;
1600 }
1601
1602
1603 /*
1604 * @unimplemented
1605 */
1606 DWORD
1607 WINAPI
1608 VDMOperationStarted (
1609 DWORD Unknown0
1610 )
1611 {
1612 STUB;
1613 return 0;
1614 }