Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

784 lines
18 KiB

//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: RegUtil.CPP
// Author: Charles Ma, 10/20/2000
//
// Revision History:
//
//
//
//
// Description:
//
// Implement IU registry accessing utility library
//
//=======================================================================
#include <windows.h>
#include <tchar.h>
#include <logging.h>
#include <memutil.h>
#include <fileutil.h>
#include <stringutil.h>
#include <shlwapi.h>
#include "wusafefn.h"
#include <regutil.h>
#include<iucommon.h>
#include <MISTSAFE.h>
const int REG_BUF_SIZE = 1024;
const LPCTSTR REG_ROOTKEY_STR[7] = {
_T("HKEY_LOCAL_MACHINE"),
_T("HKEY_CLASSES_ROOT"),
_T("HKEY_CURRENT_USER"),
_T("HKEY_CURRENT_CONFIG"),
_T("HKEY_USERS"),
_T("HKEY_PERFORMANCE_DATA"), // NT only
_T("HKEY_DYN_DATA") // W9x only
};
const HKEY REG_ROOTKEY[7] = {
HKEY_LOCAL_MACHINE,
HKEY_CLASSES_ROOT,
HKEY_CURRENT_USER,
HKEY_CURRENT_CONFIG,
HKEY_USERS,
HKEY_PERFORMANCE_DATA,
HKEY_DYN_DATA
};
typedef BOOL (WINAPI * PFN_StrToInt64Ex)(LPCTSTR pszString,
DWORD dwFlags,
LONGLONG * pllRet);
// ----------------------------------------------------------------------
//
// private function to split a full reg path into
// two parts: root key and subkey
//
// ----------------------------------------------------------------------
LPCTSTR SplitRegPath(LPCTSTR lpsRegPath, HKEY* phRootKey)
{
LPTSTR lpSubKey = NULL;
for (int i = 0; i < sizeof(REG_ROOTKEY)/sizeof(HKEY); i++)
{
if ((lpSubKey = StrStrI(lpsRegPath, REG_ROOTKEY_STR[i])) == lpsRegPath)
{
*phRootKey = REG_ROOTKEY[i];
lpSubKey += lstrlen(REG_ROOTKEY_STR[i]);
lpSubKey = CharNext(lpSubKey); // skip past "\", if any (or remain on NULL)
return lpSubKey;
}
}
//
// if come to here, must be no right root key
//
*phRootKey = 0;
return lpsRegPath;
}
// ----------------------------------------------------------------------
//
// public function to tell if a reg key exists
//
// ----------------------------------------------------------------------
BOOL RegKeyExists(
LPCTSTR lpsKeyPath, // key path
LPCTSTR lpsValName // optional value name
)
{
LOG_Block("RegKeyExists()");
HKEY hRootKey = 0, hKey = 0;
LPCTSTR lpsSubKey = NULL;
BOOL rc = FALSE;
DWORD dwType = 0x0;
if (NULL == lpsKeyPath)
{
LOG_ErrorMsg(E_INVALIDARG);
return FALSE;
}
LOG_Out(_T("Parameters: (%s, %s)"), lpsKeyPath, lpsValName);
lpsSubKey = SplitRegPath(lpsKeyPath, &hRootKey);
if (hRootKey && ERROR_SUCCESS == RegOpenKeyEx(hRootKey, lpsSubKey, 0, KEY_QUERY_VALUE, &hKey))
{
rc = (NULL == lpsValName) ||
(ERROR_SUCCESS == RegQueryValueEx(hKey, lpsValName, NULL, &dwType, NULL, NULL));
}
if (hKey)
{
RegCloseKey(hKey);
}
LOG_Out(_T("Result: %s"), rc ? _T("TRUE") : _T("FALSE"));
return rc;
}
// ----------------------------------------------------------------------
//
// public function to tell is a reg value in reg matches given value
//
// ----------------------------------------------------------------------
BOOL RegKeyValueMatch(
LPCTSTR lpsKeyPath, // key path
LPCTSTR lpsValName, // optional value name
LPCTSTR lpsValue // value value
)
{
LOG_Block("RegKeyValueMatch()");
HKEY hRootKey = 0, hKey = 0;
LPCTSTR lpsSubKey = NULL;
BOOL rc = FALSE;
BYTE btBuffer[REG_BUF_SIZE];
LPBYTE pBuffer = btBuffer;
LPCTSTR lpCurStr;
DWORD dwType = 0x0;
DWORD dwSize = sizeof(btBuffer);
DWORD dwCode = 0x0;
HRESULT hr=S_OK;
USES_MY_MEMORY;
if (NULL == lpsKeyPath || NULL == lpsValue)
{
LOG_ErrorMsg(E_INVALIDARG);
goto CleanUp;
}
LOG_Out(_T("Parameters: (%s, %s, %s)"), lpsKeyPath, lpsValName, lpsValue);
lpsSubKey = SplitRegPath(lpsKeyPath, &hRootKey);
if (0 == hRootKey || (ERROR_SUCCESS != RegOpenKeyEx(hRootKey, lpsSubKey, 0, KEY_QUERY_VALUE, &hKey)))
{
goto CleanUp;
}
//
// try to query the value with existing buffer.
//
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, btBuffer, &dwSize);
if (ERROR_MORE_DATA == dwCode)
{
//
// if found the existing buffer not large enough,
// then allocate memory large enough to store the data now
//
if (NULL == (pBuffer = (LPBYTE) MemAlloc(dwSize)))
{
goto CleanUp;
}
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, pBuffer, &dwSize);
}
if (ERROR_SUCCESS != dwCode)
{
goto CleanUp;
}
//
// since the value to compare was read from XML doc, obviously only
// the following 4 types possible to compare with
//
switch (dwType)
{
case REG_DWORD:
{
int x, y = *((int *) pBuffer);
DWORD dwFlag = STIF_DEFAULT;
//
// check if the value from manifest is a hex value:
// starts with x, or starts with 0x
//
LPCTSTR lpSecondChar = lpsValue + 1;
if (_T('0') == *lpsValue && (_T('x') == *lpSecondChar || _T('X') == *lpSecondChar))
{
dwFlag = STIF_SUPPORT_HEX;
}
if (StrToIntEx(lpsValue, dwFlag, &x))
{
rc = ( x == y);
}
}
break;
case REG_SZ:
case REG_EXPAND_SZ: // for mult-string, we only compair its first substring
rc = (lstrcmpi((LPCTSTR)lpsValue, (LPCTSTR) pBuffer) == 0);
if (!rc)
{
//
// if the ressult is not equal, it's possibly caused by
// path variables
//
// ASSUMPTION: these reg strings are for file path only, so we only
// handle cases not longer than MAX_PATH.
//
TCHAR szRegStr[MAX_PATH], szValStr[MAX_PATH];
if (dwSize >= MAX_PATH || lstrlen(lpsValue) >= MAX_PATH)
{
break;
}
if (SUCCEEDED(ExpandFilePath(lpsValue, szValStr, sizeof(szValStr)/sizeof(szValStr[0]))))
{
//
// if we can expand the given sub-string,
// then try to expand the reg string if QueryRegValue says
// this string is expandable. Otherwise, use the
// string retrieved only.
//
if (REG_EXPAND_SZ == dwType)
{
ExpandFilePath((LPCTSTR)pBuffer, szRegStr, sizeof(szRegStr)/sizeof(szRegStr[0]));
}
else
{
hr=StringCchCopyEx(szRegStr,ARRAYSIZE(szRegStr),(LPTSTR) pBuffer,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr)) break;
}
//
// compare in expanded mode
//
rc = (lstrcmpi((LPCTSTR)szRegStr, szValStr) == 0);
}
}
break;
case REG_MULTI_SZ:
{
TCHAR szRegStr[MAX_PATH], szValStr[MAX_PATH];
szValStr[0] = '\0';
lpCurStr = (LPCTSTR)pBuffer;
//
// try to match each SZ in this multi sz.
//
do
{
//
// see if the value contains the substring passed in
//
rc = (lstrcmpi((LPCTSTR)lpsValue, (LPCTSTR)pBuffer) == 0);
//
// if not found, it's possibly caused by
// path variable or environment variable embedded
//
if (!rc && _T('\0') == szValStr[0])
{
if (FAILED(ExpandFilePath(lpsValue, szValStr, sizeof(szValStr)/sizeof(szValStr[0]))))
{
szValStr[0] = '\0';
}
}
//
// compare expanded XML str with current reg str expanded
// since this is REG_MULTI_SZ type, we have no way to tell
// if this SZ inside MULTI_SZ is expandable or not, we
// we will always try to expand it.
//
if (!rc && _T('\0') != szValStr[0])
{
rc = (SUCCEEDED(ExpandFilePath((LPCTSTR)lpCurStr, szRegStr, sizeof(szRegStr)/sizeof(szRegStr[0])))) &&
(lstrcmpi((LPCTSTR)szRegStr, szValStr) == 0);
}
if (!rc)
{
//
// move to next string
//
lpCurStr += (lstrlen(lpCurStr) + 1);
if (_T('\0') == *lpCurStr)
{
break; // no more string to read
}
}
} while (!rc); // repeat to next string
}
break;
case REG_QWORD:
{
HMODULE hLib = LoadLibraryFromSystemDir(_T("Shlwapi.dll"));
if (hLib)
{
#if defined(UNICODE) || defined(_UNICODE)
PFN_StrToInt64Ex pfnStrToInt64Ex = (PFN_StrToInt64Ex) GetProcAddress(hLib, "StrToInt64ExW");
#else
PFN_StrToInt64Ex pfnStrToInt64Ex = (PFN_StrToInt64Ex) GetProcAddress(hLib, "StrToInt64ExA");
#endif
if (pfnStrToInt64Ex)
{
LONGLONG llNum;
rc = (pfnStrToInt64Ex((LPCTSTR)lpsValue, STIF_DEFAULT, &llNum) &&
(llNum == (LONGLONG)pBuffer));
}
FreeLibrary(hLib);
}
}
break;
case REG_BINARY:
rc = (CmpBinaryToString(pBuffer, dwSize, lpsValue) == 0);
break;
default:
rc = FALSE;
}
CleanUp:
if (hKey)
{
RegCloseKey(hKey);
}
LOG_Out(_T("Result: %s"), rc ? _T("TRUE") : _T("FALSE"));
return rc;
}
// ----------------------------------------------------------------------
//
// public function to tell is a reg key has a string type value
// that contains given string
//
// ----------------------------------------------------------------------
BOOL RegKeySubstring(
LPCTSTR lpsKeyPath, // key path
LPCTSTR lpsValName, // optional value name
LPCTSTR lpsSubString // substring to see if contained in value
)
{
LOG_Block("RegKeySubstring()");
HKEY hRootKey = 0, hKey = 0;
LPCTSTR lpsSubKey = NULL;
BOOL rc = FALSE;
BYTE btBuffer[REG_BUF_SIZE];
LPBYTE pBuffer = btBuffer;
LPTSTR lpCurStr = (LPTSTR) pBuffer;
DWORD dwType = 0x0;
DWORD dwSize = sizeof(btBuffer);
DWORD dwCode = 0x0;
TCHAR szRegStr[MAX_PATH];
TCHAR szValStr[MAX_PATH]; // buffer for expanding
USES_MY_MEMORY;
if (NULL == lpsKeyPath || NULL == lpsSubString)
{
LOG_ErrorMsg(E_INVALIDARG);
return FALSE;
}
LOG_Out(_T("Parameters: (%s, %s, %s)"), lpsKeyPath, lpsValName, lpsSubString);
lpsSubKey = SplitRegPath(lpsKeyPath, &hRootKey);
if (0 == hRootKey || (ERROR_SUCCESS != RegOpenKeyEx(hRootKey, lpsSubKey, 0, KEY_QUERY_VALUE, &hKey)))
{
goto CleanUp;
}
//
// try to query the value with existing buffer.
//
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, btBuffer, &dwSize);
if (ERROR_MORE_DATA == dwCode)
{
//
// if found the existing buffer not large enough,
// then allocate memory large enough to store the data now
//
if (NULL == (pBuffer = (LPBYTE) MemAlloc(dwSize)))
{
goto CleanUp;
}
lpCurStr = (LPTSTR) pBuffer;
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, pBuffer, &dwSize);
}
if (ERROR_SUCCESS != dwCode || REG_SZ != dwType && REG_EXPAND_SZ != dwType && REG_MULTI_SZ != dwType)
{
goto CleanUp;
}
szValStr[0] = _T('\0');
do
{
//
// see if the value contains the substring passed in
//
rc = (StrStrI((LPCTSTR)lpCurStr, lpsSubString) != NULL);
//
// if not found, it's possibly caused by
// path variable or environment variable embedded
//
if (!rc && _T('\0') == szValStr[0])
{
if (FAILED(ExpandFilePath(lpsSubString, szValStr, sizeof(szValStr)/sizeof(szValStr[0]))))
{
break;
}
rc = StrStrI((LPCTSTR)szRegStr, szValStr) != NULL;
}
if (!rc && _T('\0') != szValStr[0] && (REG_EXPAND_SZ == dwType ))
{
//
// try to expand string from reg if this string is expandable
//
rc = (SUCCEEDED(ExpandFilePath((LPCTSTR)lpCurStr, szRegStr, sizeof(szRegStr)/sizeof(szRegStr[0])))) &&
(StrStrI((LPCTSTR)szRegStr, szValStr) != NULL);
} // if not found
if (!rc && REG_MULTI_SZ == dwType)
{
//
// move to next string
//
lpCurStr += (lstrlen(lpCurStr) + 1);
if (_T('\0') == *lpCurStr)
{
break; // no more string to read
}
}
} while (!rc && REG_MULTI_SZ == dwType); // repeat to next string if REG_MULTI_SZ
CleanUp:
if (hKey)
{
RegCloseKey(hKey);
}
LOG_Out(_T("Result: %s"), rc ? _T("TRUE") : _T("FALSE"));
return rc;
}
// ----------------------------------------------------------------------
//
// public function to tell is a reg key has a string type value
// that contains given string
//
// since this is a comparision function, rather than to check existance,
// anything wrong to get the reg version will make the reg having default
// version: 0.0.0.0
//
// ----------------------------------------------------------------------
BOOL RegKeyVersion(
LPCTSTR lpsKeyPath, // key path
LPCTSTR lpsValName, // optional value name
LPCTSTR lpsVersion, // version in string to compare
_VER_STATUS CompareVerb // how to compair
)
{
LOG_Block("RegKeyVersion()");
HKEY hRootKey = 0, hKey = 0;
LPCTSTR lpsSubKey = NULL;
BOOL rc = FALSE;
BYTE btBuffer[REG_BUF_SIZE];
LPBYTE pBuffer = btBuffer;
DWORD dwType = 0x0;
DWORD dwSize = sizeof(btBuffer);
DWORD dwCode = 0x0;
FILE_VERSION verReg, verXml;
int verCompare;
HRESULT hr=S_OK;
USES_IU_CONVERSION;
if (NULL == lpsKeyPath || NULL == lpsVersion)
{
LOG_ErrorMsg(E_INVALIDARG);
return FALSE;
}
LOG_Out(_T("Parameters: (%s, %s, %s, %d)"), lpsKeyPath, lpsValName, lpsVersion, (int)CompareVerb);
//
// initialize the reg version string buffer
//
//The buffer size of btBuffer is sufficient to hold the source string
if(FAILED(hr=StringCchCopyEx((LPTSTR)btBuffer,ARRAYSIZE(btBuffer)/sizeof(TCHAR),_T("0.0.0.0"),NULL,NULL,MISTSAFE_STRING_FLAGS)))
{
LOG_ErrorMsg(hr);
return FALSE;
}
lpsSubKey = SplitRegPath(lpsKeyPath, &hRootKey);
if (0 == hRootKey || (ERROR_SUCCESS != RegOpenKeyEx(hRootKey, lpsSubKey, 0, KEY_QUERY_VALUE, &hKey)))
{
// LOG_ErrorMsg(ERROR_BADKEY); don't log error since we don't know if this key HAS to be there or not
goto GotVersion;
}
//
// try to query the value with existing buffer.
//
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, btBuffer, &dwSize);
if (ERROR_MORE_DATA == dwCode)
{
//
// if found the existing buffer not large enough,
// then allocate memory large enough to store the data now
//
pBuffer = (LPBYTE) MemAlloc(dwSize);
if (NULL == pBuffer)
{
goto GotVersion;
}
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, pBuffer, &dwSize);
}
if (ERROR_SUCCESS != dwCode || REG_SZ != dwType)
{
hr=StringCchCopyEx((LPTSTR)pBuffer,dwSize/sizeof(TCHAR),_T("0.0.0.0"),NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
}
GotVersion:
//
// convert the retrieved reg value to version
//
if (!ConvertStringVerToFileVer(T2CA((LPCTSTR) pBuffer), &verReg) ||
!ConvertStringVerToFileVer(T2CA((LPCTSTR) lpsVersion), &verXml))
{
goto CleanUp;
}
//
// maybe we successfully read data from reg, but that data can't be converted
// into version at all. In this case, we still want to use the default version
// for comparision
//
if (0 > verReg.Major)
{
verReg.Major = verReg.Minor = verReg.Build = verReg.Ext = 0;
}
//
// compare version number. if a < b, -1; a > b, +1
//
verCompare = CompareFileVersion(verReg, verXml);
switch (CompareVerb)
{
case DETX_LOWER:
//
// if reg key version less than XML version
//
rc = (verCompare < 0);
break;
case DETX_LOWER_OR_EQUAL:
//
// if reg key version less than or equal to XML version
//
rc = (verCompare <= 0);
break;
case DETX_SAME:
//
// if reg key version same as XML version
//
rc = (0 == verCompare);
break;
case DETX_HIGHER_OR_EQUAL:
//
// if reg key version higher than or equal to XML version
//
rc = (verCompare >= 0);
break;
case DETX_HIGHER:
//
// if reg key versiong higher than XML version
//
rc = (verCompare > 0);
break;
default:
//
// should never happen
//
rc = FALSE;
break;
}
CleanUp:
if (hKey)
{
RegCloseKey(hKey);
}
LOG_Out(_T("Result: %s"), rc ? _T("TRUE") : _T("FALSE"));
return rc;
}
// ----------------------------------------------------------------------------------
//
// public function to find out the file path based on reg
// assumption:
// lpsFilePath points to a buffer at least MAX_PATH long.
//
// ----------------------------------------------------------------------------------
BOOL GetFilePathFromReg(
LPCTSTR lpsKeyPath, // key path
LPCTSTR lpsValName, // optional value name
LPCTSTR lpsRelativePath,// optional additonal relative path to add to path in reg
LPCTSTR lpsFileName, // optional file name to append to path
LPTSTR lpsFilePath
)
{
LOG_Block("GetFilePathFromReg()");
HKEY hRootKey = 0, hKey = 0;
LPCTSTR lpsSubKey = NULL;
BOOL rc = FALSE;
BYTE btBuffer[REG_BUF_SIZE];
LPBYTE pBuffer = btBuffer;
DWORD dwType = 0x0;
DWORD dwSize = sizeof(btBuffer);
DWORD dwCode = 0x0;
FILE_VERSION verReg, verXml;
int verCompare;
HRESULT hr=S_OK;
USES_IU_CONVERSION;
if (NULL == lpsKeyPath || NULL == lpsFilePath)
{
LOG_ErrorMsg(E_INVALIDARG);
return FALSE;
}
//
// initialize file path
//
*lpsFilePath = '\0';
LOG_Out(_T("Parameters: (%s, %s, %s, %s)"), lpsKeyPath, lpsValName, lpsRelativePath, lpsFileName);
lpsSubKey = SplitRegPath(lpsKeyPath, &hRootKey);
if (0 == hRootKey || (ERROR_SUCCESS != RegOpenKeyEx(hRootKey, lpsSubKey, 0, KEY_QUERY_VALUE, &hKey)))
{
// LOG_ErrorMsg(ERROR_BADKEY); --- key probably not required to exist!
goto CleanUp;
}
//
// try to query the value with existing buffer.
//
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, btBuffer, &dwSize);
if (ERROR_MORE_DATA == dwCode)
{
//
// if found the existing buffer not large enough,
// then allocate memory large enough to store the data now
//
if (NULL == (pBuffer = (LPBYTE) MemAlloc(dwSize + sizeof(TCHAR))))
{
goto CleanUp;
}
dwCode = RegQueryValueEx(hKey, lpsValName, NULL, &dwType, pBuffer, &dwSize);
}
if (ERROR_SUCCESS != dwCode || REG_SZ != dwType)
{
LOG_ErrorMsg(ERROR_BADKEY);
goto CleanUp;
}
//
// validate the to-be-combined path can fit into the buffer
//
if (lstrlen(lpsRelativePath) + lstrlen(lpsFileName) + dwSize/sizeof(TCHAR) >= MAX_PATH)
{
LOG_ErrorMsg(ERROR_BUFFER_OVERFLOW);
goto CleanUp;
}
//
// combile the path with optional relative path and file name
//
//The size of lpsFilePath is not available for using Safe String Functions
hr=StringCchCopyEx(lpsFilePath,MAX_PATH,(LPCTSTR) pBuffer,NULL,NULL,MISTSAFE_STRING_FLAGS);
if ( SUCCEEDED(hr) && (NULL == lpsRelativePath || SUCCEEDED(PathCchAppend(lpsFilePath,MAX_PATH,lpsRelativePath)) ) && (NULL == lpsFileName || SUCCEEDED(PathCchAppend(lpsFilePath,MAX_PATH,lpsFileName)) ))
{
rc = TRUE;
}
CleanUp:
if (hKey)
{
RegCloseKey(hKey);
}
if (!rc)
{
//
// make sure the buffer is set to empty string if error
//
*lpsFilePath = _T('\0');
}
else
{
LOG_Out(_T("Found path: %s"), lpsFilePath);
}
return rc;
}