c37a3cf3589cc41f313171df65db66933ede1c8b
[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, &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 DPRINT1("BaseCreateVDMEnvironment is half-plemented!\n");
722
723 /* Terminate it */
724 *p++ = UNICODE_NULL;
725
726 /* Initialize the unicode string to hold it */
727 EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
728 RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
729 UnicodeEnv->Length = (USHORT)EnvironmentSize;
730
731 /* Create the ASCII version of it */
732 Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
733 if (!NT_SUCCESS(Status))
734 {
735 /* Set last error if conversion failure */
736 BaseSetLastNTError(Status);
737 }
738 else
739 {
740 /* Everything went okay, so return success */
741 Result = TRUE;
742 NewEnvironment = NULL;
743 }
744
745 Quickie:
746 /* Cleanup path starts here, start by destroying the envrionment copy */
747 if (!(lpEnvironment) && (Environment)) RtlDestroyEnvironment(Environment);
748
749 /* See if we are here due to failure */
750 if (NewEnvironment)
751 {
752 /* Initialize the paths to be empty */
753 RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0);
754 RtlInitEmptyAnsiString(AnsiEnv, NULL, 0);
755
756 /* Free the environment copy */
757 RegionSize = 0;
758 Status = NtFreeVirtualMemory(NtCurrentProcess(),
759 (PVOID*)&NewEnvironment,
760 &RegionSize,
761 MEM_RELEASE);
762 ASSERT(NT_SUCCESS(Status));
763 }
764
765 /* Return the result */
766 return Result;
767 }
768
769
770 /* Check whether a file is an OS/2 or a very old Windows executable
771 * by testing on import of KERNEL.
772 *
773 * FIXME: is reading the module imports the only way of discerning
774 * old Windows binaries from OS/2 ones ? At least it seems so...
775 */
776 static DWORD WINAPI
777 InternalIsOS2OrOldWin(HANDLE hFile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
778 {
779 DWORD CurPos;
780 LPWORD modtab = NULL;
781 LPSTR nametab = NULL;
782 DWORD Read, Ret;
783 int i;
784
785 Ret = BINARY_OS216;
786 CurPos = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
787
788 /* read modref table */
789 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_modtab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
790 (!(modtab = HeapAlloc(GetProcessHeap(), 0, ne->ne_cmod * sizeof(WORD)))) ||
791 (!(ReadFile(hFile, modtab, ne->ne_cmod * sizeof(WORD), &Read, NULL))) ||
792 (Read != (DWORD)ne->ne_cmod * sizeof(WORD)))
793 {
794 goto broken;
795 }
796
797 /* read imported names table */
798 if((SetFilePointer(hFile, mz->e_lfanew + ne->ne_imptab, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
799 (!(nametab = HeapAlloc(GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) ||
800 (!(ReadFile(hFile, nametab, ne->ne_enttab - ne->ne_imptab, &Read, NULL))) ||
801 (Read != (DWORD)ne->ne_enttab - ne->ne_imptab))
802 {
803 goto broken;
804 }
805
806 for(i = 0; i < ne->ne_cmod; i++)
807 {
808 LPSTR module;
809 module = &nametab[modtab[i]];
810 if(!strncmp(&module[1], "KERNEL", module[0]))
811 {
812 /* very old windows file */
813 Ret = BINARY_WIN16;
814 goto done;
815 }
816 }
817
818 broken:
819 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
820
821 done:
822 HeapFree(GetProcessHeap(), 0, modtab);
823 HeapFree(GetProcessHeap(), 0, nametab);
824 SetFilePointer(hFile, CurPos, NULL, FILE_BEGIN);
825 return Ret;
826 }
827
828 static DWORD WINAPI
829 InternalGetBinaryType(HANDLE hFile)
830 {
831 union
832 {
833 struct
834 {
835 unsigned char magic[4];
836 unsigned char ignored[12];
837 unsigned short type;
838 } elf;
839 struct
840 {
841 unsigned long magic;
842 unsigned long cputype;
843 unsigned long cpusubtype;
844 unsigned long filetype;
845 } macho;
846 IMAGE_DOS_HEADER mz;
847 } Header;
848 char magic[4];
849 DWORD Read;
850
851 if((SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
852 (!ReadFile(hFile, &Header, sizeof(Header), &Read, NULL) ||
853 (Read != sizeof(Header))))
854 {
855 return BINARY_UNKNOWN;
856 }
857
858 if(!memcmp(Header.elf.magic, "\177ELF", sizeof(Header.elf.magic)))
859 {
860 /* FIXME: we don't bother to check byte order, architecture, etc. */
861 switch(Header.elf.type)
862 {
863 case 2:
864 return BINARY_UNIX_EXE;
865 case 3:
866 return BINARY_UNIX_LIB;
867 }
868 return BINARY_UNKNOWN;
869 }
870
871 /* Mach-o File with Endian set to Big Endian or Little Endian*/
872 if(Header.macho.magic == 0xFEEDFACE ||
873 Header.macho.magic == 0xCEFAEDFE)
874 {
875 switch(Header.macho.filetype)
876 {
877 case 0x8:
878 /* MH_BUNDLE */
879 return BINARY_UNIX_LIB;
880 }
881 return BINARY_UNKNOWN;
882 }
883
884 /* Not ELF, try DOS */
885 if(Header.mz.e_magic == IMAGE_DOS_SIGNATURE)
886 {
887 /* We do have a DOS image so we will now try to seek into
888 * the file by the amount indicated by the field
889 * "Offset to extended header" and read in the
890 * "magic" field information at that location.
891 * This will tell us if there is more header information
892 * to read or not.
893 */
894 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) ||
895 (!ReadFile(hFile, magic, sizeof(magic), &Read, NULL) ||
896 (Read != sizeof(magic))))
897 {
898 return BINARY_DOS;
899 }
900
901 /* Reading the magic field succeeded so
902 * we will try to determine what type it is.
903 */
904 if(!memcmp(magic, "PE\0\0", sizeof(magic)))
905 {
906 IMAGE_FILE_HEADER FileHeader;
907 if(!ReadFile(hFile, &FileHeader, sizeof(IMAGE_FILE_HEADER), &Read, NULL) ||
908 (Read != sizeof(IMAGE_FILE_HEADER)))
909 {
910 return BINARY_DOS;
911 }
912
913 /* FIXME - detect 32/64 bit */
914
915 if(FileHeader.Characteristics & IMAGE_FILE_DLL)
916 return BINARY_PE_DLL32;
917 return BINARY_PE_EXE32;
918 }
919
920 if(!memcmp(magic, "NE", 2))
921 {
922 /* This is a Windows executable (NE) header. This can
923 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
924 * DOS program (running under a DOS extender). To decide
925 * which, we'll have to read the NE header.
926 */
927 IMAGE_OS2_HEADER ne;
928 if((SetFilePointer(hFile, Header.mz.e_lfanew, NULL, FILE_BEGIN) == 1) ||
929 !ReadFile(hFile, &ne, sizeof(IMAGE_OS2_HEADER), &Read, NULL) ||
930 (Read != sizeof(IMAGE_OS2_HEADER)))
931 {
932 /* Couldn't read header, so abort. */
933 return BINARY_DOS;
934 }
935
936 switch(ne.ne_exetyp)
937 {
938 case 2:
939 return BINARY_WIN16;
940 case 5:
941 return BINARY_DOS;
942 default:
943 return InternalIsOS2OrOldWin(hFile, &Header.mz, &ne);
944 }
945 }
946 return BINARY_DOS;
947 }
948 return BINARY_UNKNOWN;
949 }
950
951 /*
952 * @implemented
953 */
954 BOOL
955 WINAPI
956 GetBinaryTypeW (
957 LPCWSTR lpApplicationName,
958 LPDWORD lpBinaryType
959 )
960 {
961 HANDLE hFile;
962 DWORD BinType;
963
964 if(!lpApplicationName || !lpBinaryType)
965 {
966 SetLastError(ERROR_INVALID_PARAMETER);
967 return FALSE;
968 }
969
970 hFile = CreateFileW(lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL,
971 OPEN_EXISTING, 0, 0);
972 if(hFile == INVALID_HANDLE_VALUE)
973 {
974 return FALSE;
975 }
976
977 BinType = InternalGetBinaryType(hFile);
978 CloseHandle(hFile);
979
980 switch(BinType)
981 {
982 case BINARY_UNKNOWN:
983 {
984 WCHAR *dot;
985
986 /*
987 * guess from filename
988 */
989 if(!(dot = wcsrchr(lpApplicationName, L'.')))
990 {
991 return FALSE;
992 }
993 if(!lstrcmpiW(dot, L".COM"))
994 {
995 *lpBinaryType = SCS_DOS_BINARY;
996 return TRUE;
997 }
998 if(!lstrcmpiW(dot, L".PIF"))
999 {
1000 *lpBinaryType = SCS_PIF_BINARY;
1001 return TRUE;
1002 }
1003 return FALSE;
1004 }
1005 case BINARY_PE_EXE32:
1006 case BINARY_PE_DLL32:
1007 {
1008 *lpBinaryType = SCS_32BIT_BINARY;
1009 return TRUE;
1010 }
1011 case BINARY_PE_EXE64:
1012 case BINARY_PE_DLL64:
1013 {
1014 *lpBinaryType = SCS_64BIT_BINARY;
1015 return TRUE;
1016 }
1017 case BINARY_WIN16:
1018 {
1019 *lpBinaryType = SCS_WOW_BINARY;
1020 return TRUE;
1021 }
1022 case BINARY_OS216:
1023 {
1024 *lpBinaryType = SCS_OS216_BINARY;
1025 return TRUE;
1026 }
1027 case BINARY_DOS:
1028 {
1029 *lpBinaryType = SCS_DOS_BINARY;
1030 return TRUE;
1031 }
1032 case BINARY_UNIX_EXE:
1033 case BINARY_UNIX_LIB:
1034 {
1035 return FALSE;
1036 }
1037 }
1038
1039 DPRINT1("Invalid binary type %lu returned!\n", BinType);
1040 return FALSE;
1041 }
1042
1043 /*
1044 * @implemented
1045 */
1046 BOOL
1047 WINAPI
1048 GetBinaryTypeA(IN LPCSTR lpApplicationName,
1049 OUT LPDWORD lpBinaryType)
1050 {
1051 ANSI_STRING ApplicationNameString;
1052 UNICODE_STRING ApplicationNameW;
1053 BOOL StringAllocated = FALSE, Result;
1054 NTSTATUS Status;
1055
1056 RtlInitAnsiString(&ApplicationNameString, lpApplicationName);
1057
1058 if (ApplicationNameString.Length * sizeof(WCHAR) >= NtCurrentTeb()->StaticUnicodeString.MaximumLength)
1059 {
1060 StringAllocated = TRUE;
1061 Status = RtlAnsiStringToUnicodeString(&ApplicationNameW, &ApplicationNameString, TRUE);
1062 }
1063 else
1064 {
1065 Status = RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString), &ApplicationNameString, FALSE);
1066 }
1067
1068 if (!NT_SUCCESS(Status))
1069 {
1070 BaseSetLastNTError(Status);
1071 return FALSE;
1072 }
1073
1074 if (StringAllocated)
1075 {
1076 Result = GetBinaryTypeW(ApplicationNameW.Buffer, lpBinaryType);
1077 RtlFreeUnicodeString(&ApplicationNameW);
1078 }
1079 else
1080 {
1081 Result = GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
1082 }
1083
1084 return Result;
1085 }
1086
1087 /*
1088 * @unimplemented
1089 */
1090 BOOL
1091 WINAPI
1092 CmdBatNotification (
1093 DWORD Unknown
1094 )
1095 {
1096 STUB;
1097 return FALSE;
1098 }
1099
1100 /*
1101 * @implemented
1102 */
1103 VOID
1104 WINAPI
1105 ExitVDM(BOOL IsWow, ULONG iWowTask)
1106 {
1107 BASE_API_MESSAGE ApiMessage;
1108 PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
1109
1110 /* Setup the input parameters */
1111 ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1112 ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
1113 ExitVdm->WaitObjectForVDM = NULL;
1114
1115 /* Call CSRSS */
1116 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1117 NULL,
1118 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
1119 sizeof(BASE_EXIT_VDM));
1120
1121 /* Close the returned wait object handle, if any */
1122 if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
1123 {
1124 CloseHandle(ExitVdm->WaitObjectForVDM);
1125 }
1126 }
1127
1128 /*
1129 * @implemented
1130 */
1131 BOOL
1132 WINAPI
1133 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
1134 {
1135 NTSTATUS Status;
1136 BOOL Result = FALSE;
1137 BASE_API_MESSAGE ApiMessage;
1138 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest;
1139 PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest;
1140 PBASE_SET_REENTER_COUNT SetReenterCount = &ApiMessage.Data.SetReenterCountRequest;
1141 PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
1142 ULONG NumStrings = 0;
1143
1144 if (CommandData != NULL)
1145 {
1146 if (CommandData->VDMState & (VDM_NOT_LOADED | VDM_NOT_READY | VDM_READY))
1147 {
1148 /* Clear the structure */
1149 ZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
1150
1151 /* Setup the input parameters */
1152 GetNextVdmCommand->iTask = CommandData->TaskId;
1153 GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1154 GetNextVdmCommand->CmdLen = CommandData->CmdLen;
1155 GetNextVdmCommand->AppLen = CommandData->AppLen;
1156 GetNextVdmCommand->PifLen = CommandData->PifLen;
1157 GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
1158 GetNextVdmCommand->EnvLen = CommandData->EnvLen;
1159 GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
1160 GetNextVdmCommand->TitleLen = CommandData->TitleLen;
1161 GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
1162 GetNextVdmCommand->VDMState = CommandData->VDMState;
1163
1164 /* Count the number of strings */
1165 if (CommandData->CmdLen) NumStrings++;
1166 if (CommandData->AppLen) NumStrings++;
1167 if (CommandData->PifLen) NumStrings++;
1168 if (CommandData->CurDirectoryLen) NumStrings++;
1169 if (CommandData->EnvLen) NumStrings++;
1170 if (CommandData->DesktopLen) NumStrings++;
1171 if (CommandData->TitleLen) NumStrings++;
1172 if (CommandData->ReservedLen) NumStrings++;
1173
1174 /* Allocate the capture buffer */
1175 CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
1176 GetNextVdmCommand->CmdLen
1177 + GetNextVdmCommand->AppLen
1178 + GetNextVdmCommand->PifLen
1179 + GetNextVdmCommand->CurDirectoryLen
1180 + GetNextVdmCommand->EnvLen
1181 + GetNextVdmCommand->DesktopLen
1182 + GetNextVdmCommand->TitleLen
1183 + GetNextVdmCommand->ReservedLen
1184 + sizeof(STARTUPINFOA));
1185 if (CaptureBuffer == NULL)
1186 {
1187 BaseSetLastNTError(STATUS_NO_MEMORY);
1188 goto Cleanup;
1189 }
1190
1191 /* Allocate memory for the startup info */
1192 CsrAllocateMessagePointer(CaptureBuffer,
1193 sizeof(STARTUPINFOA),
1194 (PVOID*)&GetNextVdmCommand->StartupInfo);
1195
1196 if (CommandData->CmdLen)
1197 {
1198 /* Allocate memory for the command line */
1199 CsrAllocateMessagePointer(CaptureBuffer,
1200 CommandData->CmdLen,
1201 (PVOID*)&GetNextVdmCommand->CmdLine);
1202 }
1203
1204 if (CommandData->AppLen)
1205 {
1206 /* Allocate memory for the application name */
1207 CsrAllocateMessagePointer(CaptureBuffer,
1208 CommandData->AppLen,
1209 (PVOID*)&GetNextVdmCommand->AppName);
1210 }
1211
1212 if (CommandData->PifLen)
1213 {
1214 /* Allocate memory for the PIF file name */
1215 CsrAllocateMessagePointer(CaptureBuffer,
1216 CommandData->PifLen,
1217 (PVOID*)&GetNextVdmCommand->PifFile);
1218 }
1219
1220 if (CommandData->CurDirectoryLen)
1221 {
1222 /* Allocate memory for the current directory */
1223 CsrAllocateMessagePointer(CaptureBuffer,
1224 CommandData->CurDirectoryLen,
1225 (PVOID*)&GetNextVdmCommand->CurDirectory);
1226 }
1227
1228 if (CommandData->EnvLen)
1229 {
1230 /* Allocate memory for the environment */
1231 CsrAllocateMessagePointer(CaptureBuffer,
1232 CommandData->EnvLen,
1233 (PVOID*)&GetNextVdmCommand->Env);
1234 }
1235
1236 if (CommandData->DesktopLen)
1237 {
1238 /* Allocate memory for the desktop name */
1239 CsrAllocateMessagePointer(CaptureBuffer,
1240 CommandData->DesktopLen,
1241 (PVOID*)&GetNextVdmCommand->Desktop);
1242 }
1243
1244 if (CommandData->TitleLen)
1245 {
1246 /* Allocate memory for the title */
1247 CsrAllocateMessagePointer(CaptureBuffer,
1248 CommandData->TitleLen,
1249 (PVOID*)&GetNextVdmCommand->Title);
1250 }
1251
1252 if (CommandData->ReservedLen)
1253 {
1254 /* Allocate memory for the reserved parameter */
1255 CsrAllocateMessagePointer(CaptureBuffer,
1256 CommandData->ReservedLen,
1257 (PVOID*)&GetNextVdmCommand->Reserved);
1258 }
1259
1260 do
1261 {
1262 /* Call CSRSS */
1263 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1264 CaptureBuffer,
1265 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
1266 sizeof(BASE_GET_NEXT_VDM_COMMAND));
1267
1268 if (!NT_SUCCESS(Status))
1269 {
1270 BaseSetLastNTError(Status);
1271 goto Cleanup;
1272 }
1273
1274 /* Did we receive an event handle? */
1275 if (GetNextVdmCommand->WaitObjectForVDM != NULL)
1276 {
1277 /* Wait for the event to become signaled and try again */
1278 Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
1279 FALSE,
1280 NULL);
1281 if (!NT_SUCCESS(Status))
1282 {
1283 BaseSetLastNTError(Status);
1284 goto Cleanup;
1285 }
1286
1287 /* Set the retry flag and clear the exit code */
1288 GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
1289 GetNextVdmCommand->ExitCode = 0;
1290 }
1291 }
1292 while (GetNextVdmCommand->WaitObjectForVDM != NULL);
1293
1294 /* Write back the standard handles */
1295 CommandData->StdIn = GetNextVdmCommand->StdIn;
1296 CommandData->StdOut = GetNextVdmCommand->StdOut;
1297 CommandData->StdErr = GetNextVdmCommand->StdErr;
1298
1299 /* Write back the startup info */
1300 RtlMoveMemory(&CommandData->StartupInfo,
1301 GetNextVdmCommand->StartupInfo,
1302 sizeof(STARTUPINFOA));
1303
1304 if (CommandData->CmdLen)
1305 {
1306 /* Write back the command line */
1307 RtlMoveMemory(CommandData->CmdLine,
1308 GetNextVdmCommand->CmdLine,
1309 GetNextVdmCommand->CmdLen);
1310
1311 /* Set the actual length */
1312 CommandData->CmdLen = GetNextVdmCommand->CmdLen;
1313 }
1314
1315 if (CommandData->AppLen)
1316 {
1317 /* Write back the application name */
1318 RtlMoveMemory(CommandData->AppName,
1319 GetNextVdmCommand->AppName,
1320 GetNextVdmCommand->AppLen);
1321
1322 /* Set the actual length */
1323 CommandData->AppLen = GetNextVdmCommand->AppLen;
1324 }
1325
1326 if (CommandData->PifLen)
1327 {
1328 /* Write back the PIF file name */
1329 RtlMoveMemory(CommandData->PifFile,
1330 GetNextVdmCommand->PifFile,
1331 GetNextVdmCommand->PifLen);
1332
1333 /* Set the actual length */
1334 CommandData->PifLen = GetNextVdmCommand->PifLen;
1335 }
1336
1337 if (CommandData->CurDirectoryLen)
1338 {
1339 /* Write back the current directory */
1340 RtlMoveMemory(CommandData->CurDirectory,
1341 GetNextVdmCommand->CurDirectory,
1342 GetNextVdmCommand->CurDirectoryLen);
1343
1344 /* Set the actual length */
1345 CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
1346 }
1347
1348 if (CommandData->EnvLen)
1349 {
1350 /* Write back the environment */
1351 RtlMoveMemory(CommandData->Env,
1352 GetNextVdmCommand->Env,
1353 GetNextVdmCommand->EnvLen);
1354
1355 /* Set the actual length */
1356 CommandData->EnvLen = GetNextVdmCommand->EnvLen;
1357 }
1358
1359 if (CommandData->DesktopLen)
1360 {
1361 /* Write back the desktop name */
1362 RtlMoveMemory(CommandData->Desktop,
1363 GetNextVdmCommand->Desktop,
1364 GetNextVdmCommand->DesktopLen);
1365
1366 /* Set the actual length */
1367 CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
1368 }
1369
1370 if (CommandData->TitleLen)
1371 {
1372 /* Write back the title */
1373 RtlMoveMemory(CommandData->Title,
1374 GetNextVdmCommand->Title,
1375 GetNextVdmCommand->TitleLen);
1376
1377 /* Set the actual length */
1378 CommandData->TitleLen = GetNextVdmCommand->TitleLen;
1379 }
1380
1381 if (CommandData->ReservedLen)
1382 {
1383 /* Write back the reserved parameter */
1384 RtlMoveMemory(CommandData->Reserved,
1385 GetNextVdmCommand->Reserved,
1386 GetNextVdmCommand->ReservedLen);
1387
1388 /* Set the actual length */
1389 CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
1390 }
1391
1392 /* Write the remaining output parameters */
1393 CommandData->TaskId = GetNextVdmCommand->iTask;
1394 CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
1395 CommandData->CodePage = GetNextVdmCommand->CodePage;
1396 CommandData->ExitCode = GetNextVdmCommand->ExitCode;
1397 CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
1398 CommandData->VDMState = GetNextVdmCommand->VDMState;
1399 CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
1400
1401 /* It was successful */
1402 Result = TRUE;
1403 }
1404 else if ((CommandData->VDMState == VDM_INC_REENTER_COUNT)
1405 || (CommandData->VDMState == VDM_DEC_REENTER_COUNT))
1406 {
1407 /* Setup the input parameters */
1408 SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
1409 SetReenterCount->fIncDec = CommandData->VDMState;
1410
1411 /* Call CSRSS */
1412 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1413 NULL,
1414 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
1415 sizeof(BASE_SET_REENTER_COUNT));
1416 BaseSetLastNTError(Status);
1417 Result = NT_SUCCESS(Status);
1418 }
1419 else
1420 {
1421 BaseSetLastNTError(STATUS_INVALID_PARAMETER);
1422 Result = FALSE;
1423 }
1424 }
1425 else
1426 {
1427 /* Call CSRSS */
1428 Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1429 NULL,
1430 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
1431 sizeof(BASE_IS_FIRST_VDM));
1432 if (!NT_SUCCESS(Status))
1433 {
1434 BaseSetLastNTError(Status);
1435 goto Cleanup;
1436 }
1437
1438 /* Return TRUE if this is the first VDM */
1439 Result = IsFirstVdm->FirstVDM;
1440 }
1441
1442 Cleanup:
1443 if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
1444 return Result;
1445 }
1446
1447
1448 /*
1449 * @implemented
1450 */
1451 DWORD
1452 WINAPI
1453 GetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1454 {
1455 BASE_API_MESSAGE ApiMessage;
1456 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1457 PCSR_CAPTURE_BUFFER CaptureBuffer;
1458
1459 /* Allocate the capture buffer */
1460 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1461 if (CaptureBuffer == NULL)
1462 {
1463 BaseSetLastNTError(STATUS_NO_MEMORY);
1464 return 0;
1465 }
1466
1467 /* Setup the input parameters */
1468 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1469 CsrAllocateMessagePointer(CaptureBuffer,
1470 cchCurDirs,
1471 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1472
1473 /* Call CSRSS */
1474 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1475 CaptureBuffer,
1476 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMCurDirs),
1477 sizeof(BASE_GETSET_VDM_CURDIRS));
1478
1479 /* Set the last error */
1480 BaseSetLastNTError(ApiMessage.Status);
1481
1482 if (NT_SUCCESS(ApiMessage.Status))
1483 {
1484 /* Copy the result */
1485 RtlMoveMemory(lpszzCurDirs, VDMCurrentDirsRequest->lpszzCurDirs, cchCurDirs);
1486 }
1487
1488 /* Free the capture buffer */
1489 CsrFreeCaptureBuffer(CaptureBuffer);
1490
1491 /* Return the size if it was successful, or if the buffer was too small */
1492 return (NT_SUCCESS(ApiMessage.Status) || (ApiMessage.Status == STATUS_BUFFER_TOO_SMALL))
1493 ? VDMCurrentDirsRequest->cchCurDirs : 0;
1494 }
1495
1496
1497 /*
1498 * @unimplemented
1499 */
1500 BOOL
1501 WINAPI
1502 RegisterConsoleVDM (
1503 DWORD Unknown0,
1504 DWORD Unknown1,
1505 DWORD Unknown2,
1506 DWORD Unknown3,
1507 DWORD Unknown4,
1508 DWORD Unknown5,
1509 DWORD Unknown6,
1510 DWORD Unknown7,
1511 DWORD Unknown8,
1512 DWORD Unknown9,
1513 DWORD Unknown10
1514 )
1515 {
1516 STUB;
1517 return FALSE;
1518 }
1519
1520
1521 /*
1522 * @unimplemented
1523 */
1524 BOOL
1525 WINAPI
1526 RegisterWowBaseHandlers (
1527 DWORD Unknown0
1528 )
1529 {
1530 STUB;
1531 return FALSE;
1532 }
1533
1534
1535 /*
1536 * @unimplemented
1537 */
1538 BOOL
1539 WINAPI
1540 RegisterWowExec (
1541 DWORD Unknown0
1542 )
1543 {
1544 STUB;
1545 return FALSE;
1546 }
1547
1548
1549 /*
1550 * @implemented
1551 */
1552 BOOL
1553 WINAPI
1554 SetVDMCurrentDirectories(DWORD cchCurDirs, PCHAR lpszzCurDirs)
1555 {
1556 BASE_API_MESSAGE ApiMessage;
1557 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest = &ApiMessage.Data.VDMCurrentDirsRequest;
1558 PCSR_CAPTURE_BUFFER CaptureBuffer;
1559
1560 /* Allocate the capture buffer */
1561 CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
1562 if (CaptureBuffer == NULL)
1563 {
1564 BaseSetLastNTError(STATUS_NO_MEMORY);
1565 return FALSE;
1566 }
1567
1568 /* Setup the input parameters */
1569 VDMCurrentDirsRequest->cchCurDirs = cchCurDirs;
1570 CsrCaptureMessageBuffer(CaptureBuffer,
1571 lpszzCurDirs,
1572 cchCurDirs,
1573 (PVOID*)&VDMCurrentDirsRequest->lpszzCurDirs);
1574
1575 /* Call CSRSS */
1576 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
1577 CaptureBuffer,
1578 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetVDMCurDirs),
1579 sizeof(BASE_GETSET_VDM_CURDIRS));
1580
1581 /* Free the capture buffer */
1582 CsrFreeCaptureBuffer(CaptureBuffer);
1583
1584 /* Set the last error */
1585 BaseSetLastNTError(ApiMessage.Status);
1586
1587 return NT_SUCCESS(ApiMessage.Status) ? TRUE : FALSE;
1588 }
1589
1590 /*
1591 * @unimplemented
1592 */
1593 DWORD
1594 WINAPI
1595 VDMConsoleOperation (
1596 DWORD Unknown0,
1597 DWORD Unknown1
1598 )
1599 {
1600 STUB;
1601 return 0;
1602 }
1603
1604
1605 /*
1606 * @unimplemented
1607 */
1608 BOOL
1609 WINAPI
1610 VDMOperationStarted(IN ULONG Unknown0)
1611 {
1612 DPRINT1("VDMOperationStarted(%d)\n", Unknown0);
1613
1614 return
1615 BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler,
1616 NULL,
1617 0,
1618 Unknown0);
1619 }