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 #define BINARY_UNKNOWN (0)
19 #define BINARY_PE_EXE32 (1)
20 #define BINARY_PE_DLL32 (2)
21 #define BINARY_PE_EXE64 (3)
22 #define BINARY_PE_DLL64 (4)
23 #define BINARY_WIN16 (5)
24 #define BINARY_OS216 (6)
25 #define BINARY_DOS (7)
26 #define BINARY_UNIX_EXE (8)
27 #define BINARY_UNIX_LIB (9)
30 typedef enum _ENV_NAME_TYPE
37 typedef struct _ENV_INFO
39 ENV_NAME_TYPE NameType
;
42 } ENV_INFO
, *PENV_INFO
;
44 /* GLOBALS ********************************************************************/
46 #define ENV_NAME_ENTRY(type, name) \
47 {(type), _ARRAYSIZE(name) - 1, (name)}
49 static ENV_INFO BasepEnvNameType
[] =
51 ENV_NAME_ENTRY(EnvNameMultiplePath
, L
"PATH"),
52 ENV_NAME_ENTRY(EnvNameSinglePath
, L
"WINDIR"),
53 ENV_NAME_ENTRY(EnvNameSinglePath
, L
"SYSTEMROOT"),
54 ENV_NAME_ENTRY(EnvNameMultiplePath
, L
"TEMP"),
55 ENV_NAME_ENTRY(EnvNameMultiplePath
, L
"TMP"),
58 static UNICODE_STRING BaseDotComSuffixName
= RTL_CONSTANT_STRING(L
".com");
59 static UNICODE_STRING BaseDotPifSuffixName
= RTL_CONSTANT_STRING(L
".pif");
60 static UNICODE_STRING BaseDotExeSuffixName
= RTL_CONSTANT_STRING(L
".exe");
62 /* FUNCTIONS ******************************************************************/
66 BaseIsDosApplication(IN PUNICODE_STRING PathName
,
69 UNICODE_STRING String
;
72 String
.Length
= BaseDotComSuffixName
.Length
;
73 String
.Buffer
= &PathName
->Buffer
[(PathName
->Length
- String
.Length
) / sizeof(WCHAR
)];
74 if (RtlEqualUnicodeString(&String
, &BaseDotComSuffixName
, TRUE
)) return BINARY_TYPE_COM
;
77 String
.Length
= BaseDotPifSuffixName
.Length
;
78 String
.Buffer
= &PathName
->Buffer
[(PathName
->Length
- String
.Length
) / sizeof(WCHAR
)];
79 if (RtlEqualUnicodeString(&String
, &BaseDotPifSuffixName
, TRUE
)) return BINARY_TYPE_PIF
;
82 String
.Length
= BaseDotExeSuffixName
.Length
;
83 String
.Buffer
= &PathName
->Buffer
[(PathName
->Length
- String
.Length
) / sizeof(WCHAR
)];
84 if (RtlEqualUnicodeString(&String
, &BaseDotExeSuffixName
, TRUE
)) return BINARY_TYPE_EXE
;
91 BaseCheckVDM(IN ULONG BinaryType
,
92 IN PCWCH ApplicationName
,
94 IN PCWCH CurrentDirectory
,
95 IN PANSI_STRING AnsiEnvironment
,
96 IN PBASE_API_MESSAGE ApiMessage
,
98 IN DWORD CreationFlags
,
99 IN LPSTARTUPINFOW StartupInfo
,
100 IN HANDLE hUserToken OPTIONAL
)
103 PBASE_CHECK_VDM CheckVdm
= &ApiMessage
->Data
.CheckVDMRequest
;
104 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
105 PWCHAR CurrentDir
= NULL
;
106 PWCHAR ShortAppName
= NULL
;
107 PWCHAR ShortCurrentDir
= NULL
;
109 PCHAR AnsiCmdLine
= NULL
;
110 PCHAR AnsiAppName
= NULL
;
111 PCHAR AnsiCurDirectory
= NULL
;
112 PCHAR AnsiDesktop
= NULL
;
113 PCHAR AnsiTitle
= NULL
;
114 PCHAR AnsiReserved
= NULL
;
115 STARTUPINFOA AnsiStartupInfo
;
116 ULONG NumStrings
= 5;
118 /* Parameters validation */
119 if (ApplicationName
== NULL
|| CommandLine
== NULL
)
121 return STATUS_INVALID_PARAMETER
;
124 /* Trim leading whitespace from ApplicationName */
125 while (*ApplicationName
== L
' ' || *ApplicationName
== L
'\t')
128 /* Calculate the size of the short application name */
129 Length
= GetShortPathNameW(ApplicationName
, NULL
, 0);
132 Status
= STATUS_OBJECT_PATH_INVALID
;
136 /* Allocate memory for the short application name */
137 ShortAppName
= (PWCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
139 Length
* sizeof(WCHAR
));
142 Status
= STATUS_NO_MEMORY
;
146 /* Get the short application name */
147 if (GetShortPathNameW(ApplicationName
, ShortAppName
, Length
) == 0)
149 /* Try to determine which error occurred */
150 switch (GetLastError())
152 case ERROR_NOT_ENOUGH_MEMORY
:
154 Status
= STATUS_NO_MEMORY
;
158 case ERROR_INVALID_PARAMETER
:
160 Status
= STATUS_INVALID_PARAMETER
;
166 Status
= STATUS_OBJECT_PATH_INVALID
;
173 /* Trim leading whitespace from CommandLine */
174 while (*CommandLine
== L
' ' || *CommandLine
== L
'\t')
178 * CommandLine is usually formatted as: 'ApplicationName param0 ...'.
179 * So we want to strip the first token (ApplicationName) from it.
180 * Two cases are in fact possible:
181 * - either the first token is indeed ApplicationName, so we just skip it;
182 * - or the first token is not exactly ApplicationName, because it happened
183 * that somebody else already preprocessed CommandLine. Therefore we
184 * suppose that the first token corresponds to an application name and
185 * we skip it. Care should be taken when quotes are present in this token.
189 /* The first part of CommandLine should be the ApplicationName... */
190 Length
= wcslen(ApplicationName
);
191 if (Length
<= wcslen(CommandLine
) &&
192 _wcsnicmp(ApplicationName
, CommandLine
, Length
) == 0)
195 CommandLine
+= Length
;
198 * ... but it is not, however we still have a token. We suppose that
199 * it corresponds to some sort of application name, so we skip it too.
203 /* Get rid of the first token. We stop when we see whitespace. */
204 while (*CommandLine
&& !(*CommandLine
== L
' ' || *CommandLine
== L
'\t'))
206 if (*CommandLine
== L
'\"')
208 /* We enter a quoted part, skip it */
210 while (*CommandLine
&& *CommandLine
++ != L
'\"') ;
214 /* Go to the next character */
222 * Trim remaining whitespace from CommandLine that may be
223 * present between the application name and the parameters.
225 while (*CommandLine
== L
' ' || *CommandLine
== L
'\t')
228 /* Get the current directory */
229 if (CurrentDirectory
== NULL
)
231 /* Allocate memory for the current directory path */
232 Length
= GetCurrentDirectoryW(0, NULL
);
233 CurrentDir
= (PWCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
235 Length
* sizeof(WCHAR
));
236 if (CurrentDir
== NULL
)
238 Status
= STATUS_NO_MEMORY
;
242 /* Get the current directory */
243 GetCurrentDirectoryW(Length
, CurrentDir
);
244 CurrentDirectory
= CurrentDir
;
247 /* Calculate the size of the short current directory path */
248 Length
= GetShortPathNameW(CurrentDirectory
, NULL
, 0);
250 /* Allocate memory for the short current directory path */
251 ShortCurrentDir
= (PWCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
253 Length
* sizeof(WCHAR
));
254 if (!ShortCurrentDir
)
256 Status
= STATUS_NO_MEMORY
;
260 /* Get the short current directory path */
261 if (!GetShortPathNameW(CurrentDirectory
, ShortCurrentDir
, Length
))
263 /* Try to determine which error occurred */
264 switch (GetLastError())
266 case ERROR_NOT_ENOUGH_MEMORY
:
268 Status
= STATUS_NO_MEMORY
;
272 case ERROR_INVALID_PARAMETER
:
274 Status
= STATUS_INVALID_PARAMETER
;
280 Status
= STATUS_OBJECT_PATH_INVALID
;
286 /* Setup the input parameters */
287 CheckVdm
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
288 CheckVdm
->BinaryType
= BinaryType
;
289 CheckVdm
->CodePage
= CP_ACP
;
290 CheckVdm
->dwCreationFlags
= CreationFlags
;
291 CheckVdm
->CurDrive
= CurrentDirectory
[0] - L
'A';
292 CheckVdm
->CmdLen
= wcslen(CommandLine
) + 1;
293 CheckVdm
->AppLen
= wcslen(ShortAppName
) + 1;
294 CheckVdm
->PifLen
= 0; // TODO: PIF file support!
295 CheckVdm
->CurDirectoryLen
= wcslen(ShortCurrentDir
) + 1;
296 CheckVdm
->EnvLen
= AnsiEnvironment
->Length
;
297 CheckVdm
->DesktopLen
= (StartupInfo
->lpDesktop
!= NULL
) ? (wcslen(StartupInfo
->lpDesktop
) + 1) : 0;
298 CheckVdm
->TitleLen
= (StartupInfo
->lpTitle
!= NULL
) ? (wcslen(StartupInfo
->lpTitle
) + 1) : 0;
299 CheckVdm
->ReservedLen
= (StartupInfo
->lpReserved
!= NULL
) ? (wcslen(StartupInfo
->lpReserved
) + 1) : 0;
301 if (StartupInfo
->dwFlags
& STARTF_USESTDHANDLES
)
303 /* Set the standard handles */
304 CheckVdm
->StdIn
= StartupInfo
->hStdInput
;
305 CheckVdm
->StdOut
= StartupInfo
->hStdOutput
;
306 CheckVdm
->StdErr
= StartupInfo
->hStdError
;
309 /* Allocate memory for the ANSI strings */
310 // We need to add the newline characters '\r\n' to the command line
311 AnsiCmdLine
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, CheckVdm
->CmdLen
+ 2);
312 AnsiAppName
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, CheckVdm
->AppLen
);
313 AnsiCurDirectory
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, CheckVdm
->CurDirectoryLen
);
314 if (StartupInfo
->lpDesktop
)
315 AnsiDesktop
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
317 CheckVdm
->DesktopLen
);
318 if (StartupInfo
->lpTitle
)
319 AnsiTitle
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
322 if (StartupInfo
->lpReserved
)
323 AnsiReserved
= (PCHAR
)RtlAllocateHeap(RtlGetProcessHeap(),
325 CheckVdm
->ReservedLen
);
330 || (StartupInfo
->lpDesktop
&& !AnsiDesktop
)
331 || (StartupInfo
->lpTitle
&& !AnsiTitle
)
332 || (StartupInfo
->lpReserved
&& !AnsiReserved
))
334 Status
= STATUS_NO_MEMORY
;
338 /* Convert the command line into an ANSI string */
339 WideCharToMultiByte(CP_ACP
,
347 /* Add the needed newline and NULL-terminate */
348 CheckVdm
->CmdLen
--; // Rewind back to the NULL character
349 AnsiCmdLine
[CheckVdm
->CmdLen
++] = '\r';
350 AnsiCmdLine
[CheckVdm
->CmdLen
++] = '\n';
351 AnsiCmdLine
[CheckVdm
->CmdLen
++] = 0;
353 /* Convert the short application name into an ANSI string */
354 WideCharToMultiByte(CP_ACP
,
363 /* Convert the short current directory path into an ANSI string */
364 WideCharToMultiByte(CP_ACP
,
367 CheckVdm
->CurDirectoryLen
,
369 CheckVdm
->CurDirectoryLen
,
373 if (StartupInfo
->lpDesktop
)
375 /* Convert the desktop name into an ANSI string */
376 WideCharToMultiByte(CP_ACP
,
378 StartupInfo
->lpDesktop
,
379 CheckVdm
->DesktopLen
,
381 CheckVdm
->DesktopLen
,
387 if (StartupInfo
->lpTitle
)
389 /* Convert the title into an ANSI string */
390 WideCharToMultiByte(CP_ACP
,
392 StartupInfo
->lpTitle
,
401 if (StartupInfo
->lpReserved
)
403 /* Convert the reserved value into an ANSI string */
404 WideCharToMultiByte(CP_ACP
,
406 StartupInfo
->lpReserved
,
407 CheckVdm
->ReservedLen
,
409 CheckVdm
->ReservedLen
,
415 /* Fill the ANSI startup info structure */
416 RtlCopyMemory(&AnsiStartupInfo
, StartupInfo
, sizeof(AnsiStartupInfo
));
417 AnsiStartupInfo
.lpReserved
= AnsiReserved
;
418 AnsiStartupInfo
.lpDesktop
= AnsiDesktop
;
419 AnsiStartupInfo
.lpTitle
= AnsiTitle
;
421 /* Allocate the capture buffer */
422 CaptureBuffer
= CsrAllocateCaptureBuffer(NumStrings
,
426 + CheckVdm
->CurDirectoryLen
427 + CheckVdm
->DesktopLen
429 + CheckVdm
->ReservedLen
431 + sizeof(*CheckVdm
->StartupInfo
));
432 if (CaptureBuffer
== NULL
)
434 Status
= STATUS_NO_MEMORY
;
438 /* Capture the command line */
439 CsrCaptureMessageBuffer(CaptureBuffer
,
442 (PVOID
*)&CheckVdm
->CmdLine
);
444 /* Capture the application name */
445 CsrCaptureMessageBuffer(CaptureBuffer
,
448 (PVOID
*)&CheckVdm
->AppName
);
450 CheckVdm
->PifFile
= NULL
; // TODO: PIF file support!
452 /* Capture the current directory */
453 CsrCaptureMessageBuffer(CaptureBuffer
,
455 CheckVdm
->CurDirectoryLen
,
456 (PVOID
*)&CheckVdm
->CurDirectory
);
458 /* Capture the environment */
459 CsrCaptureMessageBuffer(CaptureBuffer
,
460 AnsiEnvironment
->Buffer
,
462 (PVOID
*)&CheckVdm
->Env
);
464 /* Capture the startup info structure */
465 CsrCaptureMessageBuffer(CaptureBuffer
,
467 sizeof(*CheckVdm
->StartupInfo
),
468 (PVOID
*)&CheckVdm
->StartupInfo
);
470 if (StartupInfo
->lpDesktop
)
472 /* Capture the desktop name */
473 CsrCaptureMessageBuffer(CaptureBuffer
,
475 CheckVdm
->DesktopLen
,
476 (PVOID
*)&CheckVdm
->Desktop
);
478 else CheckVdm
->Desktop
= NULL
;
480 if (StartupInfo
->lpTitle
)
482 /* Capture the title */
483 CsrCaptureMessageBuffer(CaptureBuffer
,
486 (PVOID
*)&CheckVdm
->Title
);
488 else CheckVdm
->Title
= NULL
;
490 if (StartupInfo
->lpReserved
)
492 /* Capture the reserved parameter */
493 CsrCaptureMessageBuffer(CaptureBuffer
,
495 CheckVdm
->ReservedLen
,
496 (PVOID
*)&CheckVdm
->Reserved
);
498 else CheckVdm
->Reserved
= NULL
;
500 /* Send the message to CSRSS */
501 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)ApiMessage
,
503 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepCheckVDM
),
506 /* Write back the task ID */
507 *iTask
= CheckVdm
->iTask
;
511 /* Free the ANSI strings */
512 if (AnsiCmdLine
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCmdLine
);
513 if (AnsiAppName
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiAppName
);
514 if (AnsiCurDirectory
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiCurDirectory
);
515 if (AnsiDesktop
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiDesktop
);
516 if (AnsiTitle
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiTitle
);
517 if (AnsiReserved
) RtlFreeHeap(RtlGetProcessHeap(), 0, AnsiReserved
);
519 /* Free the capture buffer */
520 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
522 /* Free the current directory, if it was allocated here, and its short path */
523 if (ShortCurrentDir
) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortCurrentDir
);
524 if (CurrentDir
) RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDir
);
526 /* Free the short app name */
527 if (ShortAppName
) RtlFreeHeap(RtlGetProcessHeap(), 0, ShortAppName
);
534 BaseUpdateVDMEntry(IN ULONG UpdateIndex
,
535 IN OUT PHANDLE WaitHandle
,
539 BASE_API_MESSAGE ApiMessage
;
540 PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry
= &ApiMessage
.Data
.UpdateVDMEntryRequest
;
542 /* Check what update is being sent */
545 /* VDM is being undone */
548 /* Tell the server how far we had gotten along */
549 UpdateVdmEntry
->iTask
= HandleToUlong(*WaitHandle
);
550 UpdateVdmEntry
->VDMCreationState
= IndexInfo
;
554 /* VDM is ready with a new process handle */
555 case VdmEntryUpdateProcess
:
557 /* Send it the process handle */
558 UpdateVdmEntry
->VDMProcessHandle
= *WaitHandle
;
559 UpdateVdmEntry
->iTask
= IndexInfo
;
564 /* Also check what kind of binary this is for the console handle */
565 if (BinaryType
== BINARY_TYPE_WOW
)
567 /* Magic value for 16-bit apps */
568 UpdateVdmEntry
->ConsoleHandle
= (HANDLE
)-1;
570 else if (UpdateVdmEntry
->iTask
)
572 /* No handle for true VDM */
573 UpdateVdmEntry
->ConsoleHandle
= NULL
;
577 /* Otherwise, use the regular console handle */
578 UpdateVdmEntry
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
581 /* Finally write the index and binary type */
582 UpdateVdmEntry
->EntryIndex
= UpdateIndex
;
583 UpdateVdmEntry
->BinaryType
= BinaryType
;
585 /* Send the message to CSRSS */
586 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
588 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepUpdateVDMEntry
),
589 sizeof(*UpdateVdmEntry
));
590 if (!NT_SUCCESS(ApiMessage
.Status
))
593 BaseSetLastNTError(ApiMessage
.Status
);
597 /* If this was an update, CSRSS returns a new wait handle */
598 if (UpdateIndex
== VdmEntryUpdateProcess
)
600 /* Return it to the caller */
601 *WaitHandle
= UpdateVdmEntry
->WaitObjectForParent
;
610 BaseCheckForVDM(IN HANDLE ProcessHandle
,
611 OUT LPDWORD ExitCode
)
614 EVENT_BASIC_INFORMATION EventBasicInfo
;
615 BASE_API_MESSAGE ApiMessage
;
616 PBASE_GET_VDM_EXIT_CODE GetVdmExitCode
= &ApiMessage
.Data
.GetVDMExitCodeRequest
;
618 /* It's VDM if the process is actually a wait handle (an event) */
619 Status
= NtQueryEvent(ProcessHandle
,
620 EventBasicInformation
,
622 sizeof(EventBasicInfo
),
624 if (!NT_SUCCESS(Status
)) return FALSE
;
626 /* Setup the input parameters */
627 GetVdmExitCode
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
628 GetVdmExitCode
->hParent
= ProcessHandle
;
631 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
633 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetVDMExitCode
),
634 sizeof(*GetVdmExitCode
));
635 if (!NT_SUCCESS(Status
)) return FALSE
;
637 /* Get the exit code from the reply */
638 *ExitCode
= GetVdmExitCode
->ExitCode
;
644 BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved
,
647 IN PUNICODE_STRING CmdLineString
,
650 WCHAR Buffer
[MAX_PATH
];
651 WCHAR CommandLine
[MAX_PATH
* 2];
654 /* Clear the buffer in case we fail */
655 CmdLineString
->Buffer
= 0;
657 /* Always return the same size: 16 Mb */
658 *VdmSize
= 0x1000000;
660 /* Get the system directory */
661 Length
= GetSystemDirectoryW(Buffer
, MAX_PATH
);
662 if (!(Length
) || (Length
>= MAX_PATH
))
664 /* Eliminate no path or path too big */
665 SetLastError(ERROR_INVALID_NAME
);
669 /* Check if this is VDM with a DOS Sequence ID */
673 * Build the VDM string for it:
674 * -i%lx : Gives the DOS Sequence ID;
675 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
677 _snwprintf(CommandLine
,
678 ARRAYSIZE(CommandLine
),
679 L
"\"%s\\ntvdm.exe\" -i%lx %s%c",
682 (BinaryType
== BINARY_TYPE_DOS
) ? L
" " : L
"-w",
683 (BinaryType
== BINARY_TYPE_SEPARATE_WOW
) ? L
's' : L
' ');
688 * Build the string for it without the DOS Sequence ID:
689 * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
691 _snwprintf(CommandLine
,
692 ARRAYSIZE(CommandLine
),
693 L
"\"%s\\ntvdm.exe\" %s%c",
695 (BinaryType
== BINARY_TYPE_DOS
) ? L
" " : L
"-w",
696 (BinaryType
== BINARY_TYPE_SEPARATE_WOW
) ? L
's' : L
' ');
699 /* Create the actual string */
700 return RtlCreateUnicodeString(CmdLineString
, CommandLine
);
705 BaseGetEnvNameType_U(IN PWCHAR Name
,
709 ENV_NAME_TYPE NameType
;
712 /* Start by assuming the environment variable doesn't describe paths */
713 NameType
= EnvNameNotAPath
;
715 /* Loop all the environment names */
716 for (i
= 0; i
< ARRAYSIZE(BasepEnvNameType
); i
++)
719 EnvInfo
= &BasepEnvNameType
[i
];
721 /* Check if it matches the name */
722 if ((EnvInfo
->NameLength
== NameLength
) &&
723 (_wcsnicmp(EnvInfo
->Name
, Name
, NameLength
) == 0))
725 /* It does, return the type */
726 NameType
= EnvInfo
->NameType
;
736 BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment
,
737 OUT PANSI_STRING AnsiEnv
,
738 OUT PUNICODE_STRING UnicodeEnv
)
740 #define IS_ALPHA(x) \
741 ( ((x) >= L'A' && (x) <= L'Z') || ((x) >= L'a' && (x) <= L'z') )
743 // From lib/rtl/path.c :
744 // Can be put in some .h ??
745 #define IS_PATH_SEPARATOR(x) ((x) == L'\\' || (x) == L'/')
747 BOOL Success
= FALSE
;
749 ULONG RegionSize
, EnvironmentSize
= 0;
750 PWCHAR Environment
, NewEnvironment
= NULL
;
751 ENV_NAME_TYPE NameType
;
752 ULONG NameLength
, NumChars
, Remaining
;
753 PWCHAR SourcePtr
, DestPtr
, StartPtr
;
755 /* Make sure we have both strings */
756 if (!AnsiEnv
|| !UnicodeEnv
)
759 SetLastError(ERROR_INVALID_PARAMETER
);
763 /* Check if an environment was passed in */
766 /* Nope, create one */
767 Status
= RtlCreateEnvironment(TRUE
, &Environment
);
768 if (!NT_SUCCESS(Status
)) goto Cleanup
;
772 /* Use the one we got */
773 Environment
= lpEnvironment
;
776 /* Do we have something now ? */
779 /* Still not, bail out */
780 SetLastError(ERROR_BAD_ENVIRONMENT
);
785 * Count how much space the whole environment takes. The environment block is
786 * doubly NULL-terminated (NULL from last string and final NULL terminator).
788 SourcePtr
= Environment
;
789 while (!(*SourcePtr
++ == UNICODE_NULL
&& *SourcePtr
== UNICODE_NULL
))
791 EnvironmentSize
+= 2; // Add the two terminating NULLs
794 * Allocate a new copy large enough to hold all the environment with paths
795 * in their short form. Since the short form of a path can be a bit longer
796 * than its long form, for example in the case where characters that are
797 * invalid in the 8.3 representation are present in the long path name:
798 * 'C:\\a+b' --> 'C:\\A_B~1', or:
799 * 'C:\\a b' --> 'C:\\AB2761~1' (with checksum inserted),
800 * we suppose that the possible total number of extra characters needed to
801 * convert the long paths into their short form is at most equal to MAX_PATH.
803 RegionSize
= (EnvironmentSize
+ MAX_PATH
) * sizeof(WCHAR
);
804 Status
= NtAllocateVirtualMemory(NtCurrentProcess(),
805 (PVOID
*)&NewEnvironment
,
810 if (!NT_SUCCESS(Status
))
812 /* We failed, bail out */
813 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
814 NewEnvironment
= NULL
;
818 /* Parse the environment block */
819 Remaining
= MAX_PATH
- 2; // '-2': remove the last two NULLs. FIXME: is it really needed??
820 SourcePtr
= Environment
;
821 DestPtr
= NewEnvironment
;
823 /* Loop through all the environment strings */
824 while (*SourcePtr
!= UNICODE_NULL
)
827 * 1. Check the type of the environment variable and copy its name.
830 /* Regular environment variable */
831 if (*SourcePtr
!= L
'=')
833 StartPtr
= SourcePtr
;
835 /* Copy the environment variable name, including the '=' */
836 while (*SourcePtr
!= UNICODE_NULL
)
838 *DestPtr
++ = *SourcePtr
;
839 if (*SourcePtr
++ == L
'=') break;
842 /* Guess the type of the environment variable */
843 NameType
= BaseGetEnvNameType_U(StartPtr
, SourcePtr
- StartPtr
- 1);
845 /* 'Current directory' environment variable (i.e. of '=X:=' form) */
846 else // if (*SourcePtr == L'=')
848 /* First assume we have a possibly malformed environment variable */
849 NameType
= EnvNameNotAPath
;
851 /* Check for a valid 'Current directory' environment variable */
852 if (IS_ALPHA(SourcePtr
[1]) && SourcePtr
[2] == L
':' && SourcePtr
[3] == L
'=')
855 * Small optimization: convert the path to short form only if
856 * the current directory is not the root directory (i.e. not
857 * of the '=X:=Y:\' form), otherwise just do a simple copy.
859 if ( wcslen(SourcePtr
) >= ARRAYSIZE("=X:=Y:\\")-1 &&
860 !( IS_ALPHA(SourcePtr
[4]) && SourcePtr
[5] == L
':' &&
861 IS_PATH_SEPARATOR(SourcePtr
[6]) && SourcePtr
[7] == UNICODE_NULL
) )
863 NameType
= EnvNameSinglePath
;
865 /* Copy the '=X:=' prefix */
866 *DestPtr
++ = SourcePtr
[0];
867 *DestPtr
++ = SourcePtr
[1];
868 *DestPtr
++ = SourcePtr
[2];
869 *DestPtr
++ = SourcePtr
[3];
876 * Invalid stuff starting with '=', i.e.:
877 * =? (with '?' not being a letter)
878 * =X??? (with '?' not being ":=" and not followed by something longer than 3 characters)
879 * =X:=??? (with '?' not being "X:\\")
881 * 'NameType' is already set to 'EnvNameNotAPath'.
888 * 2. Copy the environment value and perform conversions accordingly.
891 if (NameType
== EnvNameNotAPath
)
893 /* Copy everything, including the NULL terminator */
896 *DestPtr
++ = *SourcePtr
;
897 } while (*SourcePtr
++ != UNICODE_NULL
);
899 else if (NameType
== EnvNameSinglePath
)
901 /* Convert the path to its short form */
902 NameLength
= wcslen(SourcePtr
);
903 NumChars
= GetShortPathNameW(SourcePtr
, DestPtr
, NameLength
+ 1 + Remaining
);
904 if (NumChars
== 0 || NumChars
> NameLength
+ Remaining
)
906 /* If the conversion failed, just copy the original value */
907 RtlCopyMemory(DestPtr
, SourcePtr
, NameLength
* sizeof(WCHAR
));
908 NumChars
= NameLength
;
911 if (NumChars
> NameLength
)
912 Remaining
-= (NumChars
- NameLength
);
914 SourcePtr
+= NameLength
;
916 /* Copy the NULL terminator */
917 *DestPtr
++ = *SourcePtr
++;
919 else // if (NameType == EnvNameMultiplePath)
923 /* Loop through the list of paths (delimited by ';') and convert each path to its short form */
926 /* Copy any trailing ';' before going to the next path */
927 while (*SourcePtr
== L
';')
929 *DestPtr
++ = *SourcePtr
++;
932 StartPtr
= SourcePtr
;
934 /* Find the next path list delimiter or the NULL terminator */
935 while (*SourcePtr
!= UNICODE_NULL
&& *SourcePtr
!= L
';')
939 Delimiter
= *SourcePtr
;
941 NameLength
= SourcePtr
- StartPtr
;
945 * Temporarily replace the possible path list delimiter by NULL.
946 * 'lpEnvironment' must point to a read+write memory buffer!
948 *SourcePtr
= UNICODE_NULL
;
950 NumChars
= GetShortPathNameW(StartPtr
, DestPtr
, NameLength
+ 1 + Remaining
);
951 if ( NumChars
== 0 ||
952 (Delimiter
== L
';' ? NumChars
> NameLength
+ Remaining
953 : NumChars
> NameLength
/* + Remaining ?? */) )
955 /* If the conversion failed, just copy the original value */
956 RtlCopyMemory(DestPtr
, StartPtr
, NameLength
* sizeof(WCHAR
));
957 NumChars
= NameLength
;
960 if (NumChars
> NameLength
)
961 Remaining
-= (NumChars
- NameLength
);
963 /* If removed, restore the path list delimiter in the source environment value and copy it */
964 if (Delimiter
!= UNICODE_NULL
)
966 *SourcePtr
= Delimiter
;
967 *DestPtr
++ = *SourcePtr
++;
970 } while (*SourcePtr
!= UNICODE_NULL
);
972 /* Copy the NULL terminator */
973 *DestPtr
++ = *SourcePtr
++;
977 /* NULL-terminate the environment block */
978 *DestPtr
++ = UNICODE_NULL
;
980 /* Initialize the Unicode string to hold it */
981 RtlInitEmptyUnicodeString(UnicodeEnv
, NewEnvironment
,
982 (DestPtr
- NewEnvironment
) * sizeof(WCHAR
));
983 UnicodeEnv
->Length
= UnicodeEnv
->MaximumLength
;
985 /* Create its ANSI version */
986 Status
= RtlUnicodeStringToAnsiString(AnsiEnv
, UnicodeEnv
, TRUE
);
987 if (!NT_SUCCESS(Status
))
989 /* Set last error if conversion failure */
990 BaseSetLastNTError(Status
);
994 /* Everything went okay, so return success */
996 NewEnvironment
= NULL
;
1000 /* Cleanup path starts here, start by destroying the environment copy */
1001 if (!lpEnvironment
&& Environment
) RtlDestroyEnvironment(Environment
);
1003 /* See if we are here due to failure */
1006 /* Initialize the paths to be empty */
1007 RtlInitEmptyUnicodeString(UnicodeEnv
, NULL
, 0);
1008 RtlInitEmptyAnsiString(AnsiEnv
, NULL
, 0);
1010 /* Free the environment copy */
1012 Status
= NtFreeVirtualMemory(NtCurrentProcess(),
1013 (PVOID
*)&NewEnvironment
,
1016 ASSERT(NT_SUCCESS(Status
));
1019 /* Return the result */
1025 BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv
,
1026 IN PUNICODE_STRING UnicodeEnv
)
1030 /* Clear the ANSI buffer since Rtl creates this for us */
1031 if (AnsiEnv
->Buffer
) RtlFreeAnsiString(AnsiEnv
);
1033 /* The Unicode buffer is build by hand, though */
1034 if (UnicodeEnv
->Buffer
)
1036 /* So clear it through the API */
1037 NtFreeVirtualMemory(NtCurrentProcess(),
1038 (PVOID
*)&UnicodeEnv
->Buffer
,
1048 /* Check whether a file is an OS/2 or a very old Windows executable
1049 * by testing on import of KERNEL.
1051 * FIXME: is reading the module imports the only way of discerning
1052 * old Windows binaries from OS/2 ones ? At least it seems so...
1055 InternalIsOS2OrOldWin(HANDLE hFile
, IMAGE_DOS_HEADER
*mz
, IMAGE_OS2_HEADER
*ne
)
1058 LPWORD modtab
= NULL
;
1059 LPSTR nametab
= NULL
;
1064 CurPos
= SetFilePointer(hFile
, 0, NULL
, FILE_CURRENT
);
1066 /* read modref table */
1067 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_modtab
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
1068 (!(modtab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_cmod
* sizeof(WORD
)))) ||
1069 (!(ReadFile(hFile
, modtab
, ne
->ne_cmod
* sizeof(WORD
), &Read
, NULL
))) ||
1070 (Read
!= (DWORD
)ne
->ne_cmod
* sizeof(WORD
)))
1075 /* read imported names table */
1076 if((SetFilePointer(hFile
, mz
->e_lfanew
+ ne
->ne_imptab
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
1077 (!(nametab
= HeapAlloc(GetProcessHeap(), 0, ne
->ne_enttab
- ne
->ne_imptab
))) ||
1078 (!(ReadFile(hFile
, nametab
, ne
->ne_enttab
- ne
->ne_imptab
, &Read
, NULL
))) ||
1079 (Read
!= (DWORD
)ne
->ne_enttab
- ne
->ne_imptab
))
1084 for(i
= 0; i
< ne
->ne_cmod
; i
++)
1087 module
= &nametab
[modtab
[i
]];
1088 if(!strncmp(&module
[1], "KERNEL", module
[0]))
1090 /* very old windows file */
1097 DPRINT1("InternalIsOS2OrOldWin(): Binary file seems to be broken\n");
1100 HeapFree(GetProcessHeap(), 0, modtab
);
1101 HeapFree(GetProcessHeap(), 0, nametab
);
1102 SetFilePointer(hFile
, CurPos
, NULL
, FILE_BEGIN
);
1107 InternalGetBinaryType(HANDLE hFile
)
1113 unsigned char magic
[4];
1114 unsigned char ignored
[12];
1115 unsigned short type
;
1119 unsigned long magic
;
1120 unsigned long cputype
;
1121 unsigned long cpusubtype
;
1122 unsigned long filetype
;
1124 IMAGE_DOS_HEADER mz
;
1129 if((SetFilePointer(hFile
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
1130 (!ReadFile(hFile
, &Header
, sizeof(Header
), &Read
, NULL
) ||
1131 (Read
!= sizeof(Header
))))
1133 return BINARY_UNKNOWN
;
1136 if(!memcmp(Header
.elf
.magic
, "\177ELF", sizeof(Header
.elf
.magic
)))
1138 /* FIXME: we don't bother to check byte order, architecture, etc. */
1139 switch(Header
.elf
.type
)
1142 return BINARY_UNIX_EXE
;
1144 return BINARY_UNIX_LIB
;
1146 return BINARY_UNKNOWN
;
1149 /* Mach-o File with Endian set to Big Endian or Little Endian*/
1150 if(Header
.macho
.magic
== 0xFEEDFACE ||
1151 Header
.macho
.magic
== 0xCEFAEDFE)
1153 switch(Header
.macho
.filetype
)
1157 return BINARY_UNIX_LIB
;
1159 return BINARY_UNKNOWN
;
1162 /* Not ELF, try DOS */
1163 if(Header
.mz
.e_magic
== IMAGE_DOS_SIGNATURE
)
1165 /* We do have a DOS image so we will now try to seek into
1166 * the file by the amount indicated by the field
1167 * "Offset to extended header" and read in the
1168 * "magic" field information at that location.
1169 * This will tell us if there is more header information
1172 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
) ||
1173 (!ReadFile(hFile
, magic
, sizeof(magic
), &Read
, NULL
) ||
1174 (Read
!= sizeof(magic
))))
1179 /* Reading the magic field succeeded so
1180 * we will try to determine what type it is.
1182 if(!memcmp(magic
, "PE\0\0", sizeof(magic
)))
1184 IMAGE_FILE_HEADER FileHeader
;
1185 if(!ReadFile(hFile
, &FileHeader
, sizeof(IMAGE_FILE_HEADER
), &Read
, NULL
) ||
1186 (Read
!= sizeof(IMAGE_FILE_HEADER
)))
1191 /* FIXME - detect 32/64 bit */
1193 if(FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
1194 return BINARY_PE_DLL32
;
1195 return BINARY_PE_EXE32
;
1198 if(!memcmp(magic
, "NE", 2))
1200 /* This is a Windows executable (NE) header. This can
1201 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
1202 * DOS program (running under a DOS extender). To decide
1203 * which, we'll have to read the NE header.
1205 IMAGE_OS2_HEADER ne
;
1206 if((SetFilePointer(hFile
, Header
.mz
.e_lfanew
, NULL
, FILE_BEGIN
) == 1) ||
1207 !ReadFile(hFile
, &ne
, sizeof(IMAGE_OS2_HEADER
), &Read
, NULL
) ||
1208 (Read
!= sizeof(IMAGE_OS2_HEADER
)))
1210 /* Couldn't read header, so abort. */
1214 switch(ne
.ne_exetyp
)
1217 return BINARY_WIN16
;
1221 return InternalIsOS2OrOldWin(hFile
, &Header
.mz
, &ne
);
1226 return BINARY_UNKNOWN
;
1235 LPCWSTR lpApplicationName
,
1236 LPDWORD lpBinaryType
1242 if(!lpApplicationName
|| !lpBinaryType
)
1244 SetLastError(ERROR_INVALID_PARAMETER
);
1248 hFile
= CreateFileW(lpApplicationName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
1249 OPEN_EXISTING
, 0, 0);
1250 if(hFile
== INVALID_HANDLE_VALUE
)
1255 BinType
= InternalGetBinaryType(hFile
);
1260 case BINARY_UNKNOWN
:
1265 * guess from filename
1267 if(!(dot
= wcsrchr(lpApplicationName
, L
'.')))
1271 if(!lstrcmpiW(dot
, L
".COM"))
1273 *lpBinaryType
= SCS_DOS_BINARY
;
1276 if(!lstrcmpiW(dot
, L
".PIF"))
1278 *lpBinaryType
= SCS_PIF_BINARY
;
1283 case BINARY_PE_EXE32
:
1284 case BINARY_PE_DLL32
:
1286 *lpBinaryType
= SCS_32BIT_BINARY
;
1289 case BINARY_PE_EXE64
:
1290 case BINARY_PE_DLL64
:
1292 *lpBinaryType
= SCS_64BIT_BINARY
;
1297 *lpBinaryType
= SCS_WOW_BINARY
;
1302 *lpBinaryType
= SCS_OS216_BINARY
;
1307 *lpBinaryType
= SCS_DOS_BINARY
;
1310 case BINARY_UNIX_EXE
:
1311 case BINARY_UNIX_LIB
:
1317 DPRINT1("Invalid binary type %lu returned!\n", BinType
);
1326 GetBinaryTypeA(IN LPCSTR lpApplicationName
,
1327 OUT LPDWORD lpBinaryType
)
1329 ANSI_STRING ApplicationNameString
;
1330 UNICODE_STRING ApplicationNameW
;
1331 BOOL StringAllocated
= FALSE
, Result
;
1334 RtlInitAnsiString(&ApplicationNameString
, lpApplicationName
);
1336 if (ApplicationNameString
.Length
* sizeof(WCHAR
) >= NtCurrentTeb()->StaticUnicodeString
.MaximumLength
)
1338 StringAllocated
= TRUE
;
1339 Status
= RtlAnsiStringToUnicodeString(&ApplicationNameW
, &ApplicationNameString
, TRUE
);
1343 Status
= RtlAnsiStringToUnicodeString(&(NtCurrentTeb()->StaticUnicodeString
), &ApplicationNameString
, FALSE
);
1346 if (!NT_SUCCESS(Status
))
1348 BaseSetLastNTError(Status
);
1352 if (StringAllocated
)
1354 Result
= GetBinaryTypeW(ApplicationNameW
.Buffer
, lpBinaryType
);
1355 RtlFreeUnicodeString(&ApplicationNameW
);
1359 Result
= GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString
.Buffer
, lpBinaryType
);
1370 CmdBatNotification (
1383 ExitVDM(BOOL IsWow
, ULONG iWowTask
)
1385 BASE_API_MESSAGE ApiMessage
;
1386 PBASE_EXIT_VDM ExitVdm
= &ApiMessage
.Data
.ExitVDMRequest
;
1388 /* Setup the input parameters */
1389 ExitVdm
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1390 ExitVdm
->iWowTask
= IsWow
? iWowTask
: 0; /* Always zero for DOS tasks */
1391 ExitVdm
->WaitObjectForVDM
= NULL
;
1394 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1396 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepExitVDM
),
1399 /* Close the returned wait object handle, if any */
1400 if (NT_SUCCESS(ApiMessage
.Status
) && (ExitVdm
->WaitObjectForVDM
!= NULL
))
1402 CloseHandle(ExitVdm
->WaitObjectForVDM
);
1411 GetNextVDMCommand(PVDM_COMMAND_INFO CommandData
)
1413 BOOL Success
= FALSE
;
1415 BASE_API_MESSAGE ApiMessage
;
1416 PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand
= &ApiMessage
.Data
.GetNextVDMCommandRequest
;
1417 PBASE_IS_FIRST_VDM IsFirstVdm
= &ApiMessage
.Data
.IsFirstVDMRequest
;
1418 PBASE_SET_REENTER_COUNT SetReenterCount
= &ApiMessage
.Data
.SetReenterCountRequest
;
1419 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
1420 ULONG NumStrings
= 0;
1423 * Special case to test whether the VDM is the first one.
1425 if (CommandData
== NULL
)
1428 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1430 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepIsFirstVDM
),
1431 sizeof(*IsFirstVdm
));
1432 if (!NT_SUCCESS(ApiMessage
.Status
))
1434 BaseSetLastNTError(ApiMessage
.Status
);
1438 /* Return TRUE if this is the first VDM */
1439 return IsFirstVdm
->FirstVDM
;
1442 /* CommandData != NULL */
1445 * Special case to increment or decrement the reentrancy count.
1447 if ((CommandData
->VDMState
== VDM_INC_REENTER_COUNT
) ||
1448 (CommandData
->VDMState
== VDM_DEC_REENTER_COUNT
))
1450 /* Setup the input parameters */
1451 SetReenterCount
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1452 SetReenterCount
->fIncDec
= CommandData
->VDMState
;
1455 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1457 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetReenterCount
),
1458 sizeof(*SetReenterCount
));
1459 if (!NT_SUCCESS(ApiMessage
.Status
))
1461 BaseSetLastNTError(ApiMessage
.Status
);
1470 * Special case to retrieve or set WOW information.
1472 // TODO: if CommandData->VDMState & (VDM_LIST_WOW_PROCESSES | VDM_LIST_WOW_TASKS | VDM_ADD_WOW_TASK)
1473 // then call BasepGetNextVDMCommand in a simpler way!
1479 /* Clear the structure */
1480 RtlZeroMemory(GetNextVdmCommand
, sizeof(*GetNextVdmCommand
));
1482 /* Setup the input parameters */
1483 GetNextVdmCommand
->iTask
= CommandData
->TaskId
;
1484 GetNextVdmCommand
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1485 GetNextVdmCommand
->CmdLen
= CommandData
->CmdLen
;
1486 GetNextVdmCommand
->AppLen
= CommandData
->AppLen
;
1487 GetNextVdmCommand
->PifLen
= CommandData
->PifLen
;
1488 GetNextVdmCommand
->CurDirectoryLen
= CommandData
->CurDirectoryLen
;
1489 GetNextVdmCommand
->EnvLen
= CommandData
->EnvLen
;
1490 GetNextVdmCommand
->DesktopLen
= CommandData
->DesktopLen
;
1491 GetNextVdmCommand
->TitleLen
= CommandData
->TitleLen
;
1492 GetNextVdmCommand
->ReservedLen
= CommandData
->ReservedLen
;
1493 GetNextVdmCommand
->VDMState
= CommandData
->VDMState
;
1495 /* Count the number of strings */
1496 if (CommandData
->CmdLen
) NumStrings
++;
1497 if (CommandData
->AppLen
) NumStrings
++;
1498 if (CommandData
->PifLen
) NumStrings
++;
1499 if (CommandData
->CurDirectoryLen
) NumStrings
++;
1500 if (CommandData
->EnvLen
) NumStrings
++;
1501 if (CommandData
->DesktopLen
) NumStrings
++;
1502 if (CommandData
->TitleLen
) NumStrings
++;
1503 if (CommandData
->ReservedLen
) NumStrings
++;
1505 /* Allocate the capture buffer */
1506 CaptureBuffer
= CsrAllocateCaptureBuffer(NumStrings
+ 1,
1507 GetNextVdmCommand
->CmdLen
1508 + GetNextVdmCommand
->AppLen
1509 + GetNextVdmCommand
->PifLen
1510 + GetNextVdmCommand
->CurDirectoryLen
1511 + GetNextVdmCommand
->EnvLen
1512 + GetNextVdmCommand
->DesktopLen
1513 + GetNextVdmCommand
->TitleLen
1514 + GetNextVdmCommand
->ReservedLen
1515 + sizeof(*GetNextVdmCommand
->StartupInfo
));
1516 if (CaptureBuffer
== NULL
)
1518 BaseSetLastNTError(STATUS_NO_MEMORY
);
1522 /* Capture the data */
1524 CsrAllocateMessagePointer(CaptureBuffer
,
1525 sizeof(*GetNextVdmCommand
->StartupInfo
),
1526 (PVOID
*)&GetNextVdmCommand
->StartupInfo
);
1528 if (CommandData
->CmdLen
)
1530 CsrAllocateMessagePointer(CaptureBuffer
,
1531 CommandData
->CmdLen
,
1532 (PVOID
*)&GetNextVdmCommand
->CmdLine
);
1535 if (CommandData
->AppLen
)
1537 CsrAllocateMessagePointer(CaptureBuffer
,
1538 CommandData
->AppLen
,
1539 (PVOID
*)&GetNextVdmCommand
->AppName
);
1542 if (CommandData
->PifLen
)
1544 CsrAllocateMessagePointer(CaptureBuffer
,
1545 CommandData
->PifLen
,
1546 (PVOID
*)&GetNextVdmCommand
->PifFile
);
1549 if (CommandData
->CurDirectoryLen
)
1551 CsrAllocateMessagePointer(CaptureBuffer
,
1552 CommandData
->CurDirectoryLen
,
1553 (PVOID
*)&GetNextVdmCommand
->CurDirectory
);
1556 if (CommandData
->EnvLen
)
1558 CsrAllocateMessagePointer(CaptureBuffer
,
1559 CommandData
->EnvLen
,
1560 (PVOID
*)&GetNextVdmCommand
->Env
);
1563 if (CommandData
->DesktopLen
)
1565 CsrAllocateMessagePointer(CaptureBuffer
,
1566 CommandData
->DesktopLen
,
1567 (PVOID
*)&GetNextVdmCommand
->Desktop
);
1570 if (CommandData
->TitleLen
)
1572 CsrAllocateMessagePointer(CaptureBuffer
,
1573 CommandData
->TitleLen
,
1574 (PVOID
*)&GetNextVdmCommand
->Title
);
1577 if (CommandData
->ReservedLen
)
1579 CsrAllocateMessagePointer(CaptureBuffer
,
1580 CommandData
->ReservedLen
,
1581 (PVOID
*)&GetNextVdmCommand
->Reserved
);
1587 Status
= CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1589 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetNextVDMCommand
),
1590 sizeof(*GetNextVdmCommand
));
1592 /* Exit the waiting loop if we did not receive any event handle */
1593 if (GetNextVdmCommand
->WaitObjectForVDM
== NULL
)
1596 /* Wait for the event to become signaled and try again */
1597 Status
= NtWaitForSingleObject(GetNextVdmCommand
->WaitObjectForVDM
,
1599 if (Status
!= STATUS_SUCCESS
)
1601 /* Fail if we timed out, or if some other error happened */
1602 BaseSetLastNTError(Status
);
1606 /* Set the retry flag, clear the exit code, and retry a query */
1607 GetNextVdmCommand
->VDMState
|= VDM_FLAG_RETRY
;
1608 GetNextVdmCommand
->ExitCode
= 0;
1611 if (!NT_SUCCESS(Status
))
1613 if (Status
== STATUS_INVALID_PARAMETER
)
1616 * One of the buffer lengths was less than required. Store the correct ones.
1617 * Note that the status code is not STATUS_BUFFER_TOO_SMALL as one would expect,
1618 * in order to keep compatibility with Windows 2003 BASESRV.DLL.
1620 CommandData
->CmdLen
= GetNextVdmCommand
->CmdLen
;
1621 CommandData
->AppLen
= GetNextVdmCommand
->AppLen
;
1622 CommandData
->PifLen
= GetNextVdmCommand
->PifLen
;
1623 CommandData
->CurDirectoryLen
= GetNextVdmCommand
->CurDirectoryLen
;
1624 CommandData
->EnvLen
= GetNextVdmCommand
->EnvLen
;
1625 CommandData
->DesktopLen
= GetNextVdmCommand
->DesktopLen
;
1626 CommandData
->TitleLen
= GetNextVdmCommand
->TitleLen
;
1627 CommandData
->ReservedLen
= GetNextVdmCommand
->ReservedLen
;
1631 /* Any other failure */
1632 CommandData
->CmdLen
= 0;
1633 CommandData
->AppLen
= 0;
1634 CommandData
->PifLen
= 0;
1635 CommandData
->CurDirectoryLen
= 0;
1636 CommandData
->EnvLen
= 0;
1637 CommandData
->DesktopLen
= 0;
1638 CommandData
->TitleLen
= 0;
1639 CommandData
->ReservedLen
= 0;
1642 BaseSetLastNTError(Status
);
1646 /* Write back the standard handles */
1647 CommandData
->StdIn
= GetNextVdmCommand
->StdIn
;
1648 CommandData
->StdOut
= GetNextVdmCommand
->StdOut
;
1649 CommandData
->StdErr
= GetNextVdmCommand
->StdErr
;
1651 /* Write back the startup info */
1652 RtlMoveMemory(&CommandData
->StartupInfo
,
1653 GetNextVdmCommand
->StartupInfo
,
1654 sizeof(*GetNextVdmCommand
->StartupInfo
));
1656 if (CommandData
->CmdLen
)
1658 /* Write back the command line */
1659 RtlMoveMemory(CommandData
->CmdLine
,
1660 GetNextVdmCommand
->CmdLine
,
1661 GetNextVdmCommand
->CmdLen
);
1663 /* Set the actual length */
1664 CommandData
->CmdLen
= GetNextVdmCommand
->CmdLen
;
1667 if (CommandData
->AppLen
)
1669 /* Write back the application name */
1670 RtlMoveMemory(CommandData
->AppName
,
1671 GetNextVdmCommand
->AppName
,
1672 GetNextVdmCommand
->AppLen
);
1674 /* Set the actual length */
1675 CommandData
->AppLen
= GetNextVdmCommand
->AppLen
;
1678 if (CommandData
->PifLen
)
1680 /* Write back the PIF file name */
1681 RtlMoveMemory(CommandData
->PifFile
,
1682 GetNextVdmCommand
->PifFile
,
1683 GetNextVdmCommand
->PifLen
);
1685 /* Set the actual length */
1686 CommandData
->PifLen
= GetNextVdmCommand
->PifLen
;
1689 if (CommandData
->CurDirectoryLen
)
1691 /* Write back the current directory */
1692 RtlMoveMemory(CommandData
->CurDirectory
,
1693 GetNextVdmCommand
->CurDirectory
,
1694 GetNextVdmCommand
->CurDirectoryLen
);
1696 /* Set the actual length */
1697 CommandData
->CurDirectoryLen
= GetNextVdmCommand
->CurDirectoryLen
;
1700 if (CommandData
->EnvLen
)
1702 /* Write back the environment */
1703 RtlMoveMemory(CommandData
->Env
,
1704 GetNextVdmCommand
->Env
,
1705 GetNextVdmCommand
->EnvLen
);
1707 /* Set the actual length */
1708 CommandData
->EnvLen
= GetNextVdmCommand
->EnvLen
;
1711 if (CommandData
->DesktopLen
)
1713 /* Write back the desktop name */
1714 RtlMoveMemory(CommandData
->Desktop
,
1715 GetNextVdmCommand
->Desktop
,
1716 GetNextVdmCommand
->DesktopLen
);
1718 /* Set the actual length */
1719 CommandData
->DesktopLen
= GetNextVdmCommand
->DesktopLen
;
1722 if (CommandData
->TitleLen
)
1724 /* Write back the title */
1725 RtlMoveMemory(CommandData
->Title
,
1726 GetNextVdmCommand
->Title
,
1727 GetNextVdmCommand
->TitleLen
);
1729 /* Set the actual length */
1730 CommandData
->TitleLen
= GetNextVdmCommand
->TitleLen
;
1733 if (CommandData
->ReservedLen
)
1735 /* Write back the reserved parameter */
1736 RtlMoveMemory(CommandData
->Reserved
,
1737 GetNextVdmCommand
->Reserved
,
1738 GetNextVdmCommand
->ReservedLen
);
1740 /* Set the actual length */
1741 CommandData
->ReservedLen
= GetNextVdmCommand
->ReservedLen
;
1744 /* Write the remaining output parameters */
1745 CommandData
->TaskId
= GetNextVdmCommand
->iTask
;
1746 CommandData
->CreationFlags
= GetNextVdmCommand
->dwCreationFlags
;
1747 CommandData
->CodePage
= GetNextVdmCommand
->CodePage
;
1748 CommandData
->ExitCode
= GetNextVdmCommand
->ExitCode
;
1749 CommandData
->CurrentDrive
= GetNextVdmCommand
->CurrentDrive
;
1750 CommandData
->VDMState
= GetNextVdmCommand
->VDMState
;
1751 CommandData
->ComingFromBat
= GetNextVdmCommand
->fComingFromBat
;
1753 /* It was successful */
1757 if (CaptureBuffer
!= NULL
) CsrFreeCaptureBuffer(CaptureBuffer
);
1767 GetVDMCurrentDirectories(DWORD cchCurDirs
, PCHAR lpszzCurDirs
)
1769 BASE_API_MESSAGE ApiMessage
;
1770 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &ApiMessage
.Data
.VDMCurrentDirsRequest
;
1771 PCSR_CAPTURE_BUFFER CaptureBuffer
;
1773 /* Allocate the capture buffer */
1774 CaptureBuffer
= CsrAllocateCaptureBuffer(1, cchCurDirs
);
1775 if (CaptureBuffer
== NULL
)
1777 BaseSetLastNTError(STATUS_NO_MEMORY
);
1781 /* Setup the input parameters */
1782 VDMCurrentDirsRequest
->cchCurDirs
= cchCurDirs
;
1783 CsrAllocateMessagePointer(CaptureBuffer
,
1785 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
);
1788 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1790 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepGetVDMCurDirs
),
1791 sizeof(*VDMCurrentDirsRequest
));
1793 /* Set the last error */
1794 BaseSetLastNTError(ApiMessage
.Status
);
1796 if (NT_SUCCESS(ApiMessage
.Status
))
1798 /* Copy the result */
1799 RtlMoveMemory(lpszzCurDirs
, VDMCurrentDirsRequest
->lpszzCurDirs
, cchCurDirs
);
1802 /* Free the capture buffer */
1803 CsrFreeCaptureBuffer(CaptureBuffer
);
1805 /* Return the size if it was successful, or if the buffer was too small */
1806 return (NT_SUCCESS(ApiMessage
.Status
) || (ApiMessage
.Status
== STATUS_BUFFER_TOO_SMALL
))
1807 ? VDMCurrentDirsRequest
->cchCurDirs
: 0;
1812 * @implemented (undocumented)
1816 RegisterConsoleVDM(IN DWORD dwRegisterFlags
,
1817 IN HANDLE hStartHardwareEvent
,
1818 IN HANDLE hEndHardwareEvent
,
1819 IN HANDLE hErrorHardwareEvent
,
1820 IN DWORD dwUnusedVar
,
1821 OUT LPDWORD lpVideoStateLength
,
1822 OUT PVOID
* lpVideoState
, // PVIDEO_HARDWARE_STATE_HEADER*
1823 IN PVOID lpUnusedBuffer
,
1824 IN DWORD dwUnusedBufferLength
,
1825 IN COORD dwVDMBufferSize
,
1826 OUT PVOID
* lpVDMBuffer
)
1829 CONSOLE_API_MESSAGE ApiMessage
;
1830 PCONSOLE_REGISTERVDM RegisterVDMRequest
= &ApiMessage
.Data
.RegisterVDMRequest
;
1831 PCSR_CAPTURE_BUFFER CaptureBuffer
= NULL
;
1833 /* Set up the data to send to the Console Server */
1834 RegisterVDMRequest
->ConsoleHandle
= NtCurrentPeb()->ProcessParameters
->ConsoleHandle
;
1835 RegisterVDMRequest
->RegisterFlags
= dwRegisterFlags
;
1837 if (dwRegisterFlags
!= 0)
1839 RegisterVDMRequest
->StartHardwareEvent
= hStartHardwareEvent
;
1840 RegisterVDMRequest
->EndHardwareEvent
= hEndHardwareEvent
;
1841 RegisterVDMRequest
->ErrorHardwareEvent
= hErrorHardwareEvent
;
1843 RegisterVDMRequest
->VDMBufferSize
= dwVDMBufferSize
;
1846 RegisterVDMRequest
->UnusedBufferLength
= dwUnusedBufferLength
;
1848 /* Allocate a Capture Buffer */
1849 CaptureBuffer
= CsrAllocateCaptureBuffer(1, dwUnusedBufferLength
);
1850 if (CaptureBuffer
== NULL
)
1852 DPRINT1("CsrAllocateCaptureBuffer failed!\n");
1853 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1857 /* Capture the buffer to write */
1858 CsrCaptureMessageBuffer(CaptureBuffer
,
1859 (PVOID
)lpUnusedBuffer
,
1860 dwUnusedBufferLength
,
1861 (PVOID
*)&RegisterVDMRequest
->UnusedBuffer
);
1866 // CaptureBuffer = NULL;
1869 /* Call the server */
1870 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1872 CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX
, ConsolepRegisterVDM
),
1873 sizeof(*RegisterVDMRequest
));
1875 /* Check for success */
1876 Success
= NT_SUCCESS(ApiMessage
.Status
);
1878 /* Release the capture buffer if needed */
1879 if (CaptureBuffer
) CsrFreeCaptureBuffer(CaptureBuffer
);
1881 /* Retrieve the results */
1884 if (dwRegisterFlags
!= 0)
1888 *lpVideoStateLength
= RegisterVDMRequest
->VideoStateLength
;
1889 *lpVideoState
= RegisterVDMRequest
->VideoState
;
1890 *lpVDMBuffer
= RegisterVDMRequest
->VDMBuffer
;
1892 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1894 SetLastError(ERROR_INVALID_ACCESS
);
1902 BaseSetLastNTError(ApiMessage
.Status
);
1905 /* Return success status */
1915 RegisterWowBaseHandlers (
1943 SetVDMCurrentDirectories(DWORD cchCurDirs
, PCHAR lpszzCurDirs
)
1945 BASE_API_MESSAGE ApiMessage
;
1946 PBASE_GETSET_VDM_CURDIRS VDMCurrentDirsRequest
= &ApiMessage
.Data
.VDMCurrentDirsRequest
;
1947 PCSR_CAPTURE_BUFFER CaptureBuffer
;
1949 /* Allocate the capture buffer */
1950 CaptureBuffer
= CsrAllocateCaptureBuffer(1, cchCurDirs
);
1951 if (CaptureBuffer
== NULL
)
1953 BaseSetLastNTError(STATUS_NO_MEMORY
);
1957 /* Setup the input parameters */
1958 VDMCurrentDirsRequest
->cchCurDirs
= cchCurDirs
;
1959 CsrCaptureMessageBuffer(CaptureBuffer
,
1962 (PVOID
*)&VDMCurrentDirsRequest
->lpszzCurDirs
);
1965 CsrClientCallServer((PCSR_API_MESSAGE
)&ApiMessage
,
1967 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX
, BasepSetVDMCurDirs
),
1968 sizeof(*VDMCurrentDirsRequest
));
1970 /* Free the capture buffer */
1971 CsrFreeCaptureBuffer(CaptureBuffer
);
1973 /* Set the last error */
1974 BaseSetLastNTError(ApiMessage
.Status
);
1976 return NT_SUCCESS(ApiMessage
.Status
) ? TRUE
: FALSE
;
1984 VDMConsoleOperation (
1999 VDMOperationStarted(IN ULONG Unknown0
)
2001 DPRINT1("VDMOperationStarted(%d)\n", Unknown0
);
2003 return BaseUpdateVDMEntry(VdmEntryUpdateControlCHandler
,