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