windows-nt/Source/XPSP1/NT/windows/appcompat/sdbapi/win32base.c
2020-09-26 16:20:57 +08:00

1683 lines
41 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
win32base.c
Abstract:
This module implements low level primitives that are win32 compatible.
Author:
clupu created 10/25/2000
Revision History:
--*/
#include "sdbp.h"
#include <time.h>
#include <shlwapi.h>
// Define this for bounds-checked detection of leaks.
// #define BOUNDS_CHECKER_DETECTION
//
// Memory functions
//
void*
SdbAlloc(
IN size_t size // size in bytes to allocate
)
/*++
Return: The pointer allocated.
Desc: Just a wrapper for allocation -- perhaps useful if we move this
code to a non-NTDLL location and need to call differently.
--*/
{
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
}
void
SdbFree(
IN void* pWhat // ptr allocated with SdbAlloc that should be freed.
)
/*++
Return: The pointer allocated.
Desc: Just a wrapper for deallocation -- perhaps useful if we move this
code to a non-NTDLL location and need to call differently.
--*/
{
HeapFree(GetProcessHeap(), 0, pWhat);
}
HANDLE
SdbpOpenFile(
IN LPCTSTR szPath, // full path of file to open
IN PATH_TYPE eType // must be always DOS_PATH
)
/*++
Return: A handle to the opened file or INVALID_HANDLE_VALUE on failure.
Desc: Just a wrapper for opening an existing file for READ.
--*/
{
HANDLE hFile;
assert(eType == DOS_PATH);
hFile = CreateFile(szPath,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DBGPRINT((sdlInfo, "SdbpOpenFile", "CreateFileW failed 0x%x.\n", GetLastError()));
}
return hFile;
}
void
SdbpQueryAppCompatFlagsForExeID(
IN HKEY hkeyRoot, // the root key (HKLM or HKCU)
IN LPCTSTR pwszExeID, // the exe ID in string format
OUT LPDWORD lpdwFlags // this will contain the flags from the registry.
)
/*++
Return: void.
Desc: BUGBUG
Query registry for compatibility flags. Exe ID is a GUID in string format.
--*/
{
HKEY hkey;
DWORD type, cbSize, dwFlags = 0;
LONG lRes;
*lpdwFlags = 0;
lRes = RegOpenKey(hkeyRoot, APPCOMPAT_KEY_PATH, &hkey);
if (lRes != ERROR_SUCCESS) {
//
// No key for this ExeID. No big deal.
//
return;
}
cbSize = sizeof(DWORD);
lRes = RegQueryValueEx(hkey, pwszExeID, NULL, &type, (LPBYTE)&dwFlags, &cbSize);
if (lRes != ERROR_SUCCESS || type != REG_DWORD) {
goto cleanup;
}
*lpdwFlags = dwFlags;
cleanup:
RegCloseKey(hkey);
}
BOOL
SdbGetEntryFlags(
IN GUID* pGuid, // the EXE's ID
OUT LPDWORD lpdwFlags // will receive the flags for this EXE
)
/*++
Return: void.
Desc: BUGBUG: comment.
--*/
{
TCHAR szExeID[128];
DWORD dwFlagsMachine = 0, dwFlagsUser = 0;
if (!SdbGUIDToString(pGuid, szExeID)) {
DBGPRINT((sdlError, "SdbGetEntryFlags",
"Failed to convert guid to string\n"));
return FALSE;
}
//
// Look in both the local machine and per user keys. Then combine the
// flags.
//
SdbpQueryAppCompatFlagsForExeID(HKEY_LOCAL_MACHINE, szExeID, &dwFlagsMachine);
SdbpQueryAppCompatFlagsForExeID(HKEY_CURRENT_USER, szExeID, &dwFlagsUser);
*lpdwFlags = (dwFlagsMachine | dwFlagsUser);
return TRUE;
}
BOOL
SdbSetEntryFlags(
IN GUID* pGuid, // the EXE's ID
IN DWORD dwFlags // the registry flags for this EXE
)
/*++
Return: void.
Desc: BUGBUG: comment.
--*/
{
TCHAR szExeID[128];
DWORD dwExeFlags;
HKEY hkey;
LONG lRes;
lRes = RegCreateKey(HKEY_CURRENT_USER, APPCOMPAT_KEY_PATH, &hkey);
if (lRes != ERROR_SUCCESS) {
DBGPRINT((sdlError,
"SdbSetEntryFlags",
"Failed 0x%x to open/create key in HKCU\n",
GetLastError()));
return FALSE;
}
if (!SdbGUIDToString(pGuid, szExeID)) {
DBGPRINT((sdlError, "SdbSetEntryFlags",
"Failed to convert GUID to string\n"));
RegCloseKey(hkey);
return FALSE;
}
dwExeFlags = dwFlags;
lRes = RegSetValueEx(hkey,
szExeID,
0,
REG_DWORD,
(const BYTE*)&dwExeFlags,
sizeof(DWORD));
if (lRes != ERROR_SUCCESS) {
DBGPRINT((sdlError,
"SdbSetEntryFlags",
"Failed 0x%x to set the flags for exe ID.\n",
GetLastError()));
return FALSE;
}
return TRUE;
}
VOID
SdbpCleanupUserSDBCache(
IN PSDBCONTEXT pSdbContext
)
{
;
}
BOOL
SDBAPI
SdbGetNthUserSdb(
IN HSDB hSDB,
IN LPCTSTR szItemName, // file name (foo.exe) or layer name
IN BOOL bLayer, // true if layer
IN OUT LPDWORD pdwIndex, // 0-based index
OUT GUID* pGuidDB // guid of a database to search
)
{
TCHAR szFullKey[512];
LONG lResult;
HKEY hKey = NULL;
DWORD dwNameSize = 0;
DWORD dwDataType;
BOOL bRet = FALSE;
TCHAR szSdbName[MAX_PATH];
DWORD dwIndex = *pdwIndex;
LPTSTR pDot;
if (szItemName == NULL || pGuidDB == NULL || pdwIndex == NULL) {
DBGPRINT((sdlError, "SdbGetNthUserSdb",
"NULL parameter passed for szExeName or pGuidDB or pdwIndex.\n"));
goto out;
}
if (bLayer) {
_stprintf(szFullKey, TEXT("%s\\Layers\\%s"), APPCOMPAT_KEY_PATH_CUSTOM, szItemName);
} else {
_stprintf(szFullKey, TEXT("%s\\%s"), APPCOMPAT_KEY_PATH_CUSTOM, szItemName);
}
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szFullKey,
0,
KEY_READ,
&hKey);
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlInfo, "SdbGetNthUserSdb",
"Failed to open Key \"%s\" Error 0x%x\n", szFullKey, lResult));
goto out;
}
//
// enum all the values please
//
while (TRUE) {
dwNameSize = CHARCOUNT(szSdbName);
lResult = RegEnumValue(hKey,
dwIndex,
szSdbName,
&dwNameSize,
NULL,
&dwDataType,
NULL,
NULL);
dwIndex++;
if (lResult != ERROR_SUCCESS) {
goto out;
}
//
// we have sdb name, convert it to guid
//
pDot = _tcsrchr(szSdbName, TEXT('.'));
if (pDot != NULL) {
*pDot = TEXT('\0'); // old style entry
}
if (SdbGUIDFromString(szSdbName, pGuidDB)) {
//
// we are done
//
break;
}
}
//
// advance the counter if success
//
*pdwIndex = dwIndex;
bRet = TRUE;
out:
if (hKey != NULL) {
RegCloseKey(hKey);
}
return bRet;
}
//
// These three functions are not needed for Win9x, and are stubbed out here
//
BOOL
SdbGetPermLayerKeys(
IN LPCTSTR szPath,
OUT LPTSTR szLayers,
IN LPDWORD pdwBytes,
IN DWORD dwFlags
)
{
return FALSE;
}
BOOL
SdbSetPermLayerKeys(
IN LPCTSTR szPath,
IN LPCTSTR szLayers,
IN BOOL bMachine
)
{
return FALSE;
}
BOOL
SdbDeletePermLayerKeys(
IN LPCTSTR szPath,
IN BOOL bMachine
)
{
return FALSE;
}
BOOL
SdbpGetLongFileName(
IN LPCTSTR szFullPath, // a full UNC or DOS path & filename, "c:\foo\mylong~1.ext"
OUT LPTSTR szLongFileName // the long filename portion "mylongfilename.ext"
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: BUGBUG: comment.
--*/
{
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA FindData;
BOOL bReturn = FALSE;
hFind = FindFirstFile(szFullPath, &FindData);
if (hFind == INVALID_HANDLE_VALUE) {
DBGPRINT((sdlError,
"SdbpGetLongFileName",
"FindFirstFile failed, error 0x%x.\n",
GetLastError()));
goto Done;
}
//
// BUGBUG: Hopefuly there is enough space in 'szLongFileName' to not AV :-(
//
_tcscpy(szLongFileName, FindData.cFileName);
bReturn = TRUE;
Done:
if (hFind != INVALID_HANDLE_VALUE) {
FindClose(hFind);
}
return bReturn;
}
void
SdbpGetWinDir(
OUT LPTSTR pszDir // will contain the %windir% path.
)
/*++
Return: void.
Desc: This is a wrapper function to get the windows directory.
--*/
{
UINT cch;
//
// BUGBUG: This will only work properly on non-TS system.
// On TS we need to use GetSystemWindowsDirectory instead.
//
cch = GetWindowsDirectory(pszDir, MAX_PATH);
if (cch == 0) {
*pszDir = 0;
}
}
void
SdbpGetAppPatchDir(
OUT LPTSTR szAppPatchPath // will contain %windir%\AppPatch path
)
/*++
Return: void.
Desc: This is a wrapper function to get the %windir%\AppPatch directory.
--*/
{
UINT cch;
//
// BUGBUG: This will only work properly on non-TS system.
// On TS we need to use GetSystemWindowsDirectory instead.
//
cch = GetWindowsDirectory(szAppPatchPath, MAX_PATH);
//
// Make sure the path doesn't end with '\\'
//
if (cch > 0 && _T('\\') == szAppPatchPath[cch - 1]) {
szAppPatchPath[cch - 1] = _T('\0');
}
_tcscat(szAppPatchPath, _T("\\AppPatch"));
}
void
SdbpGetCurrentTime(
OUT LPSYSTEMTIME lpTime // will contain the local time
)
/*++
Return: void.
Desc: This is a wrapper function to get the local time.
--*/
{
GetLocalTime(lpTime);
}
NTSTATUS
SdbpGetEnvVar(
IN LPCTSTR pEnvironment,
IN LPCTSTR pszVariableName,
OUT LPTSTR pszVariableValue,
OUT LPDWORD pdwBufferSize
)
/*++
Return: BUGBUG: ?
Desc: Retrieves the value of the specified environment variable.
--*/
{
DWORD dwLength;
DWORD dwBufferSize = 0;
NTSTATUS Status;
LPTSTR pszBuffer = NULL;
assert(pEnvironment == NULL);
if (pdwBufferSize && pszVariableValue) {
dwBufferSize = *pdwBufferSize;
}
dwLength = GetEnvironmentVariable(pszVariableName, (LPTSTR)pszVariableValue, dwBufferSize);
if (dwLength == 0) {
//
// The variable was not found. Just return.
//
return STATUS_VARIABLE_NOT_FOUND;
}
if (dwLength >= dwBufferSize) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = STATUS_SUCCESS;
}
if (pdwBufferSize != NULL) {
*pdwBufferSize = dwLength;
}
return Status;
}
LPSTR
SdbpFastUnicodeToAnsi(
IN PDB pdb, // pointer to the database
IN LPCWSTR pwszSrc, // String to convert
IN TAG_TYPE ttTag, // tag type from which pwszSrc was obtained,
// either STRINGREF or STRING
IN DWORD dwRef // tagid or string's stringref
)
/*++
Return: The pointer to the ANSI string in the hash table.
Desc: This function converts a UNICODE string to ANSI and stores it in a hash
table. It then returns the pointer to the ANSI string in the hash table.
Subsequent calls trying to convert a string that has been previously
converted will be very fast.
--*/
{
LPSTR pszDest = NULL;
PSTRHASH pHash = NULL;
INT nSize;
LPSTR pszBuffer = NULL;
//
// See if this string comes from the stringtable or it is in-place.
//
switch (ttTag) {
case TAG_TYPE_STRING:
if (pdb->pHashStringBody == NULL) {
pdb->pHashStringBody = HashCreate();
}
pHash = pdb->pHashStringBody;
break;
case TAG_TYPE_STRINGREF:
if (pdb->pHashStringTable == NULL) {
pdb->pHashStringTable = HashCreate();
}
pHash = pdb->pHashStringTable;
break;
default:
DBGPRINT((sdlError,
"SdbpFastUnicodeToAnsi",
"ttTag 0x%x should be STRING or STRINGREF\n",
ttTag));
assert(FALSE);
break;
}
if (pHash == NULL) {
DBGPRINT((sdlError,
"SdbpFastUnicodeToAnsi",
"Pointer to hash is invalid, tag type 0x%x\n",
ttTag));
return NULL;
}
pszDest = HashFindStringByRef(pHash, dwRef);
if (pszDest == NULL) {
//
// Convert the string to ANSI. Do it in 2 steps to find
// the required size first.
//
nSize = WideCharToMultiByte(CP_OEMCP,
0,
pwszSrc,
-1,
NULL,
0,
NULL,
NULL);
if (nSize == 0) {
DBGPRINT((sdlError,
"SdbpFastUnicodeToAnsi",
"WideCharToMultiByte failed 0x%x.\n",
GetLastError()));
goto Done;
}
STACK_ALLOC(pszBuffer, nSize); // size is in BYTES
if (pszBuffer == NULL) {
DBGPRINT((sdlError,
"SdbpFastUnicodeToAnsi",
"Failed to allocate 0x%x bytes on the stack.\n",
nSize));
goto Done;
}
nSize = WideCharToMultiByte(CP_OEMCP,
0,
pwszSrc,
-1,
pszBuffer,
nSize,
NULL,
NULL);
if (nSize == 0) {
DBGPRINT((sdlError,
"UnicodeStringToString",
"WideCharToMultiByte failed with buffer Error = 0x%lx\n",
GetLastError()));
goto Done;
}
//
// Now we are ready to store the string in the hash table.
//
pszDest = HashAddStringByRef(pHash, pszBuffer, dwRef);
}
Done:
if (pszBuffer != NULL) {
STACK_FREE(pszBuffer);
}
return pszDest;
}
BOOL
SdbpMapFile(
IN HANDLE hFile, // handle to the open file (this is done previously)
OUT PIMAGEFILEDATA pImageData // stores the mapping info
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: This function maps the view of a file in memory so that access operations
on that file are faster.
--*/
{
NTSTATUS Status;
HANDLE hSection = NULL;
SIZE_T ViewSize = 0;
PVOID pBase = NULL;
LARGE_INTEGER liFileSize;
BOOL bSuccess = FALSE;
MEMORY_BASIC_INFORMATION MemoryInfo;
if (hFile == INVALID_HANDLE_VALUE) {
DBGPRINT((sdlError,
"SdbpMapFile",
"Invalid parameter.\n"));
return FALSE;
}
liFileSize.LowPart = GetFileSize(hFile, &liFileSize.HighPart);
if (liFileSize.LowPart == (DWORD)-1) {
DWORD dwError = GetLastError();
if (dwError != NO_ERROR) {
DBGPRINT((sdlError, "SdbpMapFile", "GetFileSize failed with 0x%x.\n", dwError));
return FALSE;
}
}
hSection = CreateFileMapping(hFile,
NULL, // no inheritance
PAGE_READONLY | SEC_COMMIT,
0,
0,
NULL);
if (hSection == NULL) {
DBGPRINT((sdlError,
"SdbpMapFile",
"CreateFileMapping failed with 0x%x.\n",
GetLastError()));
return FALSE;
}
//
// Now map the view.
//
pBase = MapViewOfFile(hSection,
FILE_MAP_READ,
0,
0,
0);
if (pBase == NULL) {
CloseHandle(hSection);
DBGPRINT((sdlError,
"SdbpMapFile",
"MapViewOfFile failed with 0x%x.\n",
GetLastError()));
return FALSE;
}
//
// Why do you need both FileSize and ViewSize ?
// Both FileSize and ViewSize are used in various places
// need to re-examine why and how they're used - BUGBUG
//
VirtualQuery(pBase, &MemoryInfo, sizeof(MemoryInfo));
pImageData->hFile = hFile;
pImageData->hSection = hSection;
pImageData->pBase = pBase;
pImageData->ViewSize = MemoryInfo.RegionSize;
pImageData->FileSize = liFileSize.QuadPart;
return TRUE;
}
BOOL
SdbpUnmapFile(
IN PIMAGEFILEDATA pImageData // mapping info
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: This function unmaps the view of a file.
--*/
{
if (pImageData->pBase) {
UnmapViewOfFile(pImageData->pBase);
pImageData->pBase = NULL;
}
if (pImageData->hSection) {
CloseHandle(pImageData->hSection);
pImageData->hSection = NULL;
}
pImageData->hFile = INVALID_HANDLE_VALUE;
return TRUE;
}
LPTSTR
SdbpDuplicateString(
IN LPCTSTR pszSrc // pointer to the string to be duplicated
)
/*++
Return: A pointer to the allocated duplicated string.
Desc: Duplicates a string by allocating a copy from the heap.
--*/
{
LPTSTR pszDest = NULL;
int nSize;
assert(pszSrc != NULL);
nSize = (_tcslen(pszSrc) + 1) * sizeof(TCHAR);
pszDest = (LPTSTR)SdbAlloc(nSize);
if (pszDest == NULL) {
DBGPRINT((sdlError,
"SdbpDuplicateString",
"Failed to allocate %d bytes.\n",
nSize));
return NULL;
}
RtlMoveMemory(pszDest, pszSrc, nSize);
return pszDest;
}
BOOL
SdbpReadStringToAnsi(
IN PDB pdb,
IN TAGID tiWhich,
OUT LPSTR pszBuffer,
IN DWORD dwBufferSize
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Reads a string from the database and converts it to ANSI.
--*/
{
WCHAR* pData;
INT nch;
pData = (WCHAR*)SdbpGetMappedTagData(pdb, tiWhich);
if (pData == NULL) {
DBGPRINT((sdlError,
"SdbpReadStringToAnsi",
"SdbpGetMappedTagData failed for TAGID 0x%x.\n",
tiWhich));
return FALSE;
}
nch = WideCharToMultiByte(CP_OEMCP,
0,
pData,
-1,
pszBuffer,
dwBufferSize * sizeof(TCHAR),
NULL,
NULL);
if (nch == 0) {
DBGPRINT((sdlError,
"SdbpReadStringToAnsi",
"WideCharToMultiByte failed with 0x%x.\n",
GetLastError()));
return FALSE;
}
return TRUE;
}
DWORD
SdbpGetFileSize(
IN HANDLE hFile // handle to the file to check the size of
)
/*++
Return: The size of the file or 0 on failure.
Desc: Gets the lower DWORD of the size of a file -- only
works accurately with files smaller than 2GB.
In general, since we're only interested in matching, we're
fine just matching the least significant DWORD of the file size.
--*/
{
return GetFileSize(hFile, NULL);
}
BOOL
SdbpQueryFileDirectoryAttributes(
IN LPCTSTR FilePath,
OUT PFILEDIRECTORYATTRIBUTES pFileDirectoryAttributes
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: BUGBUG: ?
--*/
{
WIN32_FIND_DATA FindData;
HANDLE hFind;
int i;
ZeroMemory(pFileDirectoryAttributes, sizeof(*pFileDirectoryAttributes));
hFind = FindFirstFile(FilePath, &FindData);
if (hFind == INVALID_HANDLE_VALUE) {
DBGPRINT((sdlError,
"SdbpQueryFileDirectoryAttributes",
"FindFirstFile failed with 0x%x.\n",
GetLastError()));
return FALSE;
}
//
// Make sure we are not checking vlfs.
//
if (FindData.nFileSizeHigh != 0) {
DBGPRINT((sdlError,
"SdbpQueryFileDirectoryAttributes",
"Checking vlf files (0x%x 0x%x) is not supported\n",
FindData.nFileSizeHigh,
FindData.nFileSizeLow));
return FALSE;
}
pFileDirectoryAttributes->dwFlags |= FDA_FILESIZE;
pFileDirectoryAttributes->dwFileSizeHigh = FindData.nFileSizeHigh;
pFileDirectoryAttributes->dwFileSizeLow = FindData.nFileSizeLow;
FindClose(hFind);
return TRUE;
}
BOOL
SdbpDoesFileExists(
IN LPCTSTR pszFilePath // the full path of the file
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Checks if the specified file exists.
--*/
{
DWORD dwAttributes;
dwAttributes = GetFileAttributes(pszFilePath);
return (dwAttributes != (DWORD)-1);
}
BOOL
SdbpGet16BitDescription(
OUT LPTSTR* ppszDescription,
IN PIMAGEFILEDATA pImageData
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: BUGBUG: ?
--*/
{
BOOL bSuccess;
CHAR szBuffer[256];
LPTSTR pszDescription = NULL;
bSuccess = SdbpQuery16BitDescription(szBuffer, pImageData);
if (bSuccess) {
pszDescription = SdbpDuplicateString(szBuffer);
*ppszDescription = pszDescription;
}
return (pszDescription != NULL);
}
BOOL
SdbpGet16BitModuleName(
OUT LPTSTR* ppszModuleName,
IN PIMAGEFILEDATA pImageData
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: BUGBUG: ?
--*/
{
BOOL bSuccess;
CHAR szBuffer[256];
LPTSTR pszModuleName = NULL;
bSuccess = SdbpQuery16BitModuleName(szBuffer, pImageData);
if (bSuccess) {
pszModuleName = SdbpDuplicateString(szBuffer);
*ppszModuleName = pszModuleName;
}
return (pszModuleName != NULL);
}
PVOID
SdbGetFileInfo(
IN HSDB hSDB,
IN LPCTSTR pszFilePath,
IN HANDLE hFile OPTIONAL,
IN LPVOID pImageBase OPTIONAL,
IN DWORD dwImageSize OPTIONAL,
IN BOOL bNoCache
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
LPTSTR FullPath;
NTSTATUS Status;
PFILEINFO pFileInfo = NULL;
DWORD nBufferLength;
DWORD cch;
UNICODE_STRING FullPathU;
//
// See if we have info on this file. Get the full path first.
//
cch = GetFullPathName(pszFilePath, 0, NULL, NULL);
if (cch == 0) {
DBGPRINT((sdlError,
"GetFileInfo",
"GetFullPathName failed for \"%s\" with 0x%x.\n",
pszFilePath,
GetLastError()));
return NULL;
}
nBufferLength = (cch + 1) * sizeof(TCHAR);
STACK_ALLOC(FullPath, nBufferLength);
if (FullPath == NULL) {
DBGPRINT((sdlError,
"GetFileInfo",
"Failed to allocate %d bytes on the stack for full path.\n",
nBufferLength));
return NULL;
}
cch = GetFullPathName(pszFilePath,
nBufferLength,
FullPath,
NULL);
assert(cch <= nBufferLength);
if (cch > nBufferLength || cch == 0) {
DBGPRINT((sdlError,
"GetFileInfo",
"GetFullPathName failed for \"%s\" with 0x%x.\n",
pszFilePath,
GetLastError()));
STACK_FREE(FullPath);
return NULL;
}
if (!bNoCache) {
pFileInfo = FindFileInfo(pContext, FullPath);
}
if (pFileInfo == NULL) {
if (SdbpDoesFileExists(FullPath)) {
pFileInfo = CreateFileInfo(pContext,
FullPath,
cch,
hFile,
pImageBase,
dwImageSize,
bNoCache);
}
}
STACK_FREE(FullPath);
return (PVOID)pFileInfo;
}
int
GetShimDbgLevel(
void
)
{
TCHAR szDebugLevel[128];
DWORD cch;
INT iShimDebugLevel = 0;
cch = GetEnvironmentVariable(TEXT("SHIM_DEBUG_LEVEL"),
szDebugLevel,
CHARCOUNT(szDebugLevel));
if (cch != 0) {
iShimDebugLevel = (int)_tcstol(szDebugLevel, NULL, 0);
}
return iShimDebugLevel;
}
BOOL
SdbpWriteBitsToFile(
LPCTSTR pszFile,
PBYTE pBuffer,
DWORD dwSize
)
/*++
Return: TRUE on success, FALSE otherwise.
Desc: Self explanatory.
--*/
{
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL bReturn = FALSE;
DWORD dwBytesWritten;
hFile = CreateFile(pszFile,
GENERIC_READ | GENERIC_WRITE,
0, // no sharing
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DBGPRINT((sdlError, "SdbpWriteBitsToFile",
"Failed to create file \"%s\" Error 0x%lx.\n", pszFile, GetLastError()));
goto cleanup;
}
if (!WriteFile(hFile, pBuffer, dwSize, &dwBytesWritten, NULL)) {
DBGPRINT((sdlError, "SdbpWriteBitsToFile",
"Failed to write bits to file \"%s\" Error 0x%lx\n", pszFile, GetLastError()));
goto cleanup;
}
bReturn = TRUE;
cleanup:
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
return bReturn;
}
/***
* void _resetstkoflw(void) - Recovers from Stack Overflow
*
* Purpose:
* Sets the guard page to its position before the stack overflow.
*
*******************************************************************************/
VOID
SdbResetStackOverflow(
VOID
)
{
LPBYTE pStack, pGuard, pStackBase, pCommitBase;
MEMORY_BASIC_INFORMATION mbi;
SYSTEM_INFO si;
DWORD PageSize;
// Use alloca() to get the current stack pointer
pStack = _alloca(1);
// Find the base of the stack.
VirtualQuery(pStack, &mbi, sizeof mbi);
pStackBase = mbi.AllocationBase;
VirtualQuery(pStackBase, &mbi, sizeof mbi);
if (mbi.State & MEM_RESERVE) {
pCommitBase = (LPBYTE)mbi.AllocationBase + mbi.RegionSize;
VirtualQuery(pCommitBase, &mbi, sizeof mbi);
} else {
pCommitBase = pStackBase;
}
//
// Find the page just below where stack pointer currently points.
//
GetSystemInfo(&si);
PageSize = si.dwPageSize;
pGuard = (LPBYTE) (((DWORD_PTR)pStack & ~(DWORD_PTR)(PageSize -1)) - PageSize);
if ( pGuard < pStackBase) {
//
// We can't save this
//
return;
}
if (pGuard > pStackBase) {
VirtualFree(pStackBase, pGuard -pStackBase, MEM_DECOMMIT);
}
VirtualAlloc(pGuard, PageSize, MEM_COMMIT, PAGE_READWRITE);
VirtualProtect(pGuard, PageSize, PAGE_READWRITE | PAGE_GUARD, &PageSize);
}
DWORD
SdbExpandEnvironmentStrings(
IN LPCTSTR lpSrc,
OUT LPTSTR lpDst,
IN DWORD nSize)
{
return ExpandEnvironmentStrings(lpSrc, lpDst, nSize);
}
TCHAR g_szDatabasePath[] = TEXT("DatabasePath");
TCHAR g_szDatabaseType[] = TEXT("DatabaseType");
TCHAR g_szDatabaseDescription[] = TEXT("DatabaseDescription");
BOOL
SDBAPI
SdbGetDatabaseRegPath(
IN GUID* pguidDB,
OUT LPTSTR pszDatabasePath,
IN DWORD dwBufferSize // size (in tchars) of the buffer
)
{
TCHAR szDatabaseID[64];
INT nch;
SdbGUIDToString(pguidDB, szDatabaseID);
nch = _sntprintf(pszDatabasePath,
(size_t)dwBufferSize,
TEXT("%s\\%s"),
APPCOMPAT_KEY_PATH_INSTALLEDSDB,
szDatabaseID);
return (nch > 0);
}
BOOL
SDBAPI
SdbUnregisterDatabase(
IN GUID* pguidDB
)
/*++
Unregisters a database so it's no longer available.
--*/
{
TCHAR szFullKey[512];
//
// Form the key
//
if (!SdbGetDatabaseRegPath(pguidDB, szFullKey, CHARCOUNT(szFullKey))) {
DBGPRINT((sdlError, "SdbUnregisterDatabase", "Failed to get database key path\n"));
return FALSE;
}
return (SHDeleteKey(HKEY_LOCAL_MACHINE, szFullKey) == ERROR_SUCCESS);
}
BOOL
SDBAPI
SdbRegisterDatabase(
IN LPCTSTR pszDatabasePath,
IN DWORD dwDatabaseType
)
/*++
Registers any given database so that it is "known" to our database lookup apis
Caller must ensure that appcompatflags registry entry exists
If the function fails -- the caller should try to cleanup the mess using SdbUnregisterDatabase
--*/
{
// first we write the database path
PSDBDATABASEINFO pDbInfo = NULL;
BOOL bReturn = FALSE;
DWORD dwPathLength;
DWORD dwLength;
LPTSTR pszFullPath = NULL;
TCHAR szDatabaseID[64]; // sufficient for guid
LONG lResult;
TCHAR szFullKey[512];
HKEY hKeyInstalledSDB = NULL;
HKEY hKey = NULL;
BOOL bExpandSZ = FALSE;
BOOL bFreeFullPath = FALSE;
//
// see if we need to expand some strings...
//
if (_tcschr(pszDatabasePath, TEXT('%')) != NULL) {
bExpandSZ = TRUE;
dwPathLength = ExpandEnvironmentStrings(pszDatabasePath, NULL, 0);
if (dwPathLength == 0) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to expand environment strings for \"%s\" Error 0x%lx\n",
pszDatabasePath, GetLastError()));
return FALSE;
}
pszFullPath = SdbAlloc(dwPathLength * sizeof(WCHAR));
if (pszFullPath == NULL) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to allocate 0x%lx bytes for the path buffer \"%s\"\n",
dwPathLength, pszDatabasePath));
return FALSE;
}
bFreeFullPath = TRUE;
dwLength = ExpandEnvironmentStrings(pszDatabasePath, pszFullPath, dwPathLength);
if (dwLength == 0 || dwLength > dwPathLength) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to expand environment strings for \"%s\" Length 0x%lx Return value 0x%lx Error 0x%lx\n",
pszDatabasePath, dwPathLength, dwLength, GetLastError()));
goto HandleError;
}
} else { // this path does not need expansion
pszFullPath = (LPTSTR)pszDatabasePath;
}
if (!SdbGetDatabaseInformationByName(pszFullPath, &pDbInfo)) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Cannot obtain database information for \"%s\"\n", pszFullPath));
goto HandleError;
}
if (!(pDbInfo->dwFlags & DBINFO_GUID_VALID)) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Cannot register database with no id \"%s\"\n", pszDatabasePath));
goto HandleError;
}
//
// convert the guid into the string, returns true always
//
SdbGUIDToString(&pDbInfo->guidDB, szDatabaseID);
//
// now that we have database information - create entry
//
lResult = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
APPCOMPAT_KEY_PATH_INSTALLEDSDB,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE|KEY_READ,
NULL,
&hKeyInstalledSDB,
NULL);
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to create key \"%s\" error 0x%lx\n", APPCOMPAT_KEY_PATH_INSTALLEDSDB, lResult));
goto HandleError;
}
assert(hKeyInstalledSDB != NULL);
//
// now create the key for the existing database
//
lResult = RegCreateKeyEx(hKeyInstalledSDB, // subkey
szDatabaseID,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE|KEY_READ,
NULL,
&hKey,
NULL);
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to create key \"%s\" error 0x%lx\n", szDatabaseID, lResult));
goto HandleError;
}
assert(hKey != NULL);
//
// set values for this database
//
lResult = RegSetValueEx(hKey,
g_szDatabasePath,
0,
bExpandSZ ? REG_EXPAND_SZ : REG_SZ,
(PBYTE)pszFullPath,
(_tcslen(pszFullPath) + 1) * sizeof(*pszFullPath));
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to set value \"%s\" to \"%s\" Error 0x%lx\n",
g_szDatabasePath, pszFullPath, lResult));
goto HandleError;
}
lResult = RegSetValueEx(hKey,
g_szDatabaseType,
0,
REG_DWORD,
(PBYTE)&dwDatabaseType,
sizeof(dwDatabaseType));
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to set value \"%s\" to 0x%lx Error 0x%lx\n",
g_szDatabaseType, dwDatabaseType, lResult));
goto HandleError;
}
if (pDbInfo->pszDescription != NULL) {
lResult = RegSetValueEx(hKey,
g_szDatabaseDescription,
0,
REG_SZ,
(PBYTE)pDbInfo->pszDescription,
(_tcslen(pDbInfo->pszDescription) + 1) * sizeof(*pDbInfo->pszDescription));
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbRegisterDatabase",
"Failed to set value \"%s\" to 0x%lx Error 0x%lx\n",
g_szDatabaseDescription, pDbInfo->pszDescription, lResult));
goto HandleError;
}
}
bReturn = TRUE;
HandleError:
if (hKeyInstalledSDB != NULL) {
RegCloseKey(hKeyInstalledSDB);
}
if (hKey != NULL) {
RegCloseKey(hKey);
}
if (pDbInfo != NULL) {
SdbFreeDatabaseInformation(pDbInfo);
}
if (bFreeFullPath && pszFullPath != NULL) {
SdbFree(pszFullPath);
}
return bReturn;
}
DWORD
SDBAPI
SdbResolveDatabase(
IN GUID* pguidDB, // pointer to the database guid to resolve
OUT LPDWORD lpdwDatabaseType, // optional pointer to the database type
OUT LPTSTR pszDatabasePath, // optional pointer to the database path
IN DWORD dwBufferSize // size of the buffer pszDatabasePath in tchars
)
{
TCHAR szDatabaseID[64];
TCHAR szDatabasePath[MAX_PATH];
TCHAR szFullKey[512];
LONG lResult;
HKEY hKey = NULL;
DWORD dwDataType;
DWORD dwDataSize;
DWORD dwLength = 0;
//
// convert guid to string
//
if (!SdbGetDatabaseRegPath(pguidDB, szFullKey, CHARCOUNT(szFullKey))) {
DBGPRINT((sdlError, "SdbResolveDatabase", "Failed to retrieve database key path\n"));
goto HandleError;
}
//
// open the key
//
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
szFullKey,
0,
KEY_READ,
&hKey);
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbResolveDatabase",
"Failed to open key \"%s\" Error 0x%lx\n", szFullKey, lResult));
goto HandleError; // 0 means error
}
dwDataSize = sizeof(szDatabasePath);
lResult = RegQueryValueEx(hKey,
g_szDatabasePath,
NULL,
&dwDataType,
(LPBYTE)szDatabasePath,
&dwDataSize);
if (lResult != ERROR_SUCCESS) {
DBGPRINT((sdlError, "SdbResolveDatabase",
"Failed to query value \"%s\" Error 0x%lx\n", g_szDatabasePath, lResult));
goto HandleError; // 0 means error
}
switch(dwDataType) {
case REG_SZ:
// see if we have enough room to copy the string
//
if (dwBufferSize * sizeof(TCHAR) < dwDataSize) {
DBGPRINT((sdlWarning, "SdbResolveDatabase",
"Insufficient buffer for the database path Required 0x%lx Have 0x%lx\n",
dwDataSize, dwBufferSize * sizeof(TCHAR)));
goto HandleError;
}
RtlMoveMemory(pszDatabasePath, szDatabasePath, dwDataSize);
dwLength = dwDataSize / sizeof(TCHAR);
break;
case REG_EXPAND_SZ:
// we have to expand the strings
dwLength = ExpandEnvironmentStrings(szDatabasePath, pszDatabasePath, dwBufferSize);
if (dwLength == 0 || dwLength > dwBufferSize) {
DBGPRINT((sdlWarning, "SdbResolveDatabase",
"Failed to expand output path\n"));
dwLength = 0;
goto HandleError;
}
break;
default:
// can't do it -- fail
DBGPRINT((sdlError, "SdbResolveDatabase", "Wrong key type 0x%lx\n", dwDataType));
goto HandleError;
break;
}
if (lpdwDatabaseType != NULL) {
dwDataSize = sizeof(*lpdwDatabaseType);
lResult = RegQueryValueEx(hKey,
g_szDatabaseType,
NULL,
&dwDataType,
(LPBYTE)lpdwDatabaseType,
&dwDataSize);
if (lResult == ERROR_SUCCESS) {
if (dwDataType != REG_DWORD) {
// bummer, get out -- wrong type
DBGPRINT((sdlError, "SdbResolveDatabase",
"Wrong database type - value type 0x%lx\n", dwDataType));
dwLength = 0;
goto HandleError;
}
} else {
*lpdwDatabaseType = 0;
}
}
HandleError:
if (hKey != NULL) {
RegCloseKey(hKey);
}
return dwLength;
}
DWORD
SdbpGetProcessorArchitecture(
VOID
)
{
SYSTEM_INFO SysInfo;
SysInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
GetSystemInfo(&SysInfo);
return (DWORD)SysInfo.wProcessorArchitecture;
}
BOOL
SdbpIsOs(
DWORD dwOSSKU
)
{
HKEY hkey;
DWORD type, cbSize, dwInstalled = 0;
LONG lRes;
LPTSTR pszKeyPath;
BOOL bRet = FALSE;
if (dwOSSKU == OS_SKU_TAB) {
pszKeyPath = TABLETPC_KEY_PATH;
} else if (dwOSSKU == OS_SKU_MED) {
pszKeyPath = EHOME_KEY_PATH;
} else {
DBGPRINT((sdlWarning,
"SdbpIsOs",
"Specified unknown OS type 0x%lx",
dwOSSKU));
return FALSE;
}
lRes = RegOpenKey(HKEY_LOCAL_MACHINE, pszKeyPath, &hkey);
if (lRes != ERROR_SUCCESS) {
goto cleanup;
}
cbSize = sizeof(DWORD);
lRes = RegQueryValueEx(hkey, IS_OS_INSTALL_VALUE, NULL, &type, (LPBYTE)&dwInstalled, &cbSize);
if (lRes != ERROR_SUCCESS || type != REG_DWORD) {
goto cleanup;
}
if (dwInstalled) {
bRet = TRUE;
}
DBGPRINT((sdlInfo|sdlLogPipe,
"SdbpIsOs",
"%s %s installed",
0,
(dwOSSKU == OS_SKU_TAB ? TEXT("TabletPC") : TEXT("eHome")),
(bRet ? TEXT("is") : TEXT("is not"))));
cleanup:
RegCloseKey(hkey);
return bRet;
}
VOID
SdbpGetOSSKU(
LPDWORD lpdwSKU,
LPDWORD lpdwSP
)
{
OSVERSIONINFOEXA osv;
WORD wSuiteMask;
ZeroMemory(&osv, sizeof(OSVERSIONINFOEXA));
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXA);
GetVersionExA((LPOSVERSIONINFOA)&osv);
*lpdwSP = 1 << osv.wServicePackMajor;
wSuiteMask = osv.wSuiteMask;
if (osv.wProductType == VER_NT_WORKSTATION) {
if (wSuiteMask & VER_SUITE_PERSONAL) {
*lpdwSKU = OS_SKU_PER;
} else {
#if (_WIN32_WINNT >= 0x0501)
if (SdbpIsOs(OS_SKU_TAB)) {
*lpdwSKU = OS_SKU_TAB;
} else if (SdbpIsOs(OS_SKU_MED)) {
*lpdwSKU = OS_SKU_MED;
} else {
*lpdwSKU = OS_SKU_PRO;
}
#else
*lpdwSKU = OS_SKU_PRO;
#endif
}
return;
}
if (wSuiteMask & VER_SUITE_DATACENTER) {
*lpdwSKU = OS_SKU_DTC;
return;
}
if (wSuiteMask & VER_SUITE_ENTERPRISE) {
*lpdwSKU = OS_SKU_ADS;
return;
}
if (wSuiteMask & VER_SUITE_BLADE) {
*lpdwSKU = OS_SKU_BLA;
return;
}
*lpdwSKU = OS_SKU_SRV;
}