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)
9 /* INCLUDES *******************************************************************/
16 /* TYPES **********************************************************************/
18 typedef struct _ENV_INFO
23 } ENV_INFO
, *PENV_INFO
;
25 /* GLOBALS ********************************************************************/
27 ENV_INFO BasepEnvNameType
[] =
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" },
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");
40 /* FUNCTIONS ******************************************************************/
44 BaseIsDosApplication(IN PUNICODE_STRING PathName
,
47 UNICODE_STRING String
;
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
;
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
;
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
;
69 BaseCheckVDM(IN ULONG BinaryType
,
70 IN PCWCH ApplicationName
,
72 IN PCWCH CurrentDirectory
,
73 IN PANSI_STRING AnsiEnvironment
,
74 IN PBASE_API_MESSAGE ApiMessage
,
76 IN DWORD CreationFlags
,
77 IN LPSTARTUPINFOW StartupInfo
,
78 IN HANDLE hUserToken OPTIONAL
)
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
;
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
;
96 /* Parameters validation */
97 if (ApplicationName
== NULL
|| CommandLine
== NULL
)
99 return STATUS_INVALID_PARAMETER
;
102 /* Trim leading whitespace from ApplicationName */
103 while (*ApplicationName
== L
' ' || *ApplicationName
== L
'\t')
106 /* Calculate the size of the short application name */
107 Length
= GetShortPathNameW(ApplicationName
, NULL
, 0);
110 Status
= STATUS_OBJECT_PATH_INVALID
;
114 /* Allocate memory for the short application name */
115 ShortAppName
= (PWCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
117 Length
* sizeof(WCHAR
));
120 Status
= STATUS_NO_MEMORY
;
124 /* Get the short application name */
125 if (GetShortPathNameW(ApplicationName
, ShortAppName
, Length
) == 0)
127 /* Try to determine which error occurred */
128 switch (GetLastError())
130 case ERROR_NOT_ENOUGH_MEMORY
:
132 Status
= STATUS_NO_MEMORY
;
136 case ERROR_INVALID_PARAMETER
:
138 Status
= STATUS_INVALID_PARAMETER
;
144 Status
= STATUS_OBJECT_PATH_INVALID
;
151 /* Trim leading whitespace from CommandLine */
152 while (*CommandLine
== L
' ' || *CommandLine
== L
'\t')
156 * CommandLine is usually formatted as: 'ApplicationName param0 ...'.
157 * So we want to strip the first token (ApplicationName) from it.
158 * Two cases are in fact possible:
159 * - either the first token is indeed ApplicationName, so we just skip it;
160 * - or the first token is not exactly ApplicationName, because it happened
161 * that somebody else already preprocessed CommandLine. Therefore we
162 * suppose that the first token corresponds to an application name and
163 * we skip it. Care should be taken when quotes are present in this token.
167 /* The first part of CommandLine should be the ApplicationName... */
168 Length
= wcslen(ApplicationName
);
169 if (Length
<= wcslen(CommandLine
) &&
170 _wcsnicmp(ApplicationName
, CommandLine
, Length
) == 0)
173 CommandLine
+= Length
;
176 * ... but it is not, however we still have a token. We suppose that
177 * it corresponds to some sort of application name, so we skip it too.
181 /* Get rid of the first token. We stop when we see whitespace. */
182 while (*CommandLine
&& !(*CommandLine
== L
' ' || *CommandLine
== L
'\t'))
184 if (*CommandLine
== L
'\"')
186 /* We enter a quoted part, skip it */
188 while (*CommandLine
&& *CommandLine
++ != L
'\"') ;
192 /* Go to the next character */
200 * Trim remaining whitespace from CommandLine that may be
201 * present between the application name and the parameters.
203 while (*CommandLine
== L
' ' || *CommandLine
== L
'\t')
206 /* Get the current directory */
207 if (CurrentDirectory
== NULL
)
209 /* Allocate memory for the current directory path */
210 Length
= GetCurrentDirectoryW(0, NULL
);
211 CurrentDir
= (PWCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
213 Length
* sizeof(WCHAR
));
214 if (CurrentDir
== NULL
)
216 Status
= STATUS_NO_MEMORY
;
220 /* Get the current directory */
221 GetCurrentDirectoryW(Length
, CurrentDir
);
222 CurrentDirectory
= CurrentDir
;
225 /* Calculate the size of the short current directory path */
226 Length
= GetShortPathNameW(CurrentDirectory
, NULL
, 0);
228 /* Allocate memory for the short current directory path */
229 ShortCurrentDir
= (PWCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
231 Length
* sizeof(WCHAR
));
232 if (!ShortCurrentDir
)
234 Status
= STATUS_NO_MEMORY
;
238 /* Get the short current directory path */
239 if (!GetShortPathNameW(CurrentDirectory
, ShortCurrentDir
, Length
))
241 /* Try to determine which error occurred */
242 switch (GetLastError())
244 case ERROR_NOT_ENOUGH_MEMORY
:
246 Status
= STATUS_NO_MEMORY
;
250 case ERROR_INVALID_PARAMETER
:
252 Status
= STATUS_INVALID_PARAMETER
;
258 Status
= STATUS_OBJECT_PATH_INVALID
;
264 /* Setup the input parameters */
265 CheckVdm
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
266 CheckVdm
->BinaryType
= BinaryType
;
267 CheckVdm
->CodePage
= CP_ACP
;
268 CheckVdm
->dwCreationFlags
= CreationFlags
;
269 CheckVdm
->CurDrive
= CurrentDirectory
[0] - L
'A';
270 CheckVdm
->CmdLen
= wcslen(CommandLine
) + 1;
271 CheckVdm
->AppLen
= wcslen(ShortAppName
) + 1;
272 CheckVdm
->PifLen
= 0; // TODO: PIF file support!
273 CheckVdm
->CurDirectoryLen
= wcslen(ShortCurrentDir
) + 1;
274 CheckVdm
->EnvLen
= AnsiEnvironment
->Length
;
275 CheckVdm
->DesktopLen
= (StartupInfo
->lpDesktop
!= NULL
) ? (wcslen(StartupInfo
->lpDesktop
) + 1) : 0;
276 CheckVdm
->TitleLen
= (StartupInfo
->lpTitle
!= NULL
) ? (wcslen(StartupInfo
->lpTitle
) + 1) : 0;
277 CheckVdm
->ReservedLen
= (StartupInfo
->lpReserved
!= NULL
) ? (wcslen(StartupInfo
->lpReserved
) + 1) : 0;
279 if (StartupInfo
->dwFlags
& STARTF_USESTDHANDLES
)
281 /* Set the standard handles */
282 CheckVdm
->StdIn
= StartupInfo
->hStdInput
;
283 CheckVdm
->StdOut
= StartupInfo
->hStdOutput
;
284 CheckVdm
->StdErr
= StartupInfo
->hStdError
;
287 /* Allocate memory for the ANSI strings */
288 // We need to add the newline characters '\r\n' to the command line
289 AnsiCmdLine
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, CheckVdm
->CmdLen
+ 2);
290 AnsiAppName
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, CheckVdm
->AppLen
);
291 AnsiCurDirectory
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, CheckVdm
->CurDirectoryLen
);
292 if (StartupInfo
->lpDesktop
) AnsiDesktop
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
294 CheckVdm
->DesktopLen
);
295 if (StartupInfo
->lpTitle
) AnsiTitle
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
298 if (StartupInfo
->lpReserved
) AnsiReserved
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
300 CheckVdm
->ReservedLen
);
305 || (StartupInfo
->lpDesktop
&& !AnsiDesktop
)
306 || (StartupInfo
->lpTitle
&& !AnsiTitle
)
307 || (StartupInfo
->lpReserved
&& !AnsiReserved
))
309 Status
= STATUS_NO_MEMORY
;
313 /* Convert the command line into an ANSI string */
314 WideCharToMultiByte(CP_ACP
,
322 /* Add the needed newline and NULL-terminate */
323 CheckVdm
->CmdLen
--; // Rewind back to the NULL character
324 AnsiCmdLine
[CheckVdm
->CmdLen
++] = '\r';
325 AnsiCmdLine
[CheckVdm
->CmdLen
++] = '\n';
326 AnsiCmdLine
[CheckVdm
->CmdLen
++] = 0;
328 /* Convert the short application name into an ANSI string */
329 WideCharToMultiByte(CP_ACP
,
338 /* Convert the short current directory path into an ANSI string */
339 WideCharToMultiByte(CP_ACP
,
342 CheckVdm
->CurDirectoryLen
,
344 CheckVdm
->CurDirectoryLen
,
348 if (StartupInfo
->lpDesktop
)
350 /* Convert the desktop name into an ANSI string */
351 WideCharToMultiByte(CP_ACP
,
353 StartupInfo
->lpDesktop
,
354 CheckVdm
->DesktopLen
,
356 CheckVdm
->DesktopLen
,
362 if (StartupInfo
->lpTitle
)
364 /* Convert the title into an ANSI string */
365 WideCharToMultiByte(CP_ACP
,
367 StartupInfo
->lpTitle
,
376 if (StartupInfo
->lpReserved
)
378 /* Convert the reserved value into an ANSI string */
379 WideCharToMultiByte(CP_ACP
,
381 StartupInfo
->lpReserved
,
382 CheckVdm
->ReservedLen
,
384 CheckVdm
->ReservedLen
,
390 /* Fill the ANSI startup info structure */
391 RtlCopyMemory(&AnsiStartupInfo
, StartupInfo
, sizeof(STARTUPINFO
));
392 AnsiStartupInfo
.lpReserved
= AnsiReserved
;
393 AnsiStartupInfo
.lpDesktop
= AnsiDesktop
;
394 AnsiStartupInfo
.lpTitle
= AnsiTitle
;
396 /* Allocate the capture buffer */
397 CaptureBuffer
= CsrAllocateCaptureBuffer(NumStrings
,
401 + CheckVdm
->CurDirectoryLen
402 + CheckVdm
->DesktopLen
404 + CheckVdm
->ReservedLen
406 + sizeof(STARTUPINFOA
));
407 if (CaptureBuffer
== NULL
)
409 Status
= STATUS_NO_MEMORY
;
413 /* Capture the command line */
414 CsrCaptureMessageBuffer(CaptureBuffer
,
417 (PVOID
*)&CheckVdm
->CmdLine
);
419 /* Capture the application name */
420 CsrCaptureMessageBuffer(CaptureBuffer
,
423 (PVOID
*)&CheckVdm
->AppName
);
425 CheckVdm
->PifFile
= NULL
; // TODO: PIF file support!
427 /* Capture the current directory */
428 CsrCaptureMessageBuffer(CaptureBuffer
,
430 CheckVdm
->CurDirectoryLen
,
431 (PVOID
*)&CheckVdm
->CurDirectory
);
433 /* Capture the environment */
434 CsrCaptureMessageBuffer(CaptureBuffer
,
435 AnsiEnvironment
->Buffer
,
437 (PVOID
*)&CheckVdm
->Env
);
439 /* Capture the startup info structure */
440 CsrCaptureMessageBuffer(CaptureBuffer
,
442 sizeof(STARTUPINFOA
),
443 (PVOID
*)&CheckVdm
->StartupInfo
);
445 if (StartupInfo
->lpDesktop
)
447 /* Capture the desktop name */
448 CsrCaptureMessageBuffer(CaptureBuffer
,
450 CheckVdm
->DesktopLen
,
451 (PVOID
*)&CheckVdm
->Desktop
);
453 else CheckVdm
->Desktop
= NULL
;
455 if (StartupInfo
->lpTitle
)
457 /* Capture the title */
458 CsrCaptureMessageBuffer(CaptureBuffer
,
461 (PVOID
*)&CheckVdm
->Title
);
463 else CheckVdm
->Title
= NULL
;
465 if (StartupInfo
->lpReserved
)
467 /* Capture the reserved parameter */
468 CsrCaptureMessageBuffer(CaptureBuffer
,
470 CheckVdm
->ReservedLen
,
471 (PVOID
*)&CheckVdm
->Reserved
);
473 else CheckVdm
->Reserved
= NULL
;
475 /* Send the message to CSRSS */
476 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)ApiMessage
,
478 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCheckVDM
),
479 sizeof(BASE_CHECK_VDM
));
481 /* Write back the task ID */
482 *iTask
= CheckVdm
->iTask
;
486 /* Free the ANSI strings */
487 if (AnsiCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine
);
488 if (AnsiAppName
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName
);
489 if (AnsiCurDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory
);
490 if (AnsiDesktop
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop
);
491 if (AnsiTitle
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle
);
492 if (AnsiReserved
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved
);
494 /* Free the capture buffer */
495 CsrFreeCaptureBuffer(CaptureBuffer
);
497 /* Free the current directory, if it was allocated here, and its short path */
498 if (ShortCurrentDir
) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir
);
499 if (CurrentDir
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir
);
501 /* Free the short app name */
502 if (ShortAppName
) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName
);
509 BaseUpdateVDMEntry(IN ULONG UpdateIndex
,
510 IN OUT PHANDLE WaitHandle
,
515 BASE_API_MESSAGE ApiMessage
;
516 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry
= &ApiMessage
.Data
.UpdateVDMEntryRequest
;
518 /* Check what update is being sent */
521 /* VDM is being undone */
524 /* Tell the server how far we had gotten along */
525 UpdateVdmEntry
->iTask
= HandleToUlong(*WaitHandle
);
526 UpdateVdmEntry
->VDMCreationState
= IndexInfo
;
530 /* VDM is ready with a new process handle */
531 case VdmEntryUpdateProcess
:
533 /* Send it the process handle */
534 UpdateVdmEntry
->VDMProcessHandle
= *WaitHandle
;
535 UpdateVdmEntry
->iTask
= IndexInfo
;
540 /* Also check what kind of binary this is for the console handle */
541 if (BinaryType
== BINARY_TYPE_WOW
)
543 /* Magic value for 16-bit apps */
544 UpdateVdmEntry
->ConsoleHandle
= (HANDLE
)-1;
546 else if (UpdateVdmEntry
->iTask
)
548 /* No handle for true VDM */
549 UpdateVdmEntry
->ConsoleHandle
= NULL
;
553 /* Otherwise, use the regular console handle */
554 UpdateVdmEntry
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
557 /* Finally write the index and binary type */
558 UpdateVdmEntry
->EntryIndex
= UpdateIndex
;
559 UpdateVdmEntry
->BinaryType
= BinaryType
;
561 /* Send the message to CSRSS */
562 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
564 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepUpdateVDMEntry
),
565 sizeof(BASE_UPDATE_VDM_ENTRY
));
566 if (!NT_SUCCESS(Status
))
569 BaseSetLastNTError(Status
);
573 /* If this was an update, CSRSS returns a new wait handle */
574 if (UpdateIndex
== VdmEntryUpdateProcess
)
576 /* Return it to the caller */
577 *WaitHandle
= UpdateVdmEntry
->WaitObjectForParent
;
586 BaseCheckForVDM(IN HANDLE ProcessHandle
,
587 OUT LPDWORD ExitCode
)
590 EVENT_BASIC_INFORMATION EventBasicInfo
;
591 BASE_API_MESSAGE ApiMessage
;
592 PBASE_GET_VDM_EXIT_CODE GetVdmExitCode
= &ApiMessage
.Data
.GetVDMExitCodeRequest
;
594 /* It's VDM if the process is actually a wait handle (an event) */
595 Status
= NtQueryEvent(ProcessHandle
,
596 EventBasicInformation
,
598 sizeof(EventBasicInfo
),
600 if (!NT_SUCCESS(Status
)) return FALSE
;
602 /* Setup the input parameters */
603 GetVdmExitCode
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
604 GetVdmExitCode
->hParent
= ProcessHandle
;
607 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
609 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetVDMExitCode
),
610 sizeof(BASE_GET_VDM_EXIT_CODE
));
611 if (!NT_SUCCESS(Status
)) return FALSE
;
613 /* Get the exit code from the reply */
614 *ExitCode
= GetVdmExitCode
->ExitCode
;
620 BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved
,
623 IN PUNICODE_STRING CmdLineString
,
626 WCHAR Buffer
[MAX_PATH
];
627 WCHAR CommandLine
[MAX_PATH
* 2];
630 /* Clear the buffer in case we fail */
631 CmdLineString
->Buffer
= 0;
633 /* Always return the same size: 16 Mb */
634 *VdmSize
= 0x1000000;
636 /* Get the system directory */
637 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
);
638 if (!(Length
) || (Length
>= MAX_PATH
))
640 /* Eliminate no path or path too big */
641 SetLastError(ERROR_INVALID_NAME
);
645 /* Check if this is VDM with a DOS Sequence ID */
649 * Build the VDM string for it:
650 * -i%lx : Gives the DOS Sequence ID;
651 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
653 _snwprintf(CommandLine
,
654 sizeof(CommandLine
) / sizeof(CommandLine
[0]),
655 L
"\"%s\\ntvdm.exe\" -i%lx %s%c",
658 (BinaryType
== BINARY_TYPE_DOS
) ? L
" " : L
"-w",
659 (BinaryType
== BINARY_TYPE_SEPARATE_WOW
) ? L
's' : L
' ');
664 * Build the string for it without the DOS Sequence ID:
665 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
667 _snwprintf(CommandLine
,
668 sizeof(CommandLine
) / sizeof(CommandLine
[0]),
669 L
"\"%s\\ntvdm.exe\" %s%c",
671 (BinaryType
== BINARY_TYPE_DOS
) ? L
" " : L
"-w",
672 (BinaryType
== BINARY_TYPE_SEPARATE_WOW
) ? L
's' : L
' ');
675 /* Create the actual string */
676 return RtlCreateUnicodeString(CmdLineString
, CommandLine
);
681 BaseGetEnvNameType_U(IN PWCHAR Name
,
687 /* Start by assuming unknown type */
690 /* Loop all the environment names */
691 for (i
= 0; i
< (sizeof(BasepEnvNameType
) / sizeof(ENV_INFO
)); i
++)
694 EnvInfo
= &BasepEnvNameType
[i
];
696 /* Check if it matches the name */
697 if ((EnvInfo
->NameLength
== NameLength
) &&
698 !(_wcsnicmp(EnvInfo
->Name
, Name
, NameLength
)))
700 /* It does, return the type */
701 NameType
= EnvInfo
->NameType
;
706 /* Return what we found, or unknown if nothing */
712 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv
,
713 IN PUNICODE_STRING UnicodeEnv
)
717 /* Clear the ASCII buffer since Rtl creates this for us */
718 if (AnsiEnv
->Buffer
) RtlFreeAnsiString(AnsiEnv
);
720 /* The Unicode buffer is build by hand, though */
721 if (UnicodeEnv
->Buffer
)
723 /* So clear it through the API */
724 NtFreeVirtualMemory(NtCurrentProcess(),
725 (PVOID
*)&UnicodeEnv
->Buffer
,
736 BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment
,
737 IN PANSI_STRING AnsiEnv
,
738 IN PUNICODE_STRING UnicodeEnv
)
741 ULONG RegionSize
, EnvironmentSize
= 0;
742 PWCHAR SourcePtr
, DestPtr
, Environment
, NewEnvironment
= NULL
;
743 WCHAR PathBuffer
[MAX_PATH
];
746 /* Make sure we have both strings */
747 if (!(AnsiEnv
) || !(UnicodeEnv
))
750 SetLastError(ERROR_INVALID_PARAMETER
);
754 /* Check if an environment was passed in */
757 /* Nope, create one */
758 Status
= RtlCreateEnvironment(TRUE
, &Environment
);
759 if (!NT_SUCCESS(Status
)) goto Quickie
;
763 /* Use the one we got */
764 Environment
= lpEnvironment
;
767 /* Do we have something now ? */
770 /* Still not, fail out */
771 SetLastError(ERROR_BAD_ENVIRONMENT
);
775 /* Count how much space the whole environment takes */
776 SourcePtr
= Environment
;
777 while ((*SourcePtr
++ != UNICODE_NULL
) && (*SourcePtr
!= UNICODE_NULL
)) EnvironmentSize
++;
778 EnvironmentSize
+= sizeof(UNICODE_NULL
);
780 /* Allocate a new copy */
781 RegionSize
= (EnvironmentSize
+ MAX_PATH
) * sizeof(WCHAR
);
782 if (!NT_SUCCESS(NtAllocateVirtualMemory(NtCurrentProcess(),
783 (PVOID
*)&NewEnvironment
,
789 /* We failed, bail out */
790 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
791 NewEnvironment
= NULL
;
795 /* Begin parsing the new environment */
796 SourcePtr
= Environment
;
797 DestPtr
= NewEnvironment
;
799 while (*SourcePtr
!= UNICODE_NULL
)
801 while (*SourcePtr
!= UNICODE_NULL
)
803 if (*SourcePtr
== L
'=')
805 /* Store the '=' sign */
806 *DestPtr
++ = *SourcePtr
++;
808 /* Check if this is likely a full path */
809 if (isalphaW(SourcePtr
[0])
810 && (SourcePtr
[1] == L
':')
811 && ((SourcePtr
[2] == '\\') || (SourcePtr
[2] == '/')))
813 PWCHAR Delimiter
= wcschr(SourcePtr
, L
';');
816 if (Delimiter
!= NULL
)
820 min(Delimiter
- SourcePtr
, MAX_PATH
));
822 /* Seek to the part after the delimiter */
823 SourcePtr
= Delimiter
+ 1;
827 wcsncpy(PathBuffer
, SourcePtr
, MAX_PATH
);
829 /* Seek to the end of the string */
830 SourcePtr
= wcschr(SourcePtr
, UNICODE_NULL
);
833 /* Convert the path into a short path */
834 NumChars
= GetShortPathNameW(PathBuffer
,
836 EnvironmentSize
- (DestPtr
- NewEnvironment
));
840 * If it failed, this block won't be executed, so it
841 * will continue from the character after the '=' sign.
845 /* Append the delimiter */
846 if (Delimiter
!= NULL
) *DestPtr
++ = L
';';
850 else if (islowerW(*SourcePtr
)) *DestPtr
++ = toupperW(*SourcePtr
++);
851 else *DestPtr
++ = *SourcePtr
++;
854 /* Copy the terminating NULL character */
855 *DestPtr
++ = *SourcePtr
++;
859 *DestPtr
++ = UNICODE_NULL
;
861 /* Initialize the unicode string to hold it */
862 EnvironmentSize
= (DestPtr
- NewEnvironment
) * sizeof(WCHAR
);
863 RtlInitEmptyUnicodeString(UnicodeEnv
, NewEnvironment
, (USHORT
)EnvironmentSize
);
864 UnicodeEnv
->Length
= (USHORT
)EnvironmentSize
;
866 /* Create the ASCII version of it */
867 Status
= RtlUnicodeStringToAnsiString(AnsiEnv
, UnicodeEnv
, TRUE
);
868 if (!NT_SUCCESS(Status
))
870 /* Set last error if conversion failure */
871 BaseSetLastNTError(Status
);
875 /* Everything went okay, so return success */
877 NewEnvironment
= NULL
;
881 /* Cleanup path starts here, start by destroying the envrionment copy */
882 if (!(lpEnvironment
) && (Environment
)) RtlDestroyEnvironment(Environment
);
884 /* See if we are here due to failure */
887 /* Initialize the paths to be empty */
888 RtlInitEmptyUnicodeString(UnicodeEnv
, NULL
, 0);
889 RtlInitEmptyAnsiString(AnsiEnv
, NULL
, 0);
891 /* Free the environment copy */
893 Status
= NtFreeVirtualMemory(NtCurrentProcess(),
894 (PVOID
*)&NewEnvironment
,
897 ASSERT(NT_SUCCESS(Status
));
900 /* Return the result */
905 /* Check whether a file is an OS/2 or a very old Windows executable
906 * by testing on import of KERNEL.
908 * FIXME: is reading the module imports the only way of discerning
909 * old Windows binaries from OS/2 ones ? At least it seems so...
912 InternalIsOS2OrOldWin(HANDLE hFile
, IMAGE_DOS_HEADER
*mz
, IMAGE_OS2_HEADER
*ne
)
915 LPWORD modtab
= NULL
;
916 LPSTR nametab
= NULL
;
921 CurPos
= SetFilePointer(hFile
, 0, NULL
, FILE_CURRENT
);
923 /* read modref table */
924 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_modtab
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
925 (!(modtab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_cmod
* sizeof(WORD
)))) ||
926 (!(ReadFile(hFile
, modtab
, ne
->ne_cmod
* sizeof(WORD
), &Read
, NULL
))) ||
927 (Read
!= (DWORD
)ne
->ne_cmod
* sizeof(WORD
)))
932 /* read imported names table */
933 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_imptab
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
934 (!(nametab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_enttab
- ne
->ne_imptab
))) ||
935 (!(ReadFile(hFile
, nametab
, ne
->ne_enttab
- ne
->ne_imptab
, &Read
, NULL
))) ||
936 (Read
!= (DWORD
)ne
->ne_enttab
- ne
->ne_imptab
))
941 for(i
= 0; i
< ne
->ne_cmod
; i
++)
944 module
= &nametab
[modtab
[i
]];
945 if(!strncmp(&module
[1], "KERNEL", module
[0]))
947 /* very old windows file */
954 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
957 HeapFree(GetProcessHeap(), 0, modtab
);
958 HeapFree(GetProcessHeap(), 0, nametab
);
959 SetFilePointer(hFile
, CurPos
, NULL
, FILE_BEGIN
);
964 InternalGetBinaryType(HANDLE hFile
)
970 unsigned char magic
[4];
971 unsigned char ignored
[12];
977 unsigned long cputype
;
978 unsigned long cpusubtype
;
979 unsigned long filetype
;
986 if((SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
987 (!ReadFile(hFile
, &Header
, sizeof(Header
), &Read
, NULL
) ||
988 (Read
!= sizeof(Header
))))
990 return BINARY_UNKNOWN
;
993 if(!memcmp(Header
.elf
.magic
, "\177ELF", sizeof(Header
.elf
.magic
)))
995 /* FIXME: we don't bother to check byte order, architecture, etc. */
996 switch(Header
.elf
.type
)
999 return BINARY_UNIX_EXE
;
1001 return BINARY_UNIX_LIB
;
1003 return BINARY_UNKNOWN
;
1006 /* Mach-o File with Endian set to Big Endian or Little Endian*/
1007 if(Header
.macho
.magic
== 0xFEEDFACE ||
1008 Header
.macho
.magic
== 0xCEFAEDFE)
1010 switch(Header
.macho
.filetype
)
1014 return BINARY_UNIX_LIB
;
1016 return BINARY_UNKNOWN
;
1019 /* Not ELF, try DOS */
1020 if(Header
.mz
.e_magic
== IMAGE_DOS_SIGNATURE
)
1022 /* We do have a DOS image so we will now try to seek into
1023 * the file by the amount indicated by the field
1024 * "Offset to extended header" and read in the
1025 * "magic" field information at that location.
1026 * This will tell us if there is more header information
1029 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
1030 (!ReadFile(hFile
, magic
, sizeof(magic
), &Read
, NULL
) ||
1031 (Read
!= sizeof(magic
))))
1036 /* Reading the magic field succeeded so
1037 * we will try to determine what type it is.
1039 if(!memcmp(magic
, "PE\0\0", sizeof(magic
)))
1041 IMAGE_FILE_HEADER FileHeader
;
1042 if(!ReadFile(hFile
, &FileHeader
, sizeof(IMAGE_FILE_HEADER
), &Read
, NULL
) ||
1043 (Read
!= sizeof(IMAGE_FILE_HEADER
)))
1048 /* FIXME - detect 32/64 bit */
1050 if(FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1051 return BINARY_PE_DLL32
;
1052 return BINARY_PE_EXE32
;
1055 if(!memcmp(magic
, "NE", 2))
1057 /* This is a Windows executable (NE) header. This can
1058 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
1059 * DOS program (running under a DOS extender). To decide
1060 * which, we'll have to read the NE header.
1062 IMAGE_OS2_HEADER ne
;
1063 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == 1) ||
1064 !ReadFile(hFile
, &ne
, sizeof(IMAGE_OS2_HEADER
), &Read
, NULL
) ||
1065 (Read
!= sizeof(IMAGE_OS2_HEADER
)))
1067 /* Couldn't read header, so abort. */
1071 switch(ne
.ne_exetyp
)
1074 return BINARY_WIN16
;
1078 return InternalIsOS2OrOldWin(hFile
, &Header
.mz
, &ne
);
1083 return BINARY_UNKNOWN
;
1092 LPCWSTR lpApplicationName
,
1093 LPDWORD lpBinaryType
1099 if(!lpApplicationName
|| !lpBinaryType
)
1101 SetLastError(ERROR_INVALID_PARAMETER
);
1105 hFile
= CreateFileW(lpApplicationName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
1106 OPEN_EXISTING
, 0, 0);
1107 if(hFile
== INVALID_HANDLE_VALUE
)
1112 BinType
= InternalGetBinaryType(hFile
);
1117 case BINARY_UNKNOWN
:
1122 * guess from filename
1124 if(!(dot
= wcsrchr(lpApplicationName
, L
'.')))
1128 if(!lstrcmpiW(dot
, L
".COM"))
1130 *lpBinaryType
= SCS_DOS_BINARY
;
1133 if(!lstrcmpiW(dot
, L
".PIF"))
1135 *lpBinaryType
= SCS_PIF_BINARY
;
1140 case BINARY_PE_EXE32
:
1141 case BINARY_PE_DLL32
:
1143 *lpBinaryType
= SCS_32BIT_BINARY
;
1146 case BINARY_PE_EXE64
:
1147 case BINARY_PE_DLL64
:
1149 *lpBinaryType
= SCS_64BIT_BINARY
;
1154 *lpBinaryType
= SCS_WOW_BINARY
;
1159 *lpBinaryType
= SCS_OS216_BINARY
;
1164 *lpBinaryType
= SCS_DOS_BINARY
;
1167 case BINARY_UNIX_EXE
:
1168 case BINARY_UNIX_LIB
:
1174 DPRINT1("Invalid binary type %lu returned!\n", BinType
);
1183 GetBinaryTypeA(IN LPCSTR lpApplicationName
,
1184 OUT LPDWORD lpBinaryType
)
1186 ANSI_STRING ApplicationNameString
;
1187 UNICODE_STRING ApplicationNameW
;
1188 BOOL StringAllocated
= FALSE
, Result
;
1191 RtlInitAnsiString(&ApplicationNameString
, lpApplicationName
);
1193 if (ApplicationNameString
.Length
* sizeof(WCHAR
) >= NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
1195 StringAllocated
= TRUE
;
1196 Status
= RtlAnsiStringToUnicodeString(&ApplicationNameW
, &ApplicationNameString
, TRUE
);
1200 Status
= RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString
), &ApplicationNameString
, FALSE
);
1203 if (!NT_SUCCESS(Status
))
1205 BaseSetLastNTError(Status
);
1209 if (StringAllocated
)
1211 Result
= GetBinaryTypeW(ApplicationNameW
.Buffer
, lpBinaryType
);
1212 RtlFreeUnicodeString(&ApplicationNameW
);
1216 Result
= GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString
.Buffer
, lpBinaryType
);
1227 CmdBatNotification (
1240 ExitVDM(BOOL IsWow
, ULONG iWowTask
)
1242 BASE_API_MESSAGE ApiMessage
;
1243 PBASE_EXIT_VDM ExitVdm
= &ApiMessage
.Data
.ExitVDMRequest
;
1245 /* Setup the input parameters */
1246 ExitVdm
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1247 ExitVdm
->iWowTask
= IsWow
? iWowTask
: 0; /* Always zero for DOS tasks */
1248 ExitVdm
->WaitObjectForVDM
= NULL
;
1251 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1253 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitVDM
),
1254 sizeof(BASE_EXIT_VDM
));
1256 /* Close the returned wait object handle, if any */
1257 if (NT_SUCCESS(ApiMessage
.Status
) && (ExitVdm
->WaitObjectForVDM
!= NULL
))
1259 CloseHandle(ExitVdm
->WaitObjectForVDM
);
1268 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData
)
1271 BOOL Result
= FALSE
;
1272 BASE_API_MESSAGE ApiMessage
;
1273 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand
= &ApiMessage
.Data
.GetNextVDMCommandRequest
;
1274 PBASE_IS_FIRST_VDM IsFirstVdm
= &ApiMessage
.Data
.IsFirstVDMRequest
;
1275 PBASE_SET_REENTER_COUNT SetReenterCount
= &ApiMessage
.Data
.SetReenterCountRequest
;
1276 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
1277 ULONG NumStrings
= 0;
1279 if (CommandData
!= NULL
)
1281 if (CommandData
->VDMState
& (VDM_NOT_LOADED
| VDM_NOT_READY
| VDM_READY
))
1283 /* Clear the structure */
1284 ZeroMemory(GetNextVdmCommand
, sizeof(*GetNextVdmCommand
));
1286 /* Setup the input parameters */
1287 GetNextVdmCommand
->iTask
= CommandData
->TaskId
;
1288 GetNextVdmCommand
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1289 GetNextVdmCommand
->CmdLen
= CommandData
->CmdLen
;
1290 GetNextVdmCommand
->AppLen
= CommandData
->AppLen
;
1291 GetNextVdmCommand
->PifLen
= CommandData
->PifLen
;
1292 GetNextVdmCommand
->CurDirectoryLen
= CommandData
->CurDirectoryLen
;
1293 GetNextVdmCommand
->EnvLen
= CommandData
->EnvLen
;
1294 GetNextVdmCommand
->DesktopLen
= CommandData
->DesktopLen
;
1295 GetNextVdmCommand
->TitleLen
= CommandData
->TitleLen
;
1296 GetNextVdmCommand
->ReservedLen
= CommandData
->ReservedLen
;
1297 GetNextVdmCommand
->VDMState
= CommandData
->VDMState
;
1299 /* Count the number of strings */
1300 if (CommandData
->CmdLen
) NumStrings
++;
1301 if (CommandData
->AppLen
) NumStrings
++;
1302 if (CommandData
->PifLen
) NumStrings
++;
1303 if (CommandData
->CurDirectoryLen
) NumStrings
++;
1304 if (CommandData
->EnvLen
) NumStrings
++;
1305 if (CommandData
->DesktopLen
) NumStrings
++;
1306 if (CommandData
->TitleLen
) NumStrings
++;
1307 if (CommandData
->ReservedLen
) NumStrings
++;
1309 /* Allocate the capture buffer */
1310 CaptureBuffer
= CsrAllocateCaptureBuffer(NumStrings
+ 1,
1311 GetNextVdmCommand
->CmdLen
1312 + GetNextVdmCommand
->AppLen
1313 + GetNextVdmCommand
->PifLen
1314 + GetNextVdmCommand
->CurDirectoryLen
1315 + GetNextVdmCommand
->EnvLen
1316 + GetNextVdmCommand
->DesktopLen
1317 + GetNextVdmCommand
->TitleLen
1318 + GetNextVdmCommand
->ReservedLen
1319 + sizeof(STARTUPINFOA
));
1320 if (CaptureBuffer
== NULL
)
1322 BaseSetLastNTError(STATUS_NO_MEMORY
);
1326 /* Allocate memory for the startup info */
1327 CsrAllocateMessagePointer(CaptureBuffer
,
1328 sizeof(STARTUPINFOA
),
1329 (PVOID
*)&GetNextVdmCommand
->StartupInfo
);
1331 if (CommandData
->CmdLen
)
1333 /* Allocate memory for the command line */
1334 CsrAllocateMessagePointer(CaptureBuffer
,
1335 CommandData
->CmdLen
,
1336 (PVOID
*)&GetNextVdmCommand
->CmdLine
);
1339 if (CommandData
->AppLen
)
1341 /* Allocate memory for the application name */
1342 CsrAllocateMessagePointer(CaptureBuffer
,
1343 CommandData
->AppLen
,
1344 (PVOID
*)&GetNextVdmCommand
->AppName
);
1347 if (CommandData
->PifLen
)
1349 /* Allocate memory for the PIF file name */
1350 CsrAllocateMessagePointer(CaptureBuffer
,
1351 CommandData
->PifLen
,
1352 (PVOID
*)&GetNextVdmCommand
->PifFile
);
1355 if (CommandData
->CurDirectoryLen
)
1357 /* Allocate memory for the current directory */
1358 CsrAllocateMessagePointer(CaptureBuffer
,
1359 CommandData
->CurDirectoryLen
,
1360 (PVOID
*)&GetNextVdmCommand
->CurDirectory
);
1363 if (CommandData
->EnvLen
)
1365 /* Allocate memory for the environment */
1366 CsrAllocateMessagePointer(CaptureBuffer
,
1367 CommandData
->EnvLen
,
1368 (PVOID
*)&GetNextVdmCommand
->Env
);
1371 if (CommandData
->DesktopLen
)
1373 /* Allocate memory for the desktop name */
1374 CsrAllocateMessagePointer(CaptureBuffer
,
1375 CommandData
->DesktopLen
,
1376 (PVOID
*)&GetNextVdmCommand
->Desktop
);
1379 if (CommandData
->TitleLen
)
1381 /* Allocate memory for the title */
1382 CsrAllocateMessagePointer(CaptureBuffer
,
1383 CommandData
->TitleLen
,
1384 (PVOID
*)&GetNextVdmCommand
->Title
);
1387 if (CommandData
->ReservedLen
)
1389 /* Allocate memory for the reserved parameter */
1390 CsrAllocateMessagePointer(CaptureBuffer
,
1391 CommandData
->ReservedLen
,
1392 (PVOID
*)&GetNextVdmCommand
->Reserved
);
1398 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1400 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetNextVDMCommand
),
1401 sizeof(BASE_GET_NEXT_VDM_COMMAND
));
1403 if (!NT_SUCCESS(Status
))
1405 /* Store the correct lengths */
1406 CommandData
->CmdLen
= GetNextVdmCommand
->CmdLen
;
1407 CommandData
->AppLen
= GetNextVdmCommand
->AppLen
;
1408 CommandData
->PifLen
= GetNextVdmCommand
->PifLen
;
1409 CommandData
->CurDirectoryLen
= GetNextVdmCommand
->CurDirectoryLen
;
1410 CommandData
->EnvLen
= GetNextVdmCommand
->EnvLen
;
1411 CommandData
->DesktopLen
= GetNextVdmCommand
->DesktopLen
;
1412 CommandData
->TitleLen
= GetNextVdmCommand
->TitleLen
;
1413 CommandData
->ReservedLen
= GetNextVdmCommand
->ReservedLen
;
1415 BaseSetLastNTError(Status
);
1419 /* Did we receive an event handle? */
1420 if (GetNextVdmCommand
->WaitObjectForVDM
!= NULL
)
1422 /* Wait for the event to become signaled and try again */
1423 Status
= NtWaitForSingleObject(GetNextVdmCommand
->WaitObjectForVDM
,
1426 if (!NT_SUCCESS(Status
))
1428 BaseSetLastNTError(Status
);
1432 /* Set the retry flag and clear the exit code */
1433 GetNextVdmCommand
->VDMState
|= VDM_FLAG_RETRY
;
1434 GetNextVdmCommand
->ExitCode
= 0;
1437 while (GetNextVdmCommand
->WaitObjectForVDM
!= NULL
);
1439 /* Write back the standard handles */
1440 CommandData
->StdIn
= GetNextVdmCommand
->StdIn
;
1441 CommandData
->StdOut
= GetNextVdmCommand
->StdOut
;
1442 CommandData
->StdErr
= GetNextVdmCommand
->StdErr
;
1444 /* Write back the startup info */
1445 RtlMoveMemory(&CommandData
->StartupInfo
,
1446 GetNextVdmCommand
->StartupInfo
,
1447 sizeof(STARTUPINFOA
));
1449 if (CommandData
->CmdLen
)
1451 /* Write back the command line */
1452 RtlMoveMemory(CommandData
->CmdLine
,
1453 GetNextVdmCommand
->CmdLine
,
1454 GetNextVdmCommand
->CmdLen
);
1456 /* Set the actual length */
1457 CommandData
->CmdLen
= GetNextVdmCommand
->CmdLen
;
1460 if (CommandData
->AppLen
)
1462 /* Write back the application name */
1463 RtlMoveMemory(CommandData
->AppName
,
1464 GetNextVdmCommand
->AppName
,
1465 GetNextVdmCommand
->AppLen
);
1467 /* Set the actual length */
1468 CommandData
->AppLen
= GetNextVdmCommand
->AppLen
;
1471 if (CommandData
->PifLen
)
1473 /* Write back the PIF file name */
1474 RtlMoveMemory(CommandData
->PifFile
,
1475 GetNextVdmCommand
->PifFile
,
1476 GetNextVdmCommand
->PifLen
);
1478 /* Set the actual length */
1479 CommandData
->PifLen
= GetNextVdmCommand
->PifLen
;
1482 if (CommandData
->CurDirectoryLen
)
1484 /* Write back the current directory */
1485 RtlMoveMemory(CommandData
->CurDirectory
,
1486 GetNextVdmCommand
->CurDirectory
,
1487 GetNextVdmCommand
->CurDirectoryLen
);
1489 /* Set the actual length */
1490 CommandData
->CurDirectoryLen
= GetNextVdmCommand
->CurDirectoryLen
;
1493 if (CommandData
->EnvLen
)
1495 /* Write back the environment */
1496 RtlMoveMemory(CommandData
->Env
,
1497 GetNextVdmCommand
->Env
,
1498 GetNextVdmCommand
->EnvLen
);
1500 /* Set the actual length */
1501 CommandData
->EnvLen
= GetNextVdmCommand
->EnvLen
;
1504 if (CommandData
->DesktopLen
)
1506 /* Write back the desktop name */
1507 RtlMoveMemory(CommandData
->Desktop
,
1508 GetNextVdmCommand
->Desktop
,
1509 GetNextVdmCommand
->DesktopLen
);
1511 /* Set the actual length */
1512 CommandData
->DesktopLen
= GetNextVdmCommand
->DesktopLen
;
1515 if (CommandData
->TitleLen
)
1517 /* Write back the title */
1518 RtlMoveMemory(CommandData
->Title
,
1519 GetNextVdmCommand
->Title
,
1520 GetNextVdmCommand
->TitleLen
);
1522 /* Set the actual length */
1523 CommandData
->TitleLen
= GetNextVdmCommand
->TitleLen
;
1526 if (CommandData
->ReservedLen
)
1528 /* Write back the reserved parameter */
1529 RtlMoveMemory(CommandData
->Reserved
,
1530 GetNextVdmCommand
->Reserved
,
1531 GetNextVdmCommand
->ReservedLen
);
1533 /* Set the actual length */
1534 CommandData
->ReservedLen
= GetNextVdmCommand
->ReservedLen
;
1537 /* Write the remaining output parameters */
1538 CommandData
->TaskId
= GetNextVdmCommand
->iTask
;
1539 CommandData
->CreationFlags
= GetNextVdmCommand
->dwCreationFlags
;
1540 CommandData
->CodePage
= GetNextVdmCommand
->CodePage
;
1541 CommandData
->ExitCode
= GetNextVdmCommand
->ExitCode
;
1542 CommandData
->CurrentDrive
= GetNextVdmCommand
->CurrentDrive
;
1543 CommandData
->VDMState
= GetNextVdmCommand
->VDMState
;
1544 CommandData
->ComingFromBat
= GetNextVdmCommand
->fComingFromBat
;
1546 /* It was successful */
1549 else if ((CommandData
->VDMState
== VDM_INC_REENTER_COUNT
)
1550 || (CommandData
->VDMState
== VDM_DEC_REENTER_COUNT
))
1552 /* Setup the input parameters */
1553 SetReenterCount
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1554 SetReenterCount
->fIncDec
= CommandData
->VDMState
;
1557 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1559 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetReenterCount
),
1560 sizeof(BASE_SET_REENTER_COUNT
));
1561 BaseSetLastNTError(Status
);
1562 Result
= NT_SUCCESS(Status
);
1566 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1573 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1575 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepIsFirstVDM
),
1576 sizeof(BASE_IS_FIRST_VDM
));
1577 if (!NT_SUCCESS(Status
))
1579 BaseSetLastNTError(Status
);
1583 /* Return TRUE if this is the first VDM */
1584 Result
= IsFirstVdm
->FirstVDM
;
1588 if (CaptureBuffer
!= NULL
) CsrFreeCaptureBuffer(CaptureBuffer
);
1598 GetVDMCurrentDirectories(DWORD cchCurDirs
, PCHAR lpszzCurDirs
)
1600 BASE_API_MESSAGE ApiMessage
;
1601 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &ApiMessage
.Data
.VDMCurrentDirsRequest
;
1602 PCSR_CAPTURE_BUFFER CaptureBuffer
;
1604 /* Allocate the capture buffer */
1605 CaptureBuffer
= CsrAllocateCaptureBuffer(1, cchCurDirs
);
1606 if (CaptureBuffer
== NULL
)
1608 BaseSetLastNTError(STATUS_NO_MEMORY
);
1612 /* Setup the input parameters */
1613 VDMCurrentDirsRequest
->cchCurDirs
= cchCurDirs
;
1614 CsrAllocateMessagePointer(CaptureBuffer
,
1616 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
);
1619 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1621 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetVDMCurDirs
),
1622 sizeof(BASE_GETSET_VDM_CURDIRS
));
1624 /* Set the last error */
1625 BaseSetLastNTError(ApiMessage
.Status
);
1627 if (NT_SUCCESS(ApiMessage
.Status
))
1629 /* Copy the result */
1630 RtlMoveMemory(lpszzCurDirs
, VDMCurrentDirsRequest
->lpszzCurDirs
, cchCurDirs
);
1633 /* Free the capture buffer */
1634 CsrFreeCaptureBuffer(CaptureBuffer
);
1636 /* Return the size if it was successful, or if the buffer was too small */
1637 return (NT_SUCCESS(ApiMessage
.Status
) || (ApiMessage
.Status
== STATUS_BUFFER_TOO_SMALL
))
1638 ? VDMCurrentDirsRequest
->cchCurDirs
: 0;
1643 * @implemented (undocumented)
1647 RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
1648 IN HANDLE hStartHardwareEvent
,
1649 IN HANDLE hEndHardwareEvent
,
1650 IN HANDLE hErrorHardwareEvent
,
1651 IN DWORD dwUnusedVar
,
1652 OUT LPDWORD lpVideoStateLength
,
1653 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
1654 IN PVOID lpUnusedBuffer
,
1655 IN DWORD dwUnusedBufferLength
,
1656 IN COORD dwVDMBufferSize
,
1657 OUT PVOID
* lpVDMBuffer
)
1660 CONSOLE_API_MESSAGE ApiMessage
;
1661 PCONSOLE_REGISTERVDM RegisterVDMRequest
= &ApiMessage
.Data
.RegisterVDMRequest
;
1662 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
1664 /* Set up the data to send to the Console Server */
1665 RegisterVDMRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1666 RegisterVDMRequest
->RegisterFlags
= dwRegisterFlags
;
1668 if (dwRegisterFlags
!= 0)
1670 RegisterVDMRequest
->StartHardwareEvent
= hStartHardwareEvent
;
1671 RegisterVDMRequest
->EndHardwareEvent
= hEndHardwareEvent
;
1672 RegisterVDMRequest
->ErrorHardwareEvent
= hErrorHardwareEvent
;
1674 RegisterVDMRequest
->VDMBufferSize
= dwVDMBufferSize
;
1677 RegisterVDMRequest
->UnusedBufferLength
= dwUnusedBufferLength
;
1679 /* Allocate a Capture Buffer */
1680 CaptureBuffer
= CsrAllocateCaptureBuffer(1, dwUnusedBufferLength
);
1681 if (CaptureBuffer
== NULL
)
1683 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
1684 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1688 /* Capture the buffer to write */
1689 CsrCaptureMessageBuffer(CaptureBuffer
,
1690 (PVOID
)lpUnusedBuffer
,
1691 dwUnusedBufferLength
,
1692 (PVOID
*)&RegisterVDMRequest
->UnusedBuffer
);
1697 // CaptureBuffer = NULL;
1700 /* Call the server */
1701 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1703 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepRegisterVDM
),
1704 sizeof(*RegisterVDMRequest
));
1706 /* Check for success */
1707 Success
= NT_SUCCESS(ApiMessage
.Status
);
1709 /* Release the capture buffer if needed */
1710 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
1712 /* Retrieve the results */
1715 if (dwRegisterFlags
!= 0)
1719 *lpVideoStateLength
= RegisterVDMRequest
->VideoStateLength
;
1720 *lpVideoState
= RegisterVDMRequest
->VideoState
;
1721 *lpVDMBuffer
= RegisterVDMRequest
->VDMBuffer
;
1723 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1725 SetLastError(ERROR_INVALID_ACCESS
);
1733 BaseSetLastNTError(ApiMessage
.Status
);
1736 /* Return success status */
1746 RegisterWowBaseHandlers (
1774 SetVDMCurrentDirectories(DWORD cchCurDirs
, PCHAR lpszzCurDirs
)
1776 BASE_API_MESSAGE ApiMessage
;
1777 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &ApiMessage
.Data
.VDMCurrentDirsRequest
;
1778 PCSR_CAPTURE_BUFFER CaptureBuffer
;
1780 /* Allocate the capture buffer */
1781 CaptureBuffer
= CsrAllocateCaptureBuffer(1, cchCurDirs
);
1782 if (CaptureBuffer
== NULL
)
1784 BaseSetLastNTError(STATUS_NO_MEMORY
);
1788 /* Setup the input parameters */
1789 VDMCurrentDirsRequest
->cchCurDirs
= cchCurDirs
;
1790 CsrCaptureMessageBuffer(CaptureBuffer
,
1793 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
);
1796 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1798 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetVDMCurDirs
),
1799 sizeof(BASE_GETSET_VDM_CURDIRS
));
1801 /* Free the capture buffer */
1802 CsrFreeCaptureBuffer(CaptureBuffer
);
1804 /* Set the last error */
1805 BaseSetLastNTError(ApiMessage
.Status
);
1807 return NT_SUCCESS(ApiMessage
.Status
) ? TRUE
: FALSE
;
1815 VDMConsoleOperation (
1830 VDMOperationStarted(IN ULONG Unknown0
)
1832 DPRINT1("VDMOperationStarted(%d)\n", Unknown0
);
1834 return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler
,