1683 lines
41 KiB
C
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;
|
||
|
}
|
||
|
|