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