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