#include "precomp.h" #include "regins.h" ///////////////////////////////////////////////////////////////////////////// // CRegInsMap operations HRESULT CRegInsMap::PerformAction(HKEY *phk /*= NULL*/) { (void)phk; return E_NOTIMPL; } HRESULT CRegInsMap::RegToIns(HKEY *phk /*= NULL*/, BOOL fClear /*= FALSE*/) { TCHAR szBuffer[MAX_PATH]; VARIANT var; HKEY hk; HRESULT hr; DWORD cBuffer, dwType; LONG lResult; if ((phk != NULL && *phk == NULL) && m_pszRegKey == NULL) return E_INVALIDARG; //----- Special cases processing ----- //_____ Close cached reg key _____ if ((phk != NULL && *phk != NULL) && (m_pszRegKey == NULL && m_pszRegValue == NULL)) { ASSERT(!fClear); ASSERT(m_pszInsSection == NULL && m_pszInsKey == NULL); SHCloseKey(*phk); *phk = NULL; return S_FALSE; } //_____ Clear ins file entry (not even necessary to open reg key) _____ ASSERT(m_pszInsSection != NULL && m_pszInsKey != NULL); if (fClear) { ASSERT(phk == NULL); // REVIEW: (andrewgu) if i'm clearing and when last entry is gone see if section is gone // as well and if it is not, do getprivateprofilesection to see if section is empty and // delete it if it is. WritePrivateProfileString(m_pszInsSection, m_pszInsKey, NULL, s_pszIns); return S_FALSE; } //----- Main processing ----- hk = (phk != NULL) ? *phk : NULL; openRegKey(&hk); if (hk == NULL) return E_FAIL; //_____ Special case of caching reg key _____ if (m_pszInsSection == NULL) { ASSERT(m_pszInsKey == NULL); if (phk == NULL) return E_INVALIDARG; *phk = hk; return S_FALSE; } szBuffer[0] = TEXT('\0'); cBuffer = sizeof(szBuffer); lResult = SHQueryValueEx(hk, m_pszRegValue, NULL, &dwType, szBuffer, &cBuffer); if (phk != NULL && *phk != hk) SHCloseKey(hk); if (lResult != ERROR_SUCCESS) return E_UNEXPECTED; //----- Convert szBuffer into var with proper type ----- hr = S_OK; VariantClear(&var); switch (dwType) { case REG_BINARY: if (cBuffer > sizeof(int)) { hr = E_UNEXPECTED; break; } // fall through // case REG_DWORD_LITTLE_ENDIAN: case REG_DWORD: var.vt = VT_I4; var.lVal = *(PINT)szBuffer; break; case REG_SZ: case REG_EXPAND_SZ: var.vt = VT_BSTR; var.bstrVal = T2BSTR(szBuffer); break; // case REG_DWORD_BIG_ENDIAN: // case REG_LINK: // case REG_MULTI_SZ: // case REG_NONE: // case REG_RESOURCE_LIST: default: hr = E_FAIL; } if (FAILED(hr)) return hr; //----- Convert var into szBuffer appropriate for WritePrivateProfileString ----- switch (var.vt) { case VT_I4: wnsprintf(szBuffer, countof(szBuffer), TEXT("%l"), var.lVal); break; case VT_I2: wnsprintf(szBuffer, countof(szBuffer), TEXT("%i"), var.iVal); break; case VT_UI1: wnsprintf(szBuffer, countof(szBuffer), TEXT("%u"), (UINT)var.bVal); break; case VT_BOOL: wnsprintf(szBuffer, countof(szBuffer), TEXT("%u"), (UINT)var.boolVal); break; case VT_BSTR: W2Tbuf(var.bstrVal, szBuffer, countof(szBuffer)); break; // too many cases to enumerate that are invalid default: hr = E_FAIL; } if (FAILED(hr)) return hr; WritePrivateProfileString(m_pszInsSection, m_pszInsKey, szBuffer, s_pszIns); return S_OK; } HRESULT CRegInsMap::InsToReg(HKEY *phk /*= NULL*/, BOOL fClear /*= FALSE*/) { (void)phk; (void)fClear; return E_NOTIMPL; } HRESULT CRegInsMap::RegToInsArray(CRegInsMap *prg, UINT cEntries, BOOL fClear /*= FALSE*/) { HKEY hk, *rghkStack; HRESULT hr; UINT i, cStackDepth; BOOL fContinueOnFailure, fTotalSuccess, fBufferOverrun; if (prg == NULL) return E_INVALIDARG; if (cEntries == 0) return S_OK; hr = S_OK; fContinueOnFailure = TRUE; fTotalSuccess = TRUE; fBufferOverrun = FALSE; if (fClear) { for (i = 0; i < cEntries; i++) { hr = prg->RegToIns(NULL, fClear); if (FAILED(hr)) { fTotalSuccess = FALSE; if (!fContinueOnFailure) break; } } if (FAILED(hr)) return hr; return fTotalSuccess ? S_OK : S_FALSE; } rghkStack = new HKEY[cEntries/2 + 1]; if (rghkStack == NULL) return E_OUTOFMEMORY; cStackDepth = 0; for (i = 0; i < cEntries; i++) { if (cStackDepth == 0) hk = NULL; else { hk = rghkStack[cStackDepth-1]; ASSERT(hk != NULL); } hr = prg->RegToIns(&hk); if (FAILED(hr)) { fTotalSuccess = FALSE; if (fContinueOnFailure) continue; else break; } if (hk != NULL) { if (hk != rghkStack[cStackDepth-1]) { if (cStackDepth >= cEntries/2 + 1) { SHCloseKey(hk); hr = E_UNEXPECTED; fTotalSuccess = FALSE; fBufferOverrun = TRUE; break; } rghkStack[cStackDepth++] = hk; } } else if (cStackDepth > 0) rghkStack[--cStackDepth] = NULL; } if (FAILED(hr)) { ASSERT(!fTotalSuccess); for (i = 0; i < cEntries/2 + 1; i++) if (rghkStack[i] != NULL) { SHCloseKey(rghkStack[i]); rghkStack[i] = NULL; } cStackDepth = 0; } ASSERT(cStackDepth == 0); delete[] rghkStack; if (!fBufferOverrun) if (fContinueOnFailure && !fTotalSuccess) hr = S_FALSE; return hr; } HRESULT CRegInsMap::InsToRegArray(CRegInsMap *prg, UINT cEntries, BOOL fClear /*= FALSE*/) { (void)prg; (void)cEntries; (void)fClear; return E_NOTIMPL; } ///////////////////////////////////////////////////////////////////////////// // CRegInsMap implementation helper routines void CRegInsMap::openRegKey(HKEY *phk) { LPCTSTR pszRegKey; HRESULT hr; LONG lResult; ASSERT(phk != NULL); if (*phk != NULL && m_pszRegKey == NULL) return; ASSERT(m_pszRegKey != NULL); if (*phk == NULL) { hr = getHive(phk, &pszRegKey); if (FAILED(hr)) { ASSERT(*phk == NULL && pszRegKey == NULL); return; } ASSERT(*phk != NULL && pszRegKey != NULL); } else { ASSERT(getHive(NULL, NULL, GH_LOOKUPONLY) != S_OK); pszRegKey = m_pszRegKey; } lResult = SHOpenKey(*phk, pszRegKey, KEY_QUERY_VALUE, phk); if (lResult != ERROR_SUCCESS) { ASSERT(*phk == NULL); } } HRESULT CRegInsMap::getHive(HKEY *phk, LPCTSTR *ppszRegKey, WORD wFlags /*= GH_DEFAULT*/) { LPCTSTR pszSlash; if (!(wFlags & GH_LOOKUPONLY)) { if (phk == NULL || ppszRegKey == NULL) return E_INVALIDARG; *phk = NULL; *ppszRegKey = NULL; } pszSlash = StrChr(m_pszRegKey, TEXT('\\')); if (pszSlash == NULL) return E_FAIL; ASSERT(*(pszSlash+1) != TEXT('\0')); struct { HKEY hk; LPCTSTR pszHive; } map[] = { { HKEY_CLASSES_ROOT, RH_HKCR }, { HKEY_CURRENT_USER, RH_HKCU }, { HKEY_LOCAL_MACHINE, RH_HKLM }, { HKEY_USERS, RH_HKU } }; for (UINT i = 0; i < countof(map); i++) if (StrCmpNI(m_pszRegKey, map[i].pszHive, INT(m_pszRegKey-pszSlash) + 1) == 0) break; if (i >= countof(map)) { if (!(wFlags & GH_LOOKUPONLY)) *ppszRegKey = m_pszRegKey; return S_FALSE; } if (!(wFlags & GH_LOOKUPONLY)) { *phk = map[i].hk; *ppszRegKey = pszSlash + 1; } return S_OK; } // HINTS: (andrewgu) on optimization // 1. to start a regkey optimization section (i.e. to cache a reg key) have InsSection set to // NULL, at the same time InsKey is ASSERTed NULL, meaning it better be NULL too; // 2. to close last cached key, have RegKey and RegValue equal NULL. also InsSection and InsKey // are ASSERTed NULL, so they also should be NULL; // 3. if in optimization section and reg key is not empty current cached hk will be combined with // regkey, it'll ASSERT if finds hive in RegKey; // 4. if hive is not found in RegKey and the object is not in the optimization section it's an error // 5. nested optimization sections are allowed /* LPCTSTR CRegInsMap::s_pszIns = TEXT("c:\foo.ini"); CRegInsMap rgTest1 = { TEXT("HKLM\\RegKey0"), TEXT("RegValue0"), 0L, NULL, NULL }; CRegInsMap rgTest[] = { { RH_HKLM TEXT("RegKey0"), NULL, 0L, NULL, NULL }, { TEXT("RegKey1"), TEXT("RegValue1"), 0L, TEXT("InsSection1"), TEXT("InsKey1") }, { NULL , TEXT("RegValue2"), 0L, TEXT("InsSection1"), TEXT("InsKey2") }, { NULL, NULL, 0L, NULL, NULL }, { RH_HKCR RK_IEAK, RV_TOOLBARBMP, 0L, IS_BRANDING, IK_TOOLBARBMP }, { TEXT("RegKey4"), TEXT("RegValue4"), 0L, TEXT("InsSection4"), TEXT("InsKey4") }, { TEXT("RegKey5"), TEXT("RegValue5"), 0L, TEXT("InsSection5"), TEXT("InsKey5") }, { TEXT("RegKey6"), TEXT("RegValue6"), 0L, TEXT("InsSection6"), TEXT("InsKey6") }, { TEXT("RegKey7"), TEXT("RegValue7"), 0L, TEXT("InsSection7"), TEXT("InsKey7") }, { TEXT("RegKey8"), TEXT("RegValue8"), 0L, TEXT("InsSection8"), TEXT("InsKey8") }, { TEXT("RegKey9"), TEXT("RegValue9"), 0L, TEXT("InsSection9"), TEXT("InsKey9") } }; // Example usage rgTest[0].RegToInsArray(rgTest, countof(rgTest)); */