* PROJECT: ReactOS Win32 Base API
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/win32/kernel32/client/vdm.c
- * PURPOSE: Virtual Dos Machine (VDM) Support
+ * PURPOSE: Virtual DOS Machines (VDM) Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
ENV_INFO BasepEnvNameType[] =
{
- {3, sizeof(L"PATH"), L"PATH"},
- {2, sizeof(L"WINDIR"), L"WINDIR"},
+ {3, sizeof(L"PATH") , L"PATH" },
+ {2, sizeof(L"WINDIR") , L"WINDIR" },
{2, sizeof(L"SYSTEMROOT"), L"SYSTEMROOT"},
- {3, sizeof(L"TEMP"), L"TEMP"},
- {3, sizeof(L"TMP"), L"TMP"},
+ {3, sizeof(L"TEMP") , L"TEMP" },
+ {3, sizeof(L"TMP") , L"TMP" },
};
UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com");
/* Is it a .com? */
String.Length = BaseDotComSuffixName.Length;
String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
- if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return 2;
+ if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE)) return BINARY_TYPE_COM;
/* Is it a .pif? */
String.Length = BaseDotPifSuffixName.Length;
String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
- if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return 3;
+ if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE)) return BINARY_TYPE_PIF;
/* Is it an exe? */
String.Length = BaseDotExeSuffixName.Length;
String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
- if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return 1;
+ if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE)) return BINARY_TYPE_EXE;
+
return 0;
}
+NTSTATUS
+WINAPI
+BaseCheckVDM(IN ULONG BinaryType,
+ IN PCWCH ApplicationName,
+ IN PCWCH CommandLine,
+ IN PCWCH CurrentDirectory,
+ IN PANSI_STRING AnsiEnvironment,
+ IN PCSR_API_MESSAGE ApiMessage,
+ IN OUT PULONG iTask,
+ IN DWORD CreationFlags,
+ IN LPSTARTUPINFOW StartupInfo,
+ IN HANDLE hUserToken OPTIONAL)
+{
+ /* This is not supported */
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+BOOL
+WINAPI
+BaseUpdateVDMEntry(IN ULONG UpdateIndex,
+ IN OUT PHANDLE WaitHandle,
+ IN ULONG IndexInfo,
+ IN ULONG BinaryType)
+{
+ NTSTATUS Status;
+ BASE_API_MESSAGE ApiMessage;
+ PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVDMEntryRequest;
+
+ /* Check what update is being sent */
+ switch (UpdateIndex)
+ {
+ /* VDM is being undone */
+ case VdmEntryUndo:
+ {
+ /* Tell the server how far we had gotten along */
+ UpdateVdmEntry->iTask = HandleToUlong(*WaitHandle);
+ UpdateVdmEntry->VDMCreationState = IndexInfo;
+ break;
+ }
+
+ /* VDM is ready with a new process handle */
+ case VdmEntryUpdateProcess:
+ {
+ /* Send it the process handle */
+ UpdateVdmEntry->VDMProcessHandle = *WaitHandle;
+ UpdateVdmEntry->iTask = IndexInfo;
+ break;
+ }
+ }
+
+ /* Also check what kind of binary this is for the console handle */
+ if (BinaryType == BINARY_TYPE_WOW)
+ {
+ /* Magic value for 16-bit apps */
+ UpdateVdmEntry->ConsoleHandle = (HANDLE)-1;
+ }
+ else if (UpdateVdmEntry->iTask)
+ {
+ /* No handle for true VDM */
+ UpdateVdmEntry->ConsoleHandle = NULL;
+ }
+ else
+ {
+ /* Otherwise, use the regular console handle */
+ UpdateVdmEntry->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+ }
+
+ /* Finally write the index and binary type */
+ UpdateVdmEntry->EntryIndex = UpdateIndex;
+ UpdateVdmEntry->BinaryType = BinaryType;
+
+ /* Send the message to CSRSS */
+ Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+ NULL,
+ CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepUpdateVDMEntry),
+ sizeof(BASE_UPDATE_VDM_ENTRY));
+ if (!NT_SUCCESS(Status))
+ {
+ /* Handle failure */
+ BaseSetLastNTError(Status);
+ return FALSE;
+ }
+
+ /* If this was an update, CSRSS returns a new wait handle */
+ if (UpdateIndex == VdmEntryUpdateProcess)
+ {
+ /* Return it to the caller */
+ *WaitHandle = UpdateVdmEntry->WaitObjectForParent;
+ }
+
+ /* We made it */
+ return TRUE;
+}
+
BOOL
WINAPI
-BaseCheckForVDM(IN HANDLE hProcess,
- OUT LPDWORD lpExitCode)
+BaseCheckForVDM(IN HANDLE ProcessHandle,
+ OUT LPDWORD ExitCode)
{
NTSTATUS Status;
EVENT_BASIC_INFORMATION EventBasicInfo;
+ BASE_API_MESSAGE ApiMessage;
+ PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVDMExitCodeRequest;
/* It's VDM if the process is actually a wait handle (an event) */
- Status = NtQueryEvent(hProcess,
+ Status = NtQueryEvent(ProcessHandle,
EventBasicInformation,
&EventBasicInfo,
sizeof(EventBasicInfo),
NULL);
if (!NT_SUCCESS(Status)) return FALSE;
- /* FIXME: Send a message to csrss */
- return FALSE;
+ /* Setup the input parameters */
+ GetVdmExitCode->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+ GetVdmExitCode->hParent = ProcessHandle;
+
+ /* Call CSRSS */
+ Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+ NULL,
+ CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetVDMExitCode),
+ sizeof(BASE_GET_VDM_EXIT_CODE));
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Get the exit code from the reply */
+ *ExitCode = GetVdmExitCode->ExitCode;
+ return TRUE;
}
BOOL
WINAPI
-BaseGetVdmConfigInfo(IN LPCWSTR Reserved,
+BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
IN ULONG DosSeqId,
IN ULONG BinaryType,
IN PUNICODE_STRING CmdLineString,
/* Clear the buffer in case we fail */
CmdLineString->Buffer = 0;
-
- /* Always return the same size */
+
+ /* Always return the same size: 16 Mb */
*VdmSize = 0x1000000;
/* Get the system directory */
SetLastError(ERROR_INVALID_NAME);
return FALSE;
}
-
+
/* Check if this is VDM with a DOS Sequence ID */
if (DosSeqId)
{
- /* Build the VDM string for it */
+ /*
+ * Build the VDM string for it:
+ * -i%lx : Gives the DOS Sequence ID;
+ * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
+ */
_snwprintf(CommandLine,
sizeof(CommandLine),
L"\"%s\\ntvdm.exe\" -i%lx %s%c",
Buffer,
DosSeqId,
- (BinaryType == 0x10) ? L" " : L"-w",
- (BinaryType == 0x40) ? 's' : ' ');
+ (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
+ (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
}
else
{
- /* Non-DOS, build the stirng for it without the task ID */
+ /*
+ * Build the string for it without the DOS Sequence ID:
+ * %s%c : Nothing if DOS VDM, -w if WoW VDM, -ws if separate WoW VDM.
+ */
_snwprintf(CommandLine,
sizeof(CommandLine),
- L"\"%s\\ntvdm.exe\" %s%c",
+ L"\"%s\\ntvdm.exe\" %s%c",
Buffer,
- (BinaryType == 0x10) ? L" " : L"-w",
- (BinaryType == 0x40) ? 's' : ' ');
+ (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
+ (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
}
-
+
/* Create the actual string */
return RtlCreateUnicodeString(CmdLineString, CommandLine);
}
/* Start by assuming unknown type */
NameType = 1;
-
+
/* Loop all the environment names */
for (i = 0; i < (sizeof(BasepEnvNameType) / sizeof(ENV_INFO)); i++)
{
/* Get this entry */
EnvInfo = &BasepEnvNameType[i];
-
+
/* Check if it matches the name */
if ((EnvInfo->NameLength == NameLength) &&
!(_wcsnicmp(EnvInfo->Name, Name, NameLength)))
break;
}
}
-
+
/* Return what we found, or unknown if nothing */
return NameType;
}
IN PUNICODE_STRING UnicodeEnv)
{
ULONG Dummy = 0;
-
+
/* Clear the ASCII buffer since Rtl creates this for us */
if (AnsiEnv->Buffer) RtlFreeAnsiString(AnsiEnv);
-
+
/* The Unicode buffer is build by hand, though */
if (UnicodeEnv->Buffer)
{
{
BOOL Result;
ULONG RegionSize, EnvironmentSize = 0;
- PWCHAR p, Environment, NewEnvironment;
+ PWCHAR p, Environment, NewEnvironment = NULL;
NTSTATUS Status;
/* Make sure we have both strings */
SetLastError(ERROR_BAD_ENVIRONMENT);
goto Quickie;
}
-
+
/* Count how much space the whole environment takes */
p = Environment;
while ((*p++ != UNICODE_NULL) && (*p != UNICODE_NULL)) EnvironmentSize++;
NewEnvironment = NULL;
goto Quickie;
}
-
+
/* Begin parsing the new environment */
p = NewEnvironment;
/* Terminate it */
*p++ = UNICODE_NULL;
-
+
/* Initialize the unicode string to hold it */
EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
- RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, EnvironmentSize);
- UnicodeEnv->Length = EnvironmentSize;
-
+ RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
+ UnicodeEnv->Length = (USHORT)EnvironmentSize;
+
/* Create the ASCII version of it */
Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
if (!NT_SUCCESS(Status))
Quickie:
/* Cleanup path starts here, start by destroying the envrionment copy */
if (!(lpEnvironment) && (Environment)) RtlDestroyEnvironment(Environment);
-
+
/* See if we are here due to failure */
if (NewEnvironment)
{
/* Initialize the paths to be empty */
RtlInitEmptyUnicodeString(UnicodeEnv, NULL, 0);
RtlInitEmptyAnsiString(AnsiEnv, NULL, 0);
-
+
/* Free the environment copy */
RegionSize = 0;
Status = NtFreeVirtualMemory(NtCurrentProcess(),
MEM_RELEASE);
ASSERT(NT_SUCCESS(Status));
}
-
+
/* Return the result */
return Result;
}
}
}
- DPRINT1("Invalid binary type returned!\n", BinType);
+ DPRINT1("Invalid binary type %lu returned!\n", BinType);
return FALSE;
}
}
/*
- * @unimplemented
+ * @implemented
*/
-DWORD
+VOID
WINAPI
-ExitVDM (
- DWORD Unknown0,
- DWORD Unknown1
- )
+ExitVDM(BOOL IsWow, ULONG iWowTask)
{
- STUB;
- return 0;
+ BASE_API_MESSAGE ApiMessage;
+ PBASE_EXIT_VDM ExitVdm = &ApiMessage.Data.ExitVDMRequest;
+
+ /* Setup the input parameters */
+ ExitVdm->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
+ ExitVdm->iWowTask = IsWow ? iWowTask : 0; /* Always zero for DOS tasks */
+ ExitVdm->WaitObjectForVDM = NULL;
+
+ /* Call CSRSS */
+ CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
+ NULL,
+ CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepExitVDM),
+ sizeof(BASE_EXIT_VDM));
+
+ /* Close the returned wait object handle, if any */
+ if (NT_SUCCESS(ApiMessage.Status) && (ExitVdm->WaitObjectForVDM != NULL))
+ {
+ CloseHandle(ExitVdm->WaitObjectForVDM);
+ }
}
*/
DWORD
WINAPI
-GetNextVDMCommand (
- DWORD Unknown0
- )
+GetNextVDMCommand(PGET_NEXT_VDM_COMMAND_DATA CommandData)
{
STUB;
return 0;