/////////////////////////////////////////////////////////////////////////////// // Name: msw/regconf.cpp // Purpose: // Author: Vadim Zeitlin // Modified by: // Created: 27.04.98 // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin // Licence: wxWindows license /////////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "regconf.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/string.h" #endif //WX_PRECOMP #include "wx/event.h" #include "wx/app.h" #include "wx/log.h" #include "wx/config.h" #ifndef __WIN16__ #include "wx/msw/registry.h" #include "wx/msw/regconf.h" // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- // we put our data in HKLM\SOFTWARE_KEY\appname #define SOFTWARE_KEY wxString("Software\\") // ---------------------------------------------------------------------------- // global functions // ---------------------------------------------------------------------------- // get the value if the key is opened and it exists bool TryGetValue(const wxRegKey& key, const wxString& str, wxString& strVal) { return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, strVal); } bool TryGetValue(const wxRegKey& key, const wxString& str, long *plVal) { return key.IsOpened() && key.HasValue(str) && key.QueryValue(str, plVal); } // ============================================================================ // implementation // ============================================================================ // ---------------------------------------------------------------------------- // ctor/dtor // ---------------------------------------------------------------------------- // create the config object which stores its data under HKCU\vendor\app and, if // style & wxCONFIG_USE_GLOBAL_FILE, under HKLM\vendor\app wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName, const wxString& strLocal, const wxString& strGlobal, long style) : wxConfigBase(appName, vendorName, strLocal, strGlobal, style) { wxString strRoot; bool bDoUseGlobal = (style & wxCONFIG_USE_GLOBAL_FILE) != 0; // the convention is to put the programs keys under \ // (but it can be overriden by specifying the pathes explicitly in strLocal // and/or strGlobal) if ( strLocal.IsEmpty() || (strGlobal.IsEmpty() && bDoUseGlobal) ) { if ( vendorName.IsEmpty() ) { if ( wxTheApp ) strRoot = wxTheApp->GetVendorName(); } else { strRoot = vendorName; } // no '\\' needed if no vendor name if ( !strRoot.IsEmpty() ) { strRoot += '\\'; } if ( appName.IsEmpty() ) { wxCHECK_RET( wxTheApp, wxT("No application name in wxRegConfig ctor!") ); strRoot << wxTheApp->GetAppName(); } else { strRoot << appName; } } //else: we don't need to do all the complicated stuff above wxString str = strLocal.IsEmpty() ? strRoot : strLocal; m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str); m_keyLocal.SetName(m_keyLocalRoot, ""); if ( bDoUseGlobal ) { str = strGlobal.IsEmpty() ? strRoot : strGlobal; m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str); m_keyGlobal.SetName(m_keyGlobalRoot, ""); } // Create() will Open() if key already exists m_keyLocalRoot.Create(); // as it's the same key, Open() shouldn't fail (i.e. no need for Create()) m_keyLocal.Open(); // OTOH, this key may perfectly not exist, so suppress error messages the call // to Open() might generate if ( bDoUseGlobal ) { wxLogNull nolog; m_keyGlobalRoot.Open(); } } wxRegConfig::~wxRegConfig() { // nothing to do - key will be closed in their dtors } // ---------------------------------------------------------------------------- // path management // ---------------------------------------------------------------------------- void wxRegConfig::SetPath(const wxString& strPath) { wxArrayString aParts; // because GetPath() returns "" when we're at root, we must understand // empty string as "/" if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) { // absolute path wxSplitPath(aParts, strPath); } else { // relative path, combine with current one wxString strFullPath = GetPath(); strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; wxSplitPath(aParts, strFullPath); } // recombine path parts in one variable wxString strOldPath = m_strPath, strRegPath; m_strPath.Empty(); for ( size_t n = 0; n < aParts.Count(); n++ ) { strRegPath << '\\' << aParts[n]; m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; } if ( m_strPath == strOldPath ) return; // as we create the registry key when SetPath(key) is done, we can be left // with plenty of empty keys if this was only done to try to read some value // which, in fact, doesn't exist - to prevent this from happening we // automatically delete the old key if it was empty if ( m_keyLocal.IsEmpty() ) { m_keyLocal.DeleteSelf(); } // change current key(s) m_keyLocal.SetName(m_keyLocalRoot, strRegPath); m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath); m_keyLocal.Create(); wxLogNull nolog; m_keyGlobal.Open(); } // ---------------------------------------------------------------------------- // enumeration (works only with current group) // ---------------------------------------------------------------------------- /* We want to enumerate all local keys/values after the global ones, but, of course, we don't want to repeat a key which appears locally as well as globally twice. We use the 15th bit of lIndex for distinction between global and local. */ #define LOCAL_MASK 0x8000 #define IS_LOCAL_INDEX(l) (((l) & LOCAL_MASK) != 0) bool wxRegConfig::GetFirstGroup(wxString& str, long& lIndex) const { lIndex = 0; return GetNextGroup(str, lIndex); } bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const { // are we already enumerating local entries? if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) { // try to find a global entry which doesn't appear locally do { if ( !m_keyGlobal.GetNextKey(str, lIndex) ) { // no more global entries lIndex |= LOCAL_MASK; break; } } while( m_keyLocal.HasSubKey(str) ); } // much easier with local entries: get the next one we find // (don't forget to clear our flag bit and set it again later) lIndex &= ~LOCAL_MASK; bool bOk = m_keyLocal.GetNextKey(str, lIndex); lIndex |= LOCAL_MASK; return bOk; } bool wxRegConfig::GetFirstEntry(wxString& str, long& lIndex) const { lIndex = 0; return GetNextEntry(str, lIndex); } bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const { // are we already enumerating local entries? if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) { // try to find a global entry which doesn't appear locally do { if ( !m_keyGlobal.GetNextValue(str, lIndex) ) { // no more global entries lIndex |= LOCAL_MASK; break; } } while( m_keyLocal.HasValue(str) ); } // much easier with local entries: get the next one we find // (don't forget to clear our flag bit and set it again later) lIndex &= ~LOCAL_MASK; bool bOk = m_keyLocal.GetNextValue(str, lIndex); lIndex |= LOCAL_MASK; return bOk; } size_t wxRegConfig::GetNumberOfEntries(bool bRecursive) const { size_t nEntries = 0; // dummy vars wxString str; long l; bool bCont = ((wxRegConfig*)this)->GetFirstEntry(str, l); while ( bCont ) { nEntries++; bCont = ((wxRegConfig*)this)->GetNextEntry(str, l); } return nEntries; } size_t wxRegConfig::GetNumberOfGroups(bool bRecursive) const { size_t nGroups = 0; // dummy vars wxString str; long l; bool bCont = ((wxRegConfig*)this)->GetFirstGroup(str, l); while ( bCont ) { nGroups++; bCont = ((wxRegConfig*)this)->GetNextGroup(str, l); } return nGroups; } // ---------------------------------------------------------------------------- // tests for existence // ---------------------------------------------------------------------------- bool wxRegConfig::HasGroup(const wxString& key) const { wxConfigPathChanger path(this, key); wxString strName(path.Name()); return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName); } bool wxRegConfig::HasEntry(const wxString& key) const { wxConfigPathChanger path(this, key); wxString strName(path.Name()); return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName); } wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const { wxConfigPathChanger path(this, key); wxString strName(path.Name()); bool isNumeric; if ( m_keyLocal.HasValue(strName) ) isNumeric = m_keyLocal.IsNumericValue(strName); else if ( m_keyGlobal.HasValue(strName) ) isNumeric = m_keyGlobal.IsNumericValue(strName); else return wxConfigBase::Type_Unknown; return isNumeric ? wxConfigBase::Type_Integer : wxConfigBase::Type_String; } // ---------------------------------------------------------------------------- // reading/writing // ---------------------------------------------------------------------------- bool wxRegConfig::Read(const wxString& key, wxString *pStr) const { wxConfigPathChanger path(this, key); bool bQueryGlobal = TRUE; // if immutable key exists in global key we must check that it's not // overriden by the local key with the same name if ( IsImmutable(path.Name()) ) { if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) { if ( m_keyLocal.HasValue(path.Name()) ) { wxLogWarning(wxT("User value for immutable key '%s' ignored."), path.Name().c_str()); } *pStr = wxConfigBase::ExpandEnvVars(*pStr); return TRUE; } else { // don't waste time - it's not there anyhow bQueryGlobal = FALSE; } } // first try local key if ( TryGetValue(m_keyLocal, path.Name(), *pStr) || (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) { // nothing to do *pStr = wxConfigBase::ExpandEnvVars(*pStr); return TRUE; } return FALSE; } bool wxRegConfig::Read(const wxString& key, wxString *pStr, const wxString& szDefault) const { wxConfigPathChanger path(this, key); bool bQueryGlobal = TRUE; // if immutable key exists in global key we must check that it's not // overriden by the local key with the same name if ( IsImmutable(path.Name()) ) { if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) { if ( m_keyLocal.HasValue(path.Name()) ) { wxLogWarning(wxT("User value for immutable key '%s' ignored."), path.Name().c_str()); } return TRUE; } else { // don't waste time - it's not there anyhow bQueryGlobal = FALSE; } } // first try local key if ( TryGetValue(m_keyLocal, path.Name(), *pStr) || (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) { *pStr = wxConfigBase::ExpandEnvVars(*pStr); return TRUE; } else { if ( IsRecordingDefaults() ) { ((wxRegConfig*)this)->Write(key, szDefault); } // default value *pStr = szDefault; } *pStr = wxConfigBase::ExpandEnvVars(*pStr); return FALSE; } bool wxRegConfig::Read(const wxString& key, long *plResult) const { wxConfigPathChanger path(this, key); bool bQueryGlobal = TRUE; // if immutable key exists in global key we must check that it's not // overriden by the local key with the same name if ( IsImmutable(path.Name()) ) { if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) { if ( m_keyLocal.HasValue(path.Name()) ) { wxLogWarning(wxT("User value for immutable key '%s' ignored."), path.Name().c_str()); } return TRUE; } else { // don't waste time - it's not there anyhow bQueryGlobal = FALSE; } } // first try local key if ( TryGetValue(m_keyLocal, path.Name(), plResult) || (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) { return TRUE; } return FALSE; } bool wxRegConfig::Write(const wxString& key, const wxString& szValue) { wxConfigPathChanger path(this, key); if ( IsImmutable(path.Name()) ) { wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str()); return FALSE; } return m_keyLocal.SetValue(path.Name(), szValue); } bool wxRegConfig::Write(const wxString& key, long lValue) { wxConfigPathChanger path(this, key); if ( IsImmutable(path.Name()) ) { wxLogError(wxT("Can't change immutable entry '%s'."), path.Name().c_str()); return FALSE; } return m_keyLocal.SetValue(path.Name(), lValue); } // ---------------------------------------------------------------------------- // renaming // ---------------------------------------------------------------------------- bool wxRegConfig::RenameEntry(const wxString& oldName, const wxString& newName) { // check that the old entry exists... if ( !HasEntry(oldName) ) return FALSE; // and that the new one doesn't if ( HasEntry(newName) ) return FALSE; // delete the old entry and create the new one - but do in the reverse // order to not lose the data if Create() fails bool ok; if ( m_keyLocal.IsNumericValue(oldName) ) { long val; ok = m_keyLocal.QueryValue(oldName, &val) && m_keyLocal.SetValue(newName, val); } else { wxString val; ok = m_keyLocal.QueryValue(oldName, val) && m_keyLocal.SetValue(newName, val); } if ( !ok ) return FALSE; if ( !m_keyLocal.DeleteValue(oldName) ) { m_keyLocal.DeleteValue(newName); return FALSE; } return TRUE; } bool wxRegConfig::RenameGroup(const wxString& oldName, const wxString& newName) { // check that the old group exists... if ( !HasGroup(oldName) ) return FALSE; // and that the new one doesn't if ( HasGroup(newName) ) return FALSE; // TODO there is no way to rename a registry key - we must do a deep copy // ourselves wxFAIL_MSG(wxT("Registry key renaming not implemented")); return FALSE; } // ---------------------------------------------------------------------------- // deleting // ---------------------------------------------------------------------------- bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso) { wxConfigPathChanger path(this, value); if ( !m_keyLocal.DeleteValue(path.Name()) ) return FALSE; if ( m_keyLocal.IsEmpty() ) { wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR); SetPath(".."); // changes m_keyLocal return m_keyLocal.DeleteKey(strKey); } return TRUE; } bool wxRegConfig::DeleteGroup(const wxString& key) { wxConfigPathChanger path(this, key); return m_keyLocal.DeleteKey(path.Name()); } bool wxRegConfig::DeleteAll() { m_keyLocal.Close(); m_keyGlobal.Close(); bool bOk = m_keyLocalRoot.DeleteSelf(); // make sure that we opened m_keyGlobalRoot and so it has a reasonable name: // otherwise we will delete HKEY_CLASSES_ROOT recursively if ( bOk && m_keyGlobalRoot.IsOpened() ) bOk = m_keyGlobalRoot.DeleteSelf(); return bOk; } #endif // __WIN16__