// // MODULE: CommonREGCONNECT.CPP // // PURPOSE: read - write to the registry; common code for Online TS and Local TS, which differ // on many functions of this class // // COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com // // AUTHOR: Oleg Kalosha, Joe Mabel // // ORIGINAL DATE: 8-24-98 in Online TS. This file abstracted 1-19-98 // // NOTES: // // Version Date By Comments //-------------------------------------------------------------------- // V3.0 08-04-98 OK // V3.0 09-10-98 JM backslashing; access log file info // V3.1 01-19-98 JM branch out version exclusively for Local TS #pragma warning(disable:4786) #include "stdafx.h" #include "apgtsregconnect.h" #include "event.h" #include "apgtsevt.h" #include "apgtscls.h" #include "apgts.h" #include "apiwraps.h" CMutexOwner CAPGTSRegConnector::s_mx(_T("APGTSRegConnector")); //////////////////////////////////////////////////////////////////////////////////// // CAPGTSRegConnector //////////////////////////////////////////////////////////////////////////////////// CAPGTSRegConnector::~CAPGTSRegConnector() { } // When this lock is held, it locks against not just other threads locking this object, // but against other threads locking any objects of class CAPGTSRegConnector. void CAPGTSRegConnector::Lock() { WAIT_INFINITE( s_mx.Handle() ); } void CAPGTSRegConnector::Unlock() { ::ReleaseMutex(s_mx.Handle()); } bool CAPGTSRegConnector::IsRead() { bool ret = false; Lock(); ret = m_RegistryInfo.m_bIsRead; Unlock(); return ret; } // the root key (typically "SOFTWARE\Microsoft" in Local TS or "SOFTWARE\\ISAPITroubleShoot" in Online TS) exists bool CAPGTSRegConnector::Exists() { bool ret = false; CRegUtil reg; Lock(); if (reg.Open(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), KEY_QUERY_VALUE)) if (reg.Open(RegThisProgram(), KEY_QUERY_VALUE)) ret = true; reg.Close(); Unlock(); return ret; } /*static*/ CString & CAPGTSRegConnector::StringFromConnector(ERegConnector e, CString & str) { switch (e) { case eResourcePath: str = FULLRESOURCE_STR; break; case eVrootPath: str = VROOTPATH_STR; break; case eMaxThreads: str = MAX_THREADS_STR; break; case eThreadsPP: str = THREADS_PER_PROCESSOR_STR; break; case eMaxWQItems: str = MAX_WORK_QUEUE_ITEMS_STR; break; case eCookieLife: str = COOKIE_LIFE_IN_MINS_STR; break; case eReloadDelay: str = RELOAD_DELAY_STR; break; case eDetailedEventLogging: str = DETAILED_EVENT_LOGGING_STR; break; case eLogFilePath: str = LOG_FILE_DIR_STR; break; case eTopicFileExtension: str = LOG_FILE_DIR_STR; break; case eSniffAutomatic: str = SNIFF_AUTOMATIC_STR; break; case eSniffManual: str = SNIFF_MANUAL_STR; break; default: str = _T(""); break; } return str; } /*static*/ CAPGTSRegConnector::ERegConnector CAPGTSRegConnector::ConnectorFromString( const CString & str) { ERegConnector e = eIndefinite; if (str == FULLRESOURCE_STR) e = eResourcePath; else if (str == VROOTPATH_STR) e = eVrootPath; else if (str == MAX_THREADS_STR) e = eMaxThreads; else if (str == THREADS_PER_PROCESSOR_STR) e = eThreadsPP; else if (str == MAX_WORK_QUEUE_ITEMS_STR) e = eMaxWQItems; else if (str == COOKIE_LIFE_IN_MINS_STR) e = eCookieLife; else if (str == RELOAD_DELAY_STR) e = eReloadDelay; else if (str == DETAILED_EVENT_LOGGING_STR) e = eDetailedEventLogging; else if (str == LOG_FILE_DIR_STR) e = eLogFilePath; else if (str == SNIFF_AUTOMATIC_STR) e = eSniffAutomatic; else if (str == SNIFF_MANUAL_STR) e = eSniffManual; return e; } /*static*/ bool CAPGTSRegConnector::IsNumeric(ERegConnector e) { switch (e) { case eMaxThreads: return true; case eThreadsPP: return true; case eMaxWQItems: return true; case eCookieLife: return true; case eReloadDelay: return true; case eDetailedEventLogging: return true; case eSniffAutomatic: return true; case eSniffManual: return true; default: return false; } } /*static*/ bool CAPGTSRegConnector::IsString(ERegConnector e) { switch (e) { case eResourcePath: return true; case eVrootPath: return true; case eLogFilePath: return true; case eTopicFileExtension: return true; default: return false; } } //////////////////////////////////////////////////////// // The following 2 functions set values in the registry. Note that they do NOT // maintain member values. That must be done at a higher level. // Like CRegUtil::SetNumericValue(), and CRegUtil::SetStringValue(), // these assume we already have right key open. // These also assume we have the relevant lock. void CAPGTSRegConnector::SetNumericValue(CRegUtil ®, ERegConnector e, DWORD dwValue) { CString str; if( IsNumeric(e) && reg.SetNumericValue(StringFromConnector(e, str), dwValue)) return; // either inappropriate input or otherwise couldn't set value throw CAPGTSRegConnectorException(__FILE__, __LINE__, reg, e); } // // See comments on CAPGTSRegConnector::SetNumericValue void CAPGTSRegConnector::SetStringValue(CRegUtil ®, ERegConnector e, CString strValue) { CString str; if( IsString(e) && reg.SetStringValue(StringFromConnector(e, str), strValue)) return; // either inappropriate input or otherwise couldn't set value throw CAPGTSRegConnectorException(__FILE__, __LINE__, reg, e); } /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// // The following 3 functions set values in the registry. Note that they do NOT // maintain member values. Typically, these are to be used in a CAPGTSRegConnector // that exists briefly for the sole purpose of setting registry values. // // If there is a CRegistryMonitor in existence -- whether it is this object itself // or a distinct object -- it will become aware of this change by monitoring // the registry and will behave accordingly. // // SetOneNumericValue() is a higher-level way to set a numeric value. // Does not assume anything about open keys or held locks. // Does assume value is in the usual area where APGTS stores its registry data. bool CAPGTSRegConnector::SetOneNumericValue(ERegConnector e, DWORD dwValue) { bool bRet=true; Lock(); try { CRegUtil reg; bool was_created = false; if (reg.Create(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), &was_created, KEY_QUERY_VALUE | KEY_WRITE)) { if (reg.Create(RegThisProgram(), &was_created, KEY_READ | KEY_WRITE)) { SetNumericValue(reg, e, dwValue); } } } catch(CAPGTSRegConnectorException& exception) { exception.Log(); exception.Close(); bRet=false; } Unlock(); return bRet; } // // See comments on CAPGTSRegConnector::SetOneNumericValue // SetOneStringValue() is a higher-level way to set a string value. // Does not assume anything about open keys or held locks. // Does assume value is in the usual area where APGTS stores its registry data. bool CAPGTSRegConnector::SetOneStringValue(ERegConnector e, const CString & strValue) { bool bRet=true; Lock(); try { CRegUtil reg; bool was_created = false; if (reg.Create(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), &was_created, KEY_QUERY_VALUE | KEY_WRITE)) { if (reg.Create(RegThisProgram(), &was_created, KEY_READ | KEY_WRITE)) { SetStringValue(reg, e, strValue); } } } catch(CAPGTSRegConnectorException& exception) { exception.Log(); exception.Close(); bRet=false; } Unlock(); return bRet; } // // See comments on CAPGTSRegConnector::SetOneNumericValue. This is the public function // Function returns true if strName represents a value we maintain. // bChanged returns true if the value is changed. If the function returns false, bChanged // always returns false. bool CAPGTSRegConnector::SetOneValue(const CString & strName, const CString & strValue, bool &bChanged) { ERegConnector e = ConnectorFromString(strName); if (IsNumeric(e)) { bChanged = SetOneNumericValue(e, _ttoi(strValue)); return true; } else if (IsString(e)) { bChanged = SetOneStringValue(e, strValue); return true; } else { CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ ); CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(), SrcLoc.GetSrcFileLineStr(), _T(""), _T(""), EV_GTS_ERROR_INVALIDREGCONNECTOR ); bChanged = false; return false; } } ////////////////////////////////////////////////////// // Having read a string strNew from the registry & done any massaging it gets, // assign this string value to the appropriate variable strPersist. // Returns true and logs dwEvent if strPersist is changed (new value differs from old). /*static*/ bool CAPGTSRegConnector::AssignString(CString & strPersist, const CString & strNew, DWORD dwEvent) { if (!(strNew == strPersist)) { CString str = strPersist; str += _T(" | "); str += strNew; CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ ); CEvent::ReportWFEvent(SrcLoc.GetSrcFileLineStr(), SrcLoc.GetSrcFileLineStr(), str, _T(""), dwEvent); strPersist = strNew; return true; } return false; } // Having read a numeric dwNew from the registry // assign this value to the appropriate variable dwPersist. // Also used a second time if we need to force the value to an acceptable number. // Returns true and logs dwEvent if dwPersist is changed (new value differs from old). // If dwEventDecrease is non-zero, it provides a distinct message to log if the value // is decreased rather than increased. /*static*/ bool CAPGTSRegConnector::AssignNumeric(DWORD & dwPersist, DWORD dwNew, DWORD dwEvent, DWORD dwEventDecrease /* =0 */) { if (dwNew != dwPersist) { CString strOld; strOld.Format(_T("%d"), dwPersist ); CString strNew; strNew.Format(_T("%d"), dwNew); CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ ); CEvent::ReportWFEvent(SrcLoc.GetSrcFileLineStr(), SrcLoc.GetSrcFileLineStr(), strOld, strNew, (dwEventDecrease != 0 && dwNew < dwPersist) ? dwEventDecrease : dwEvent); dwPersist = dwNew; return true; } return false; } /*static*/ bool CAPGTSRegConnector::ForceRangeOfNumeric( DWORD & dw, DWORD dwDefault, DWORD dwEvent, DWORD dwMin, /*=1*/ DWORD dwMax /*=ABS_MAX_REG_PARAM_VAL*/ ) { // do limited validation; if (dw > dwMax || dw < dwMin) { AssignNumeric(dw, dwDefault, dwEvent); return true; } return false; } // pump data into m_RegistryInfo - PLUS sets absent data in registry to default. // OUTPUT maskChanged or-ed ERegConnector-based mask of elements that have been // changed since last read // OUTPUT maskCreated or-ed ERegConnector-based mask of elements that were created // in registry (because they previously didn't exist in registry) bool CAPGTSRegConnector::Read(int & maskChanged, int & maskCreated) { bool ret = true; Lock(); try { ReadUpdateRegistry(maskChanged, maskCreated); m_RegistryInfo.m_bIsRead = true; } catch(CAPGTSRegConnectorException& exception) { exception.Log(); exception.Close(); ret = false; } Unlock(); return ret; } void CAPGTSRegConnector::Clear() { Lock(); // Check if our registry tree exists. if (!Exists()) { // Rebuilds our registry tree if it has been damaged or deleted. CRegUtil reg; bool was_created = false; if (reg.Create(HKEY_LOCAL_MACHINE, RegSoftwareLoc(), &was_created, KEY_QUERY_VALUE | KEY_WRITE)) reg.Create(RegThisProgram(), &was_created, KEY_READ | KEY_WRITE); reg.Close(); } m_RegistryInfo.SetToDefault(); Unlock(); } bool CAPGTSRegConnector::GetNumericInfo(ERegConnector en, DWORD& out) { bool ret = true; Lock(); if (en == eMaxThreads) out = m_RegistryInfo.dwMaxThreads; else if (en == eThreadsPP) out = m_RegistryInfo.dwThreadsPP; else if (en == eMaxWQItems) out = m_RegistryInfo.dwMaxWQItems; else if (en == eCookieLife) out = m_RegistryInfo.dwCookieLife; else if (en == eReloadDelay) out = m_RegistryInfo.dwReloadDelay; else if (en == eDetailedEventLogging) out = m_RegistryInfo.dwDetailedEventLogging; else if (en == eSniffAutomatic) out = m_RegistryInfo.dwSniffAutomatic; else if (en == eSniffManual) out = m_RegistryInfo.dwSniffManual; else ret = false; Unlock(); return ret; } bool CAPGTSRegConnector::GetStringInfo(ERegConnector en, CString& out) { bool ret = true; Lock(); if (en == eResourcePath) out = m_RegistryInfo.strResourcePath; else if (en == eVrootPath) out = m_RegistryInfo.strVrootPath; else if (en == eLogFilePath) out = m_RegistryInfo.strLogFilePath; else if (en == eTopicFileExtension) out = m_RegistryInfo.strTopicFileExtension; else ret = false; Unlock(); return ret; } // AddBackslash appends a backslash ('\') to CStrings that do not already end in '\'. /* static */void CAPGTSRegConnector::AddBackslash(CString & str) { int len = str.GetLength(); if (len && str.Right(1).Find('\\') >= 0) { // do nothing, already has backslash } else // add backslash str += "\\"; return; } // BackslashIt replaces all frontslashes ('/') in str with backslashes ('\') // and (optionally) forces termination with a backslash /* static */void CAPGTSRegConnector::BackslashIt(CString & str, bool bForce) { int loc; while ((loc = str.Find('/')) != -1) { str = str.Left(loc) + "\\" + str.Mid(loc+1); } if (bForce) AddBackslash(str); } // APGTS key access CString CAPGTSRegConnector::ThisProgramFullKey() { CString str; str.Format(_T("%s\\%s"), RegSoftwareLoc(), RegThisProgram()); return str; } //////////////////////////////////////////////////////////////////////////////////// // CAPGTSRegConnectorException //////////////////////////////////////////////////////////////////////////////////// void CAPGTSRegConnectorException::Log() { CString str; switch (eVariable) { case CAPGTSRegConnector::eResourcePath: case CAPGTSRegConnector::eVrootPath: case CAPGTSRegConnector::eMaxThreads: case CAPGTSRegConnector::eThreadsPP: case CAPGTSRegConnector::eMaxWQItems: case CAPGTSRegConnector::eCookieLife: case CAPGTSRegConnector::eReloadDelay: case CAPGTSRegConnector::eDetailedEventLogging: case CAPGTSRegConnector::eLogFilePath: case CAPGTSRegConnector::eSniffAutomatic: case CAPGTSRegConnector::eSniffManual: CAPGTSRegConnector::StringFromConnector(eVariable, str); break; case CAPGTSRegConnector::eProblemWithKey: str = _T("Can't open reg key"); break; case CAPGTSRegConnector::eProblemWithLogKey: str = _T("Can't open IIS reg key"); break; case CAPGTSRegConnector::eIndefinite: // falls through to default. default: str = _T(""); break; } CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ ); CEvent::ReportWFEvent(GetSrcFileLineStr(), SrcLoc.GetSrcFileLineStr(), str, _T(""), TSERR_REG_READ_WRITE_PROBLEM); }