* 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)
*/
/* TYPES **********************************************************************/
+typedef struct _ENV_INFO
+{
+ ULONG NameType;
+ ULONG NameLength;
+ PWCHAR Name;
+} ENV_INFO, *PENV_INFO;
+
+/* GLOBALS ********************************************************************/
+
+ENV_INFO BasepEnvNameType[] =
+{
+ {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" },
+};
+
+UNICODE_STRING BaseDotComSuffixName = RTL_CONSTANT_STRING(L".com");
+UNICODE_STRING BaseDotPifSuffixName = RTL_CONSTANT_STRING(L".pif");
+UNICODE_STRING BaseDotExeSuffixName = RTL_CONSTANT_STRING(L".exe");
+
/* FUNCTIONS ******************************************************************/
+ULONG
+WINAPI
+BaseIsDosApplication(IN PUNICODE_STRING PathName,
+ IN NTSTATUS Status)
+{
+ UNICODE_STRING String;
+
+ /* Is it a .com? */
+ String.Length = BaseDotComSuffixName.Length;
+ String.Buffer = &PathName->Buffer[(PathName->Length - String.Length) / sizeof(WCHAR)];
+ 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 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 BINARY_TYPE_EXE;
+
+ return 0;
+}
+
+BOOL
+WINAPI
+BaseCheckVDM(IN ULONG BinaryType,
+ IN PCWCH ApplicationName,
+ IN PCWCH CommandLine,
+ IN PCWCH CurrentDirectory,
+ IN PANSI_STRING AnsiEnvironment,
+ IN PBASE_API_MESSAGE ApiMessage,
+ IN OUT PULONG iTask,
+ IN DWORD CreationFlags,
+ IN LPSTARTUPINFOW StartupInfo,
+ IN HANDLE hUserToken OPTIONAL)
+{
+ /* This is not supported */
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+BOOL
+WINAPI
+BaseUpdateVDMEntry(IN ULONG UpdateIndex,
+ IN OUT PHANDLE WaitHandle,
+ IN ULONG IndexInfo,
+ IN ULONG BinaryType)
+{
+#if 0 // Unimplemented in BASESRV
+ NTSTATUS Status;
+ BASE_API_MESSAGE ApiMessage;
+ PBASE_UPDATE_VDM_ENTRY UpdateVdmEntry = &ApiMessage.Data.UpdateVdmEntry;
+
+ /* 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;
+ }
+#endif
+ /* We made it */
+ return TRUE;
+}
+
+BOOL
+WINAPI
+BaseCheckForVDM(IN HANDLE ProcessHandle,
+ OUT LPDWORD ExitCode)
+{
+#if 0 // Unimplemented in BASESRV
+ NTSTATUS Status;
+ EVENT_BASIC_INFORMATION EventBasicInfo;
+ BASE_API_MESSAGE ApiMessage;
+ PBASE_GET_VDM_EXIT_CODE GetVdmExitCode = &ApiMessage.Data.GetVdmExitCode;
+
+ /* It's VDM if the process is actually a wait handle (an event) */
+ Status = NtQueryEvent(ProcessHandle,
+ EventBasicInformation,
+ &EventBasicInfo,
+ sizeof(EventBasicInfo),
+ NULL);
+ if (!NT_SUCCESS(Status)) 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;
+#endif
+ return TRUE;
+}
+
+BOOL
+WINAPI
+BaseGetVdmConfigInfo(IN LPCWSTR CommandLineReserved,
+ IN ULONG DosSeqId,
+ IN ULONG BinaryType,
+ IN PUNICODE_STRING CmdLineString,
+ OUT PULONG VdmSize)
+{
+ WCHAR Buffer[MAX_PATH];
+ WCHAR CommandLine[MAX_PATH * 2];
+ ULONG Length;
+
+ /* Clear the buffer in case we fail */
+ CmdLineString->Buffer = 0;
+
+ /* Always return the same size: 16 Mb */
+ *VdmSize = 0x1000000;
+
+ /* Get the system directory */
+ Length = GetSystemDirectoryW(Buffer, MAX_PATH);
+ if (!(Length) || (Length >= MAX_PATH))
+ {
+ /* Eliminate no path or path too big */
+ SetLastError(ERROR_INVALID_NAME);
+ return FALSE;
+ }
+
+ /* Check if this is VDM with a DOS Sequence ID */
+ if (DosSeqId)
+ {
+ /*
+ * 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 == BINARY_TYPE_DOS) ? L" " : L"-w",
+ (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
+ }
+ else
+ {
+ /*
+ * 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",
+ Buffer,
+ (BinaryType == BINARY_TYPE_DOS) ? L" " : L"-w",
+ (BinaryType == BINARY_TYPE_SEPARATE_WOW) ? L's' : L' ');
+ }
+
+ /* Create the actual string */
+ return RtlCreateUnicodeString(CmdLineString, CommandLine);
+}
+
+UINT
+WINAPI
+BaseGetEnvNameType_U(IN PWCHAR Name,
+ IN ULONG NameLength)
+{
+ PENV_INFO EnvInfo;
+ ULONG NameType, i;
+
+ /* 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)))
+ {
+ /* It does, return the type */
+ NameType = EnvInfo->NameType;
+ break;
+ }
+ }
+
+ /* Return what we found, or unknown if nothing */
+ return NameType;
+}
+
+BOOL
+NTAPI
+BaseDestroyVDMEnvironment(IN PANSI_STRING AnsiEnv,
+ 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)
+ {
+ /* So clear it through the API */
+ NtFreeVirtualMemory(NtCurrentProcess(),
+ (PVOID*)&UnicodeEnv->Buffer,
+ &Dummy,
+ MEM_RELEASE);
+ }
+
+ /* All done */
+ return TRUE;
+}
+
+BOOL
+NTAPI
+BaseCreateVDMEnvironment(IN PWCHAR lpEnvironment,
+ IN PANSI_STRING AnsiEnv,
+ IN PUNICODE_STRING UnicodeEnv)
+{
+ BOOL Result;
+ ULONG RegionSize, EnvironmentSize = 0;
+ PWCHAR p, Environment, NewEnvironment = NULL;
+ NTSTATUS Status;
+
+ /* Make sure we have both strings */
+ if (!(AnsiEnv) || !(UnicodeEnv))
+ {
+ /* Fail */
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ /* Check if an environment was passed in */
+ if (!lpEnvironment)
+ {
+ /* Nope, create one */
+ Status = RtlCreateEnvironment(TRUE, (PWCHAR*)&Environment);
+ if (!NT_SUCCESS(Status)) goto Quickie;
+ }
+ else
+ {
+ /* Use the one we got */
+ Environment = lpEnvironment;
+ }
+
+ /* Do we have something now ? */
+ if (!Environment)
+ {
+ /* Still not, fail out */
+ SetLastError(ERROR_BAD_ENVIRONMENT);
+ goto Quickie;
+ }
+
+ /* Count how much space the whole environment takes */
+ p = Environment;
+ while ((*p++ != UNICODE_NULL) && (*p != UNICODE_NULL)) EnvironmentSize++;
+ EnvironmentSize += sizeof(UNICODE_NULL);
+
+ /* Allocate a new copy */
+ RegionSize = (EnvironmentSize + MAX_PATH) * sizeof(WCHAR);
+ if (!NT_SUCCESS(NtAllocateVirtualMemory(NtCurrentProcess(),
+ (PVOID*)&NewEnvironment,
+ 0,
+ &RegionSize,
+ MEM_COMMIT,
+ PAGE_READWRITE)))
+ {
+ /* We failed, bail out */
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ NewEnvironment = NULL;
+ goto Quickie;
+ }
+
+ /* Begin parsing the new environment */
+ p = NewEnvironment;
+
+ /* FIXME: Code here */
+
+ /* Terminate it */
+ *p++ = UNICODE_NULL;
+
+ /* Initialize the unicode string to hold it */
+ EnvironmentSize = (p - NewEnvironment) * sizeof(WCHAR);
+ RtlInitEmptyUnicodeString(UnicodeEnv, NewEnvironment, (USHORT)EnvironmentSize);
+ UnicodeEnv->Length = (USHORT)EnvironmentSize;
+
+ /* Create the ASCII version of it */
+ Status = RtlUnicodeStringToAnsiString(AnsiEnv, UnicodeEnv, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Set last error if conversion failure */
+ BaseSetLastNTError(Status);
+ }
+ else
+ {
+ /* Everything went okay, so return success */
+ Result = TRUE;
+ NewEnvironment = NULL;
+ }
+
+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(),
+ (PVOID*)&NewEnvironment,
+ &RegionSize,
+ MEM_RELEASE);
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ /* Return the result */
+ return Result;
+}
+
/* Check whether a file is an OS/2 or a very old Windows executable
* by testing on import of KERNEL.
}
}
- DPRINT1("Invalid binary type returned!\n", BinType);
+ DPRINT1("Invalid binary type %lu returned!\n", BinType);
return FALSE;
}