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