//+--------------------------------------------------------------------------- // // Copyright (C) 1992, Microsoft Corporation. // // File: registry.cxx // // Contents: implementations for CRegKey member Members // // Members: CRegKey::CRegKey - constructor for registry key object // CRegKey::CRegKey - constructor for registry key object // CRegKey::CreateKey - real worker for constructors // CRegKey::~CRegKey - destructor for registry key object // CRegKey::Delete - delete a registry key // CRegKey::EnumValues - enumerate values of a registry key // CRegKey::EnumKeys - enumerate subkeys of a registry key // CRegKey::NotifyChange - setup change notification for a key // // CRegValue::GetValue - sets a registry value // CRegValue::SetValue - retrieves a registry value // CRegValue::Delete - deletes a registry value // CRegValue::GetTypeCode - returns the type code of the value // // CRegMSZ::SetStrings - sets a multi-string registry value // CRegMSZ::GetStrings - retrieves a multi-string registry value // // History: 09/30/92 Rickhi Created // 09/22/93 AlokS Took out exception throwing code // and added proper return code for // each method. // // 07/26/94 AlokS Made it real light weight for simple // registry set/get operations // // Notes: see notes in registry.hxx // //---------------------------------------------------------------------------- #include "headers.hxx" #pragma hdrstop #include #include #include //+------------------------------------------------------------------------- // // Member: CRegKey::CRegKey // // Synopsis: Constructor for registry key object, using HKEY for parent // // Arguments: [hkParent] - handle to parent key // [pwszPath] - pathname to key // [samDesiredAccess] - desired access rights to the key // [pwszClass] - class for the key // [dwOptions] - options for the key eg volatile or not // [pdwDisposition] - to find out if key was opened or created // [pSecurityAttributes] - used only if the key is created // [fThrowExceptionOnError] - Constructor throw exception on error // // Signals: Internal error state is set if construction fails. // // Returns: -none- // // History: 09/30/92 Rickhi Created // // Notes: All except the hkParent and pwszPath are optional parameters. // //-------------------------------------------------------------------------- CRegKey::CRegKey ( HKEY hkParent, const LPWSTR pwszPath, REGSAM samDesiredAccess, const LPWSTR pwszClass, DWORD dwOptions, DWORD *pdwDisposition, const LPSECURITY_ATTRIBUTES pSecurityAttributes ) :_hkParent(hkParent), _hkThis(NULL), _dwErr (ERROR_SUCCESS) { _dwErr = CreateKey( _hkParent, pwszPath, samDesiredAccess, pwszClass, dwOptions, pdwDisposition, pSecurityAttributes ); } //+------------------------------------------------------------------------- // // Member: CRegKey::CRegKey // // Synopsis: Constructor for registry key object, using CRegKey for parent // // Arguments: [prkParent] - ptr to Parent CRegKey // [pwszPath] - pathname to key // [samDesiredAccess] - desired access rights to the key // [pwszClass] - class for the key // [dwOptions] - options for the key eg volatile or not // [pdwDisposition] - to find out if key was opened or created // [pSecurityAttributes] - used only if the key is created // [fThrowExceptionOnError] - Constructor throw exception on error // // Signals: Internal Error state is set if error occures during construction. // // Returns: nothing // // History: 09/30/92 Rickhi Created // // Notes: All except the prkParent and pwszPath are optional parameters. // //-------------------------------------------------------------------------- CRegKey::CRegKey ( const CRegKey &crkParent, const LPWSTR pwszPath, REGSAM samDesiredAccess, const LPWSTR pwszClass, DWORD dwOptions, DWORD *pdwDisposition, const LPSECURITY_ATTRIBUTES pSecurityAttributes ) :_hkParent(crkParent.GetHandle()), _hkThis(NULL), _dwErr(ERROR_SUCCESS) { _dwErr = CreateKey ( _hkParent, pwszPath, samDesiredAccess, pwszClass, dwOptions, pdwDisposition, pSecurityAttributes ); } //+------------------------------------------------------------------------- // // Member: CRegKey::CRegKey // // Synopsis: Constructor for registry key object, using HKEY for parent // Merely opens the key, if exist // // Arguments: [hkParent] - HKEY to Parent // [dwErr] - Error code returned here // [pwszPath] - pathname to key // [samDesiredAccess] - desired access rights to the key // // Signals: Internal Error state is set if error occures during construction // // Returns: nothing // // History: 09/22/93 AlokS Created // // Notes: Check error status to determine if constructor succeeded // //-------------------------------------------------------------------------- CRegKey::CRegKey ( HKEY hkParent, DWORD *pdwErr, const LPWSTR pwszPath, REGSAM samDesiredAccess ) :_hkParent(hkParent), _hkThis(NULL), _dwErr(ERROR_SUCCESS) { *pdwErr = _dwErr = OpenKey ( _hkParent, pwszPath, samDesiredAccess ); } //+------------------------------------------------------------------------- // // Member: CRegKey::CRegKey // // Synopsis: Constructor for registry key object, using CRegKey for parent // Merely opens the key, if exist // // Arguments: [prkParent] - ptr to Parent CRegKey // [dwErr] - Error code returned here. // [pwszPath] - pathname to key // [samDesiredAccess] - desired access rights to the key // // Signals: Internal Error state is set if error occures during construction // // Returns: nothing // // History: 09/22/93 AlokS Created // // Notes: Check error status to determine if constructor succeeded // //-------------------------------------------------------------------------- CRegKey::CRegKey ( const CRegKey &crkParent, DWORD *pdwErr, const LPWSTR pwszPath, REGSAM samDesiredAccess ) :_hkParent(crkParent.GetHandle()), _hkThis(NULL), _dwErr(ERROR_SUCCESS) { IDfsVolInlineDebOut(( DEB_TRACE, "CRegKey::+CRegKey(0x%x)\n", this)); *pdwErr = _dwErr = OpenKey ( _hkParent, pwszPath, samDesiredAccess ); } //+------------------------------------------------------------------------- // // Member: CRegKey::~CRegKey, public // // Synopsis: Destructor for registry key object // // Arguments: none // // Signals: nothing // // Returns: nothing // // History: 09/30/92 Rickhi Created // // Notes: // //-------------------------------------------------------------------------- CRegKey::~CRegKey() { IDfsVolInlineDebOut(( DEB_TRACE, "CRegKey::~CRegKey(0x%x)\n", this)); if (_hkThis != NULL) { RegCloseKey(_hkThis); } } //+------------------------------------------------------------------------- // // Member: CRegKey::CreateKey, private // // Synopsis: This method does the real work of the constructors. // // Arguments: [hkParent] - handle to parent key // [pwszPath] - pathname to key // [samDesiredAccess] - desired access rights to the key // [pwszClass] - class for the key // [dwOptions] - options for the key eg volatile or not // [pdwDisposition] - to find out if key was opened or created // [pSecurityAttributes] - used only if the key is created // // Signals: -none- // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/92 Rickhi Created // // Notes: All parameters are required. // //-------------------------------------------------------------------------- DWORD CRegKey::CreateKey ( HKEY hkParent, const LPWSTR pwszPath, REGSAM samDesiredAccess, const LPWSTR pwszClass, DWORD dwOptions, DWORD *pdwDisposition, const LPSECURITY_ATTRIBUTES pSecurityAttributes ) { DWORD dwDisposition; DWORD dwRc; DWORD dwErr = ERROR_SUCCESS; LPSECURITY_ATTRIBUTES lpsec = pSecurityAttributes; // create/open the key if ((dwRc = RegCreateKeyEx(hkParent, pwszPath, // path to key 0, // title index pwszClass, // class of key dwOptions, // key options samDesiredAccess, // desired access lpsec, // if created &_hkThis, // handle &dwDisposition) // opened/created )==ERROR_SUCCESS) { // save away the name _cwszName.Set(pwszPath); // setup the return parameters if (pdwDisposition != NULL) *pdwDisposition = dwDisposition; } else dwErr = Creg_ERROR(dwRc); return(dwErr); } //+------------------------------------------------------------------------- // // Member: CRegKey::OpenKey, private // // Synopsis: This method does the real work of the constructors. // // Arguments: [hkParent] - handle to parent key // [pwszPath] - pathname to key // [samDesiredAccess] - desired access rights to the key // // Signals: -none- // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/22/93 AlokS Created // // Notes: All parameters are required. // //-------------------------------------------------------------------------- DWORD CRegKey::OpenKey ( HKEY hkParent, const LPWSTR pwszPath, REGSAM samDesiredAccess ) { DWORD dwRc; DWORD dwErr = ERROR_SUCCESS; // open the key if ((dwRc = RegOpenKeyEx(hkParent, pwszPath, // path to key 0, // reserved samDesiredAccess, // desired access &_hkThis // handle ))==ERROR_SUCCESS) { // save away the name _cwszName.Set(pwszPath); } else dwErr = Creg_ERROR(dwRc); return(dwErr); } //+------------------------------------------------------------------------- // // Member: CRegKey::Delete, public // // Synopsis: Deletes an existing key from the registry. Note that // the key object still exists, the destructor must be // called seperately. // // Arguments: none // // Signals: -none- // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/92 Rickhi Created // // Notes: // //-------------------------------------------------------------------------- DWORD CRegKey::Delete(void) { DWORD dwErr = ERROR_SUCCESS; DWORD dwRc; SRegKeySet *pChildren; dwErr = this->EnumKeys(&pChildren); if (dwErr == ERROR_SUCCESS) { ULONG i; DWORD dwErrDelete = ERROR_SUCCESS; for(i = 0; i < pChildren->cKeys; i++) { dwErr = pChildren->aprkKey[i]->Delete(); if (dwErr != ERROR_SUCCESS) { dwErrDelete = dwErr; } delete pChildren->aprkKey[i]; } if (dwErrDelete == ERROR_SUCCESS) { if (( dwRc= RegDeleteKey(_hkThis, NULL))!=ERROR_SUCCESS) { dwErr = Creg_ERROR(dwRc); } } else { dwErr = dwErrDelete; } delete pChildren; } return(dwErr); } //+------------------------------------------------------------------------- // // Member: CRegKey::EnumValues, public // // Synopsis: Enumerates the values stored in an open registry key. // // Arguments: [pprvs] - SRegValueSet allocated and returned by this // method. The caller is responsible for releasing // the allocated CRegValue objects via delete and the // SRegValueSet structure via CRegKey::MemFree. // // Signals: none // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/92 Rickhi Created // // Notes: The data associated with each Value is not returned. The // caller may invoke the GetValue method of each CRegValue // returned to get it's associated data. // //-------------------------------------------------------------------------- DWORD CRegKey::EnumValues(SRegValueSet **pprvs) { DWORD dwErr = ERROR_SUCCESS; // figure out how many values are currently stored in this key // and allocate a buffer to hold the return results. WCHAR wszClass[MAX_PATH]; ULONG cbClass = sizeof(wszClass); ULONG cSubKeys, cbMaxSubKeyLen, cbMaxClassLen; ULONG cValues, cbMaxValueIDLen, cbMaxValueLen; SECURITY_DESCRIPTOR SecDescriptor; FILETIME ft; DWORD dwRc = RegQueryInfoKey(_hkThis, wszClass, &cbClass, NULL, &cSubKeys, &cbMaxSubKeyLen, &cbMaxClassLen, &cValues, &cbMaxValueIDLen, &cbMaxValueLen, (DWORD *)&SecDescriptor, &ft ); if ( dwRc == ERROR_SUCCESS ) { *pprvs = (SRegValueSet *) new BYTE [ sizeof(SRegValueSet)+ cValues*sizeof(CRegValue *) ]; if ( *pprvs == NULL ) { dwErr = ERROR_OUTOFMEMORY; } } else { // QueryInfo failed. dwErr = Creg_ERROR(dwRc); } if (dwErr != ERROR_SUCCESS) { return(dwErr); } // loop enumerating and creating a RegValue object for each value DWORD dwIndex=0; do { WCHAR wszValueID[MAX_PATH]; ULONG cbValueID = MAX_PATH; DWORD dwTypeCode; CRegValue *pRegVal; if ((dwRc = RegEnumValue(_hkThis, // handle dwIndex, // index wszValueID, // value id &cbValueID, // length of value name NULL, // title index &dwTypeCode, // data type NULL, // data buffer NULL // size of data buffer ))==ERROR_SUCCESS) { // create the appropriate class of value object switch (dwTypeCode) { case REG_SZ: pRegVal = (CRegValue *) new CRegSZ((const CRegKey &)*this, wszValueID); break; case REG_DWORD: pRegVal = (CRegValue *) new CRegDWORD((const CRegKey &)*this, wszValueID); break; case REG_BINARY: pRegVal = (CRegValue *) new CRegBINARY((const CRegKey &)*this, wszValueID); break; default: pRegVal = (CRegValue *) new CRegBINARY((const CRegKey &)*this, wszValueID); break; } // save ptr to value object and count another entry (*pprvs)->aprvValue[dwIndex++] = pRegVal; } else { // error, we're done with the enumeration break; } } while (dwIndex < cValues); // finished the enumeration, check the results if (dwRc == ERROR_NO_MORE_ITEMS || dwRc == ERROR_SUCCESS) { // set the return count (*pprvs)->cValues = dwIndex; } else { // Cleanup and return an error while (dwIndex) { delete (*pprvs)->aprvValue[--dwIndex]; } delete [] *pprvs; dwErr = Creg_ERROR(dwRc); } return(dwErr); } //+------------------------------------------------------------------------- // // Member: CRegKey::EnumKeys, public // // Synopsis: Enumerates the subkeys of an open registry key. // // Arguments: [pprks] - SRegKeySet allocated and returned by this method. // The caller is responsible for releasing all the // allocated CRegKey objects and the SRegKeySet // structure. // // Signals: none // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/92 Rickhi Created // // Notes: // //-------------------------------------------------------------------------- DWORD CRegKey::EnumKeys(SRegKeySet **pprks) { // figure out how many keys are currently stored in this key // and allocate a buffer to hold the return results. WCHAR wszClass[MAX_PATH]; ULONG cbClass = sizeof(wszClass); ULONG cSubKeys, cbMaxSubKeyLen, cbMaxClassLen; ULONG cValues, cbMaxValueIDLen, cbMaxValueLen; SECURITY_DESCRIPTOR SecDescriptor; FILETIME ft; DWORD dwErr = ERROR_SUCCESS; DWORD dwRc = RegQueryInfoKey(_hkThis, wszClass, &cbClass, NULL, &cSubKeys, &cbMaxSubKeyLen, &cbMaxClassLen, &cValues, &cbMaxValueIDLen, &cbMaxValueLen, (DWORD *)&SecDescriptor, &ft); if ( dwRc == ERROR_SUCCESS ) { *pprks = (SRegKeySet*) new BYTE [sizeof(SRegKeySet)+cSubKeys*sizeof(CRegKey *)]; if ( *pprks == NULL ) { dwErr = ERROR_OUTOFMEMORY; } } else { // QueryInfo failed.. dwErr = Creg_ERROR(dwRc); } if (dwErr != ERROR_SUCCESS) { return(dwErr); } // loop enumerating and creating a RegKey object for each subkey DWORD dwIndex=0; do { WCHAR wszKeyName[MAX_PATH]; ULONG cbKeyName = MAX_PATH; WCHAR wszClass[MAX_PATH]; ULONG cbClass = MAX_PATH; FILETIME ft; if ((dwRc = RegEnumKeyEx(_hkThis, // handle dwIndex, // index wszKeyName, // key name &cbKeyName, // length of key name NULL, // title index wszClass, // class &cbClass, // length of class &ft // last write time ))==ERROR_SUCCESS) { // Create a CRegKey object for the subkey CRegKey *pRegKey = (CRegKey *) new CRegKey((const CRegKey &)*this, wszKeyName); // bug 447481: check for null return from above. if (pRegKey == NULL) { dwErr = ERROR_OUTOFMEMORY; break; } if (ERROR_SUCCESS != (dwErr = pRegKey->QueryErrorStatus())) { break; } (*pprks)->aprkKey[dwIndex++] = pRegKey; } else { // error, we're done with the enumeration break; } } while (dwIndex < cSubKeys); // finished the enumeration, check the results if ((dwErr == ERROR_SUCCESS) && ((dwRc == ERROR_NO_MORE_ITEMS || dwRc == ERROR_SUCCESS))) { // set the return count (*pprks)->cKeys = dwIndex; } else { // Cleanup and return an error while (dwIndex) { delete (*pprks)->aprkKey[--dwIndex]; } delete [] *pprks; dwErr = Creg_ERROR(dwRc); } return(dwErr); } //+------------------------------------------------------------------------- // // Member: CRegValue::GetValue, public // // Purpose: Returns the data associated with a registry value. // // Arguements: [pbData] - ptr to buffer supplied by caller. // [cbData] - size of data buffer supplied. // [pdwTypeCode] - type of data returned. // // Signals: // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/92 Rickhi Created // // Notes: // // // //-------------------------------------------------------------------------- DWORD CRegValue::GetValue(LPBYTE pbData, ULONG* pcbData, DWORD *pdwTypeCode) { DWORD dwRc = RegQueryValueEx(GetParentHandle(), (LPWSTR)_cwszValueID, // value id NULL, // title index pdwTypeCode, // type of data returned pbData, // data pcbData); // size of data return(dwRc); } //+------------------------------------------------------------------------- // // Member: CRegValue::SetValue // // Purpose: Writes the data associated with a registry value. // // Arguements: [pbData] - ptr to data to write. // [cbData] - size of data to write. // [dwTypeCode] - type of data to write. // // Signals: -none- // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/92 Rickhi Created // // Notes: // //-------------------------------------------------------------------------- DWORD CRegValue::SetValue(const LPBYTE pbData, ULONG cbData, DWORD dwTypeCode) { DWORD dwRc; DWORD dwErr = ERROR_SUCCESS; if ((dwRc = RegSetValueEx(GetParentHandle(), // key handle (LPWSTR)_cwszValueID, // value id NULL, // title index dwTypeCode, // type of info in buffer pbData, // data cbData) // size of data )!= ERROR_SUCCESS) { dwErr = Creg_ERROR(dwRc); } return(dwErr); } //+------------------------------------------------------------------------- // // Function: DelRegKeyTree // // Purpose: Deletes a key and any of it's children. This is like // delnode for registry // // Arguements: [hParent] - Handle to Parent Key // [lpwszKeyPath] - Path (relative to Parent) of the key // // Signals: // // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs // or from Memory allocation // // History: 09/30/93 AlokS Created // // Notes: // //-------------------------------------------------------------------------- DWORD DelRegKeyTree ( HKEY hParent, LPWSTR lpwszKeyPath) { DWORD dwErr = ERROR_SUCCESS; CRegKey cregKey ( hParent, lpwszKeyPath ); if (ERROR_SUCCESS != (dwErr = cregKey.QueryErrorStatus())) { return(dwErr); } // Enumerate the children of the key. We will // not propogate to the caller errors from enumeration SRegKeySet *pRegKeySet = NULL; if (ERROR_SUCCESS == (dwErr = cregKey.EnumKeys ( & pRegKeySet))) { // Now we have set of Keys which need to be deleted in depth // first manner for (ULONG i = 0; i < pRegKeySet->cKeys; i++ ) { dwErr = DelRegKeyTree ( cregKey.GetHandle(), pRegKeySet->aprkKey[i]->GetName() ); // Delete the key itself delete pRegKeySet->aprkKey[i]; } // Delete the enumerator structure delete pRegKeySet; } // Finally delete this key dwErr = cregKey.Delete(); return(dwErr); } DWORD CRegKey::DeleteChildren() { // figure out how many keys are currently stored in this key ULONG cSubKeys, cbMaxSubKeyLen; DWORD dwErr = ERROR_SUCCESS; DWORD dwRc = RegQueryInfoKey(_hkThis, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKeyLen, NULL, NULL, NULL, NULL, NULL, NULL); if ( dwRc != ERROR_SUCCESS ) { // QueryInfo failed.. dwErr = Creg_ERROR(dwRc); } if (dwErr != ERROR_SUCCESS) { return(dwErr); } // loop enumerating and creating a RegKey object for each subkey DWORD dwIndex=0; do { WCHAR wszKeyName[MAX_PATH]; ULONG cbKeyName = sizeof(wszKeyName); FILETIME ft; if ((dwRc = RegEnumKeyEx(_hkThis, // handle dwIndex, // index wszKeyName, // key name &cbKeyName, // length of key name NULL, // title index NULL, // class NULL, // length of class &ft // last write time ))==ERROR_SUCCESS) { // Create a CRegKey object for the subkey CRegKey *pRegKey = (CRegKey *) new CRegKey((const CRegKey &)*this, wszKeyName); if (ERROR_SUCCESS != (dwErr = pRegKey->QueryErrorStatus())) { break; } pRegKey->DeleteChildren(); delete pRegKey; dwRc = RegDeleteKey(_hkThis, wszKeyName); } else { // error, we're done with the enumeration break; } } while (dwIndex < cSubKeys); // finished the enumeration, check the results if ((dwErr == ERROR_SUCCESS) && (dwRc != ERROR_NO_MORE_ITEMS && dwRc != ERROR_SUCCESS)) { dwErr = Creg_ERROR(dwRc); } return(dwErr); }