Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1039 lines
31 KiB

/*++
Copyright (c) 1998-2000 Microsoft Corporation
Module Name:
ntvdm64.c
Abstract:
Support for 16-bit process thunking on NT64
Author:
12-Jan-1999 PeterHal
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <wow64t.h>
#include <shlobj.h>
#include <stdio.h>
#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))
#if DBG
#define DEBUG_PRINT(args) DbgPrint args
#else
#define DEBUG_PRINT(args)
#endif
typedef struct {
LPCWSTR Name;
LPCWSTR Version;
LPCWSTR ProdName;
LPCWSTR InternalName;
LPCWSTR CmdLine;
LPCWSTR MappedExe;
} NTVDM64_ENTRY;
typedef CONST NTVDM64_ENTRY *PNTVDM64_ENTRY;
CONST NTVDM64_ENTRY NtVdm64Entries[] = {
{L"ACMSETUP301", L"3.01", L"Microsoft Setup for Windows", L"*", L"-m \"%m\" %c", L"setup16.exe"},
{L"ACMSETUP30", L"3.0", L"Microsoft Setup for Windows", L"*", L"-m \"%m\" %c", L"setup16.exe"},
{L"ACMSETUP30K", L"3.0", L"Microsoft Windows*", L"bootstrp", L"-m \"%m\" %c", L"setup16.exe"},
{L"ACMSETUP30G", L"3.0", L"Microsoft Setup*", L"bootstrp", L"-m \"%m\" %c", L"setup16.exe"},
{L"ACMSETUP30F", L"3.0", L"Programme d'installation Microsoft pour Windows", L"bootstrp", L"-m \"%m\" %c", L"setup16.exe"},
{L"ACMSETUP26", L"2.6", L"Microsoft Setup for Windows", L"*", L"-m \"%m\" %c", L"setup16.exe"},
{L"ACMSETUP12", L"1.2", L"Microsoft Setup for Windows", L"*", L"-m \"%m\" %c", L"setup16.exe"},
{L"INSTALLSHIELD5", L"5*", L"InstallShield*", L"*", L"-isw64\"%m\" %c", L"InstallShield\\setup.exe"}
};
#if !_WIN64
CONST int CsidlList[] = {
CSIDL_COMMON_STARTMENU,
CSIDL_COMMON_PROGRAMS,
CSIDL_COMMON_STARTUP,
CSIDL_COMMON_DESKTOPDIRECTORY,
CSIDL_COMMON_APPDATA,
CSIDL_COMMON_TEMPLATES,
CSIDL_COMMON_DOCUMENTS,
CSIDL_COMMON_ADMINTOOLS,
CSIDL_COMMON_FAVORITES
};
#endif
LONG
CreateNtvdm64Entry(
HKEY hKeyVdm,
PNTVDM64_ENTRY Entry
)
/*++
Routine Description:
Write a registry entry for a single entry in the table
Arguments:
hKeyVdm - key to write the entry to
Entry - the entry to write
Return Value:
LONG - a return code from a Registry API, 0 for success
--*/
{
LONG l;
HKEY h;
WCHAR Path[MAX_PATH];
if (!GetSystemWindowsDirectoryW(Path, sizeof(Path)/sizeof(Path[0]))) {
return 1;
}
if ((lstrlenW(Path) + (sizeof (L"\\" WOW64_SYSTEM_DIRECTORY_U L"\\") / sizeof(WCHAR))) >= (sizeof(Path)/sizeof(Path[0]))) {
return 1;
}
wcscat(Path, L"\\" WOW64_SYSTEM_DIRECTORY_U L"\\");
if ((lstrlenW(Path) + lstrlenW(Entry->MappedExe)) >= (sizeof(Path)/sizeof(Path[0]))) {
return 1;
}
wcscat(Path, Entry->MappedExe);
l = RegCreateKeyW(hKeyVdm, Entry->Name, &h);
if (l) {
return l;
}
l = RegSetValueExW(h, L"CommandLine", 0, REG_SZ, (BYTE *)Entry->CmdLine, (wcslen(Entry->CmdLine)+1)*sizeof(WCHAR));
if (l) goto exit;
l = RegSetValueExW(h, L"ProductName", 0, REG_SZ, (BYTE *)Entry->ProdName, (wcslen(Entry->ProdName)+1)*sizeof(WCHAR));
if (l) {
return l;
}
l = RegSetValueExW(h, L"InternalName", 0, REG_SZ, (BYTE *)Entry->InternalName, (wcslen(Entry->InternalName)+1)*sizeof(WCHAR));
if (l) {
return l;
}
l = RegSetValueExW(h, L"ProductVersion", 0, REG_SZ, (BYTE *)Entry->Version, (wcslen(Entry->Version)+1)*sizeof(WCHAR));
if (l) goto exit;
l = RegSetValueExW(h, L"MappedExeName", 0, REG_SZ, (BYTE *)Path, (wcslen(Path)+1)*sizeof(WCHAR));
exit: RegCloseKey (h); //askhalid fix resource leak Adding RegCloseKey
return l;
}
STDAPI
DllInstall(
BOOL bInstall,
LPCWSTR pszCmdLine
)
/*++
Routine Description:
Routine called during guimode setup to register ntvdm64.dll
Arguments:
bInstall - TRUE if registering, FALSE if unregistering
pszCmdLine - command-line
Return Value:
HRESULT
--*/
{
HKEY hKeyVdm;
LONG l;
SIZE_T i;
WCHAR Path[MAX_PATH];
BOOL bResult;
UNREFERENCED_PARAMETER(pszCmdLine);
if (!bInstall) {
// There is no uninstall for ntvdm64
return NOERROR;
}
l = RegCreateKeyW(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\NtVdm64",
&hKeyVdm);
if (l) {
return E_FAIL;
}
for (i=0; i<ARRAYSIZE(NtVdm64Entries); ++i) {
l = CreateNtvdm64Entry(hKeyVdm, &NtVdm64Entries[i]);
if (l) {
break;
}
}
RegCloseKey(hKeyVdm);
if (l) {
return E_FAIL;
}
#if !_WIN64
//
// Call shell32, asking for some common CSIDL_ values. This forces
// shell32 to create values under HKLM\Software\Microsoft\Windows\
// Explorere\Shell Folders. Some apps (VB, VC, MSDN) expect these
// values to be present in the registry, but they are created on-demand
// as a side-effect of calling the shell APIs to query for them. On x86
// NT, guimode setup itself calls shell32 several times, while creating
// the Start Menu, etc. so several values are always present when apps
// run for the first time.
//
for (i=0; i<sizeof(CsidlList)/sizeof(CsidlList[0]); ++i) {
bResult = SHGetSpecialFolderPathW(NULL, Path, CsidlList[i], TRUE);
if (!bResult) {
return E_FAIL;
}
}
#endif
return NOERROR;
}
//-----------------------------------------------------------------------
// This section is ripped off from mvdm\wow32\wkman.c
//
// MyVerQueryValue checks several popular code page values for the given
// string. This may need to be extended ala WinFile's wfdlgs2.c to search
// the translation table. For now we only need a few.
//
BOOL
MyVerQueryValue(
const LPVOID pBlock,
LPWSTR lpName,
LPVOID * lplpBuffer,
PUINT puLen
)
{
DWORD dwDefaultLanguage[] = {0x04E40409, 0x00000409};
WCHAR szSubBlock[128];
PDWORD pdwTranslation;
DWORD uLen;
BOOL fRet;
int i;
if(!VerQueryValue(pBlock, "\\VarFileInfo\\Translation", (PVOID*)&pdwTranslation, &uLen)) {
pdwTranslation = dwDefaultLanguage;
uLen = sizeof (dwDefaultLanguage);
}
fRet = FALSE;
while ((uLen > 0) && !fRet) {
swprintf(szSubBlock, L"\\StringFileInfo\\%04X%04X\\%ws",
LOWORD(*pdwTranslation),
HIWORD(*pdwTranslation),
lpName);
fRet = VerQueryValueW(pBlock, szSubBlock, lplpBuffer, puLen);
pdwTranslation++;
uLen -= sizeof (DWORD);
}
if (!fRet) {
DEBUG_PRINT(("NtVdm64: Failed to get resource %ws.\n", lpName));
}
return fRet;
}
//
// Utility routine to fetch the Product Name and Product Version strings
// from a given EXE.
//
BOOL
WowGetProductNameVersion(
LPCWSTR pszExePath,
LPWSTR pszProductName,
DWORD cbProductName,
LPWSTR pszInternalName,
DWORD cbInternalName,
LPWSTR pszProductVersion,
DWORD cbProductVersion
)
{
DWORD dwZeroMePlease;
DWORD cbVerInfo;
LPVOID lpVerInfo = NULL;
LPWSTR pName;
DWORD cbName;
LPWSTR pIntName;
DWORD cbIntName;
LPWSTR pVersion;
DWORD cbVersion;
*pszProductName = 0;
*pszInternalName = 0;
*pszProductVersion = 0;
cbVerInfo = GetFileVersionInfoSizeW((LPWSTR)pszExePath, &dwZeroMePlease);
if (!cbVerInfo) {
return TRUE;
}
lpVerInfo = RtlAllocateHeap( RtlProcessHeap(), 0, (cbVerInfo));
if (!lpVerInfo) {
DEBUG_PRINT(("NtVdm64: Failed to allocate version info.\n"));
return FALSE;
}
if (!GetFileVersionInfoW((LPWSTR)pszExePath, 0, cbVerInfo, lpVerInfo)) {
DEBUG_PRINT(("NtVdm64: Failed to get version info. GLE %x\n", GetLastError()));
return FALSE;
}
if (MyVerQueryValue(lpVerInfo, L"ProductName", &pName, &cbName)) {
if (cbName <= cbProductName) {
wcscpy(pszProductName, pName);
} else {
DEBUG_PRINT(("NtVdm64: ProductName resource too large %ws. Size %x\n", pName, cbName));
}
}
if (MyVerQueryValue(lpVerInfo, L"InternalName", &pIntName, &cbIntName)) {
if (cbIntName <= cbInternalName) {
wcscpy(pszInternalName, pIntName);
} else {
DEBUG_PRINT(("NtVdm64: InternalName resource too large %ws. Sizw %x\n", pIntName, cbIntName));
}
}
if (MyVerQueryValue(lpVerInfo, L"ProductVersion", &pVersion, &cbVersion)) {
if (cbVersion <= cbProductVersion) {
wcscpy(pszProductVersion, pVersion);
} else {
DEBUG_PRINT(("NtVdm64: ProductVersion resource too large %ws. Size %x\n", pVersion, cbVersion));
}
}
RtlFreeHeap(RtlProcessHeap(), 0, lpVerInfo);
return TRUE;
}
//-----------------------------------------------------------------------
LPWSTR
GetDotExeEndPtr(
LPCWSTR Path)
/*++
Routine Description:
Returns a pointer to the end of .EXE in the path name, if exists
Arguments:
Path - File path to an executable.
Return Value:
Pointer to the end of the applicable ".EXE", otherwise NULL.
cases:
""a:\foo.exe \foo.exe" /p xx" .exe should point to the last one.
--*/
{
PWSTR pwsz = (PWSTR)Path;
BOOL bQuteMatch = FALSE;
PWSTR strGoodOccurance = NULL;
if (pwsz == NULL)
return NULL;
while (*pwsz != UNICODE_NULL) {
if (*pwsz == L'"') {
bQuteMatch = !bQuteMatch; // this must be false at the time of match.
if (!bQuteMatch)
return pwsz++;
}
if (*pwsz == L'.') {
if ( (pwsz[1] == L'e' || pwsz[1]==L'E') &&
(pwsz[1] == L'e' || pwsz[1]==L'E') &&
(pwsz[1] == L'e' || pwsz[1]==L'E')
) { // found an exe match
pwsz += 4;
if (*pwsz == L'"') {
bQuteMatch = !bQuteMatch;
pwsz++; //skip double quote
}
if ( !bQuteMatch) //quote matching is done
return pwsz;
else continue;
}
}//if
pwsz++;
} // while loop
return NULL;
}
BOOL
MapCommandLine(
HKEY hkeyMapping,
LPCWSTR lpWin16ApplicationName,
LPCWSTR lpMappedApplicationName,
BOOL fPrefixMappedApplicationName,
LPCWSTR lpCommandLine,
LPWSTR *lplpMappedCommandLine
)
/*++
Routine Description:
Maps the command line for a Win16 application.
Arguments:
hkeyMapping - open registry keyfor the mapping entry
lpWin16ApplicationName - Win16 file name (with path)
lpMappedApplicationName - the ported version
of lpWin16ApplicationName
fPrefixMappedApplicationName
- TRUE means that the original lpApplicationName was NULL.
The application name was stripped from the head of
lpCommandLine.
The mapped application name needs to be added to the
head of the mapped command line.
- FALSE means that the original lpAPplicationName was non-NULL.
the lpCommandLine argument is identical to the original
lpCommandLine argument.
lpCommandLine - see comment for fPrefixMappedApplicationName.
lplpMappedCommandLine - returns the mapped command line
caller must free the returned pointer using RtlFreeHeap
Return Value:
TRUE if the mapping was successful
--*/
{
WCHAR achBuffer[MAX_PATH+1];
DWORD dwBufferLength;
DWORD dwType;
LPWSTR lpsz;
LPWSTR lpMappedCommandLine;
DWORD dwRequiredBufferLength;
LONG result;
LPCWSTR lpOriginalCommandLine;
// set default command line to empty string
if (NULL == lpCommandLine) {
lpCommandLine = L"";
}
lpOriginalCommandLine = lpCommandLine;
// get the command line map from the registry
dwBufferLength = ARRAYSIZE(achBuffer);
result = RegQueryValueExW(hkeyMapping, L"CommandLine", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
if (ERROR_SUCCESS != result || dwType != REG_SZ) {
DEBUG_PRINT(("NtVdm64: CommandLine failed to get REG_SZ value. Result %x Type %x\n", result, dwType));
return FALSE;
}
// calculate mapped buffer size and allocate it
dwRequiredBufferLength = 1;
if (fPrefixMappedApplicationName) {
dwRequiredBufferLength += wcslen(lpMappedApplicationName) + 1;
} else {
PWSTR pDotExeEndPtr;
pDotExeEndPtr = GetDotExeEndPtr (lpCommandLine);
if (pDotExeEndPtr != NULL) {
ASSERT (pDotExeEndPtr > lpCommandLine);
ASSERT (((ULONG_PTR)pDotExeEndPtr & 0x01) == 0);
while (lpCommandLine != pDotExeEndPtr) {
dwRequiredBufferLength++;
lpCommandLine++;
}
} else {
while (*lpCommandLine && *lpCommandLine != L' ') {
dwRequiredBufferLength++;
lpCommandLine++;
}
}
// consume any extra spaces
while (*lpCommandLine == L' ') {
lpCommandLine++;
}
// account for one space in the output buffer
dwRequiredBufferLength++;
}
lpsz = achBuffer;
while (*lpsz) {
if (*lpsz == L'%') {
lpsz += 1;
switch (*lpsz) {
// %c : Insert Original Command Line
case L'c':
case L'C':
lpsz += 1;
dwRequiredBufferLength += wcslen(lpCommandLine);
break;
// %m : Insert Original Module Name
case L'm':
case L'M':
lpsz += 1;
dwRequiredBufferLength += wcslen(lpWin16ApplicationName);
break;
// %% : Insert a real %
case L'%':
lpsz += 1;
dwRequiredBufferLength += 1;
break;
// %\0 : eat terminating %\0
case 0:
DEBUG_PRINT(("NtVdm64: ignoring trailing %% in CommandLine.\n"));
break;
// %x : undefined macro expands to nothing
default:
DEBUG_PRINT(("NtVdm64: ignoring unknown macro %%%wc in CommandLine.\n", *lpsz));
lpsz += 1;
break;
}
} else {
lpsz += 1;
dwRequiredBufferLength += 1;
}
}
*lplpMappedCommandLine = RtlAllocateHeap(RtlProcessHeap(), 0, dwRequiredBufferLength * sizeof (WCHAR));
if (!*lplpMappedCommandLine) {
DEBUG_PRINT(("NtVdm64: failed to allocate CommandLine. GLE %x.\n", GetLastError()));
return FALSE;
}
// map the buffer
lpCommandLine = lpOriginalCommandLine;
lpsz = achBuffer;
lpMappedCommandLine = *lplpMappedCommandLine;
if (fPrefixMappedApplicationName) {
wcscpy(lpMappedCommandLine, lpMappedApplicationName);
lpMappedCommandLine += wcslen(lpMappedApplicationName);
*lpMappedCommandLine = L' ';
lpMappedCommandLine += 1;
} else {
// copy in the first whitespace-delimited part of the old
// command-line as it is the name of the app.
PWSTR pDotExeEndPtr;
pDotExeEndPtr = GetDotExeEndPtr (lpCommandLine);
if (pDotExeEndPtr != NULL) {
ASSERT (pDotExeEndPtr > lpCommandLine);
ASSERT (((ULONG_PTR)pDotExeEndPtr & 0x01) == 0);
while (lpCommandLine != pDotExeEndPtr) {
*lpMappedCommandLine = *lpCommandLine;
lpMappedCommandLine++;
lpCommandLine++;
}
} else {
while (*lpCommandLine && *lpCommandLine != L' ') {
*lpMappedCommandLine = *lpCommandLine;
lpMappedCommandLine++;
lpCommandLine++;
}
}
// add in a space of padding and skip over any spaces in the
// original command line
*lpMappedCommandLine++ = L' ';
while (*lpCommandLine == L' ') {
lpCommandLine++;
}
}
while (*lpsz) {
if (*lpsz == L'%') {
lpsz += 1;
switch (*lpsz) {
// %c : Insert Original Command Line
case L'c':
case L'C':
lpsz += 1;
wcscpy(lpMappedCommandLine, lpCommandLine);
lpMappedCommandLine += wcslen(lpCommandLine);
break;
// %m : Insert Original Module Name
case L'm':
case L'M':
lpsz += 1;
wcscpy(lpMappedCommandLine, lpWin16ApplicationName);
lpMappedCommandLine += wcslen(lpWin16ApplicationName);
break;
// %% : Insert a real %
case L'%':
lpsz += 1;
*lpMappedCommandLine = L'%';
lpMappedCommandLine += 1;
break;
// %\0 : eat terminating %\0
case 0:
break;
// %x : undefined macro expands to nothing
default:
lpsz += 1;
break;
}
} else {
*lpMappedCommandLine = *lpsz;
lpMappedCommandLine += 1;
lpsz += 1;
}
}
*lpMappedCommandLine = L'\0';
return TRUE;
}
int
CompareStrings(
LPWSTR lpRegString,
LPCWSTR lpExeString
)
/*++
Routine Description:
Compares strings using a minimal wildcard support in addition
to just a stock wcscmp. The RegString can have an optional '*'
which is used as a wildcard that matches any characters upto the
end of the string.
Arguments:
lpRegString - string loaded from the registry
lpExeString - string loaded from the app's resource section
Return Value:
same as wcscmp: 0 for equal, nonzero non-equal
--*/
{
LPCWSTR pRegStar;
if (wcscmp(lpRegString, lpExeString) == 0) {
// an exact match
return 0;
}
// not an exact match - see if the registry key contains a wildcard
pRegStar = wcschr(lpRegString, L'*');
if (!pRegStar) {
// No wildcard in the registry key, so no match
return -1;
}
if (pRegStar == lpRegString) {
// Wildcard is the first character - match everything
return 0;
}
// Compare only upto the character before the '*'
return wcsncmp(lpRegString, lpExeString,
pRegStar - lpRegString);
}
BOOL
CheckMapArguments(
HKEY hkeyMapping,
LPCWSTR lpApplicationName,
LPCWSTR lpProductName,
LPCWSTR lpInternalName,
LPCWSTR lpProductVersion,
LPWSTR lpMappedApplicationName,
DWORD dwMappedApplicationNameSize,
BOOL fPrefixMappedApplicationName,
LPCWSTR lpCommandLine,
LPWSTR *lplpMappedCommandLine
)
/*++
Routine Description:
Attempts to map a Win16 application and command line to their ported version
using a single entry in the NtVdm64 mapping in the registry.
Arguments:
hkeyMapping - open registry keyfor the mapping entry
lpApplicationName - Win16 file name (with path)
lpExeName - Win16 file name wihtout path
lpProductName - value of ProductName Version resource of lpApplicationName
lpProductVersion - value of ProductVersion version resource of lpApplicationName
lpMappedApplicationName - returns the name of the ported version
of lpApplicationName
dwMappedApplicationNameSize - size of lpMappedApplicationName buffer
fPrefixMappedApplicationName
- TRUE means that the original lpApplicationName was NULL.
The application name was stripped from the head of
lpCommandLine.
The mapped application name needs to be added to the
head of the mapped command line.
- FALSE means that the original lpAPplicationName was non-NULL.
the lpCommandLine argument is identical to the original
lpCommandLine argument.
lpCommandLine - see comment for fPrefixMappedApplicationName.
lplpMappedCommandLine - returns the mapped command line
caller must free the returned pointer using RtlFreeHeap
Return Value:
TRUE if the mapping was successful
--*/
{
WCHAR achBuffer[MAX_PATH+1];
DWORD dwBufferLength;
DWORD dwType;
LONG result;
dwBufferLength = ARRAYSIZE(achBuffer);
result = RegQueryValueExW(hkeyMapping, L"ProductName", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
if (ERROR_SUCCESS != result || dwType != REG_SZ) {
DEBUG_PRINT(("NtVdm64: Failed to open ProductName REG_SZ key. Result %x. Type %x\n", result, dwType));
return FALSE;
}
if (CompareStrings(achBuffer, lpProductName)) {
DEBUG_PRINT(("NtVdm64: ProductName mismatch %ws vs %ws\n", achBuffer, lpProductName));
return FALSE;
}
dwBufferLength = ARRAYSIZE(achBuffer);
result = RegQueryValueExW(hkeyMapping, L"InternalName", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
if (ERROR_SUCCESS != result || dwType != REG_SZ) {
DEBUG_PRINT(("NtVdm64: Failed to open InternalName REG_SZ key. Result %x. Type %x\n", result, dwType));
return FALSE;
}
if (CompareStrings(achBuffer, lpInternalName)) {
DEBUG_PRINT(("NtVdm64: InternalName mismatch %ws vs %ws\n", achBuffer, lpInternalName));
return FALSE;
}
dwBufferLength = ARRAYSIZE(achBuffer);
result = RegQueryValueExW(hkeyMapping, L"ProductVersion", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
if (ERROR_SUCCESS != result || dwType != REG_SZ) {
DEBUG_PRINT(("NtVdm64: Failed to open ProductVersion REG_SZ key. Result %x. Type %x\n", result, dwType));
return FALSE;
}
if (CompareStrings(achBuffer, lpProductVersion)) {
DEBUG_PRINT(("NtVdm64: ProductVersion mismatch %ws vs %ws\n", achBuffer, lpProductVersion));
return FALSE;
}
dwBufferLength = ARRAYSIZE(achBuffer);
result = RegQueryValueExW(hkeyMapping, L"MappedExeName", 0, &dwType, (LPBYTE)achBuffer, &dwBufferLength);
if (ERROR_SUCCESS != result) {
DEBUG_PRINT(("NtVdm64: Failed to open MappedExeName REG_SZ key. Result %x.\n", result));
return FALSE;
}
if (dwType == REG_EXPAND_SZ) {
WCHAR achBuffer2[MAX_PATH+1];
wcscpy(achBuffer2, achBuffer);
dwBufferLength = ExpandEnvironmentStringsW(achBuffer2, achBuffer, ARRAYSIZE(achBuffer));
if (dwBufferLength == 0 || dwBufferLength > ARRAYSIZE(achBuffer)) {
DEBUG_PRINT(("NtVdm64: MappedExeName failed to expand environment strings in %ws. Length %x\n", achBuffer, dwBufferLength));
return FALSE;
}
} else if (dwType != REG_SZ) {
DEBUG_PRINT(("NtVdm64: MappedExeName value doesn't have string type. Type %x\n", dwType));
return FALSE;
}
if (dwBufferLength > dwMappedApplicationNameSize) {
DEBUG_PRINT(("NtVdm64: MappedExeName too long. Length %x\n", dwBufferLength));
return FALSE;
}
wcscpy(lpMappedApplicationName, achBuffer);
if (!MapCommandLine(hkeyMapping, lpApplicationName, lpMappedApplicationName, fPrefixMappedApplicationName, lpCommandLine, lplpMappedCommandLine)) {
return FALSE;
}
return TRUE;
}
BOOL
MapArguments(
LPCWSTR lpApplicationName,
LPWSTR lpMappedApplicationName,
DWORD dwMappedApplicationNameSize,
BOOL fPrefixMappedApplicationName,
LPCWSTR lpCommandLine,
LPWSTR *lplpMappedCommandLine
)
/*++
Routine Description:
Maps a Win16 application and command line to their ported version
using the NtVdm64 mapping in the registry.
Arguments:
lpApplicationName - Win16 file name not optional
lpMappedApplicationName - returns the name of the ported version
of lpApplicationName
dwMappedApplicationNameSize - size of lpMappedApplicationName buffer
fPrefixMappedApplicationName
- TRUE means that the original lpApplicationName was NULL.
The application name was stripped from the head of
lpCommandLine.
The mapped application name needs to be added to the
head of the mapped command line.
- FALSE means that the original lpAPplicationName was non-NULL.
the lpCommandLine argument is identical to the original
lpCommandLine argument.
lpCommandLine - see comment for fPrefixMappedApplicationName.
lplpMappedCommandLine - returns the mapped command line
caller must free the returned pointer using RtlFreeHeap
Return Value:
TRUE if the mapping was successful
--*/
{
HKEY hkeyMappingRoot;
LONG result;
DWORD dwIndex;
WCHAR achSubKeyName[MAX_PATH+1];
DWORD dwSubKeyNameLength;
BOOL mapped;
WCHAR achExeNameBuffer[MAX_PATH+1];
LPWSTR lpExeName;
WCHAR achProductName[MAX_PATH+1];
WCHAR achInternalName[MAX_PATH+1];
WCHAR achProductVersion[MAX_PATH+1];
//
// get the .exe name without the preceding path
//
if (0 == SearchPathW(
NULL,
lpApplicationName,
(PWSTR)L".exe",
MAX_PATH,
achExeNameBuffer,
&lpExeName
)) {
DEBUG_PRINT(("NtVdm64: SearchPathW failed: %ws\n", lpApplicationName));
return FALSE;
}
if (!WowGetProductNameVersion(lpApplicationName,
achProductName,
ARRAYSIZE(achProductName),
achInternalName,
ARRAYSIZE(achInternalName),
achProductVersion,
ARRAYSIZE(achProductVersion))) {
return FALSE;
}
mapped = FALSE;
result = RegOpenKeyW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NtVdm64",
&hkeyMappingRoot
);
if (ERROR_SUCCESS != result) {
DEBUG_PRINT(("NtVdm64: Failed to Open NtVdm64 Registry Key : %x\n", result));
return FALSE;
}
dwIndex = 0;
dwSubKeyNameLength = ARRAYSIZE(achSubKeyName);
while (!mapped && ERROR_SUCCESS == (result = RegEnumKeyW(hkeyMappingRoot, dwIndex, achSubKeyName, dwSubKeyNameLength))) {
HKEY hkeyMapping;
result = RegOpenKeyW(hkeyMappingRoot, achSubKeyName, &hkeyMapping);
if (ERROR_SUCCESS == result) {
mapped = CheckMapArguments(hkeyMapping,
lpApplicationName,
achProductName,
achInternalName,
achProductVersion,
lpMappedApplicationName,
dwMappedApplicationNameSize,
fPrefixMappedApplicationName,
lpCommandLine,
lplpMappedCommandLine);
RegCloseKey(hkeyMapping);
}
dwSubKeyNameLength = ARRAYSIZE(achSubKeyName);
dwIndex += 1;
}
RegCloseKey(hkeyMappingRoot);
if ( !mapped )
DEBUG_PRINT(("NtVdm64: Unknown 16bit app or given parameters are wrong\n"));
return mapped;
}
extern
BOOL STDAPICALLTYPE ApphelpCheckExe(
LPCWSTR lpApplicationName,
BOOL bApphelp,
BOOL bShim,
BOOL bUseModuleName);
BOOL
CheckAppCompat(
LPCWSTR lpApplicationName
)
/*++
Check application compatibility database for blocked application,
possibly show UI advising user of a problem
--*/
{
return ApphelpCheckExe(lpApplicationName,
TRUE,
FALSE,
FALSE);
}
BOOL
WINAPI
NtVdm64CreateProcess(
BOOL fPrefixMappedApplicationName,
LPCWSTR lpApplicationName,
LPCWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
)
/*++
Routine Description:
Checks if there is a ported version of the Win16 lpApplicationName and
if so creates a process with the ported version.
Arguments:
fPrefixMappedApplicationName
- TRUE means that the original lpApplicationName was NULL.
The application name was stripped from the head of
lpCommandLine.
The mapped application name needs to be added to the
head of the mapped command line.
- FALSE means that the original lpAPplicationName was non-NULL.
the lpCommandLine argument is identical to the original
lpCommandLine argument.
lpApplicationName - Win16 file name not optional
lpCommandLine - see comment for fPrefixMappedApplicationName.
other arguments are identical to CreateProcessW.
Return Value:
Same as CreateProcessW
--*/
{
WCHAR achMappedApplicationName[MAX_PATH+1];
LPWSTR lpMappedCommandLine;
BOOL Result;
ASSERT(lpApplicationName);
//
// check appcompat
//
if (!CheckAppCompat(lpApplicationName)) {
SetLastError(ERROR_CANCELLED);
return FALSE;
}
if (lpCommandLine == NULL) {
lpCommandLine = L"";
}
lpMappedCommandLine = NULL;
Result = MapArguments(lpApplicationName,
achMappedApplicationName,
ARRAYSIZE(achMappedApplicationName),
fPrefixMappedApplicationName,
lpCommandLine,
&lpMappedCommandLine);
if (Result) {
Result = CreateProcessW((fPrefixMappedApplicationName ?
NULL :
achMappedApplicationName),
lpMappedCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
if (lpMappedCommandLine) {
RtlFreeHeap(RtlProcessHeap(), 0, lpMappedCommandLine);
}
} else {
SetLastError(ERROR_BAD_EXE_FORMAT);
}
return Result;
}