//======================================================================= // // 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 #include #include #include #include #include #include #include "wusafefn.h" #include #include #include 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; }