Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

816 lines
25 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1992, Microsoft Corporation.
  4. //
  5. // File: registry.cxx
  6. //
  7. // Contents: implementations for CRegKey member Members
  8. //
  9. // Members: CRegKey::CRegKey - constructor for registry key object
  10. // CRegKey::CRegKey - constructor for registry key object
  11. // CRegKey::CreateKey - real worker for constructors
  12. // CRegKey::~CRegKey - destructor for registry key object
  13. // CRegKey::Delete - delete a registry key
  14. // CRegKey::EnumValues - enumerate values of a registry key
  15. // CRegKey::EnumKeys - enumerate subkeys of a registry key
  16. // CRegKey::NotifyChange - setup change notification for a key
  17. //
  18. // CRegValue::GetValue - sets a registry value
  19. // CRegValue::SetValue - retrieves a registry value
  20. // CRegValue::Delete - deletes a registry value
  21. // CRegValue::GetTypeCode - returns the type code of the value
  22. //
  23. // CRegMSZ::SetStrings - sets a multi-string registry value
  24. // CRegMSZ::GetStrings - retrieves a multi-string registry value
  25. //
  26. // History: 09/30/92 Rickhi Created
  27. //
  28. // 09/22/93 AlokS Took out exception throwing code
  29. // and added proper return code for
  30. // each method.
  31. //
  32. // 07/26/94 AlokS Made it real light weight for simple
  33. // registry set/get operations
  34. //
  35. // 12/09/07 Milans Ported it over to Exchange
  36. //
  37. // Notes: see notes in registry.h
  38. //
  39. //----------------------------------------------------------------------------
  40. #include "smtpinc.h"
  41. #include "registry.h"
  42. //+-------------------------------------------------------------------------
  43. //
  44. // Member: CRegKey::CRegKey
  45. //
  46. // Synopsis: Constructor for registry key object, using HKEY for parent
  47. //
  48. // Arguments: [hkParent] - handle to parent key
  49. // [pszPath] - pathname to key
  50. // [samDesiredAccess] - desired access rights to the key
  51. // [pszClass] - class for the key
  52. // [dwOptions] - options for the key eg volatile or not
  53. // [pdwDisposition] - to find out if key was opened or created
  54. // [pSecurityAttributes] - used only if the key is created
  55. // [fThrowExceptionOnError] - Constructor throw exception on error
  56. //
  57. // Signals: Internal error state is set if construction fails.
  58. //
  59. // Returns: -none-
  60. //
  61. // History: 09/30/92 Rickhi Created
  62. //
  63. // Notes: All except the hkParent and pszPath are optional parameters.
  64. //
  65. //--------------------------------------------------------------------------
  66. CRegKey::CRegKey (
  67. HKEY hkParent,
  68. LPCSTR pszPath,
  69. REGSAM samDesiredAccess,
  70. LPCSTR pszClass,
  71. DWORD dwOptions,
  72. DWORD *pdwDisposition,
  73. const LPSECURITY_ATTRIBUTES pSecurityAttributes )
  74. :_hkParent(hkParent),
  75. _hkThis(NULL),
  76. _dwErr (ERROR_SUCCESS)
  77. {
  78. _dwErr = CreateKey( _hkParent,
  79. pszPath,
  80. samDesiredAccess,
  81. pszClass,
  82. dwOptions,
  83. pdwDisposition,
  84. pSecurityAttributes );
  85. }
  86. //+-------------------------------------------------------------------------
  87. //
  88. // Member: CRegKey::CRegKey
  89. //
  90. // Synopsis: Constructor for registry key object, using CRegKey for parent
  91. //
  92. // Arguments: [prkParent] - ptr to Parent CRegKey
  93. // [pszPath] - pathname to key
  94. // [samDesiredAccess] - desired access rights to the key
  95. // [pszClass] - class for the key
  96. // [dwOptions] - options for the key eg volatile or not
  97. // [pdwDisposition] - to find out if key was opened or created
  98. // [pSecurityAttributes] - used only if the key is created
  99. // [fThrowExceptionOnError] - Constructor throw exception on error
  100. //
  101. // Signals: Internal Error state is set if error occures during construction.
  102. //
  103. // Returns: nothing
  104. //
  105. // History: 09/30/92 Rickhi Created
  106. //
  107. // Notes: All except the prkParent and pszPath are optional parameters.
  108. //
  109. //--------------------------------------------------------------------------
  110. CRegKey::CRegKey (
  111. const CRegKey &crkParent,
  112. LPCSTR pszPath,
  113. REGSAM samDesiredAccess,
  114. LPCSTR pszClass,
  115. DWORD dwOptions,
  116. DWORD *pdwDisposition,
  117. const LPSECURITY_ATTRIBUTES pSecurityAttributes )
  118. :_hkParent(crkParent.GetHandle()),
  119. _hkThis(NULL),
  120. _dwErr(ERROR_SUCCESS)
  121. {
  122. _dwErr = CreateKey ( _hkParent,
  123. pszPath,
  124. samDesiredAccess,
  125. pszClass,
  126. dwOptions,
  127. pdwDisposition,
  128. pSecurityAttributes );
  129. }
  130. //+-------------------------------------------------------------------------
  131. //
  132. // Member: CRegKey::CRegKey
  133. //
  134. // Synopsis: Constructor for registry key object, using HKEY for parent
  135. // Merely opens the key, if exist
  136. //
  137. // Arguments: [hkParent] - HKEY to Parent
  138. // [dwErr] - Error code returned here
  139. // [pszPath] - pathname to key
  140. // [samDesiredAccess] - desired access rights to the key
  141. //
  142. // Signals: Internal Error state is set if error occures during construction
  143. //
  144. // Returns: nothing
  145. //
  146. // History: 09/22/93 AlokS Created
  147. //
  148. // Notes: Check error status to determine if constructor succeeded
  149. //
  150. //--------------------------------------------------------------------------
  151. CRegKey::CRegKey (
  152. HKEY hkParent,
  153. DWORD *pdwErr,
  154. LPCSTR pszPath,
  155. REGSAM samDesiredAccess )
  156. :_hkParent(hkParent),
  157. _hkThis(NULL),
  158. _dwErr(ERROR_SUCCESS)
  159. {
  160. *pdwErr = _dwErr = OpenKey ( _hkParent, pszPath, samDesiredAccess );
  161. }
  162. //+-------------------------------------------------------------------------
  163. //
  164. // Member: CRegKey::CRegKey
  165. //
  166. // Synopsis: Constructor for registry key object, using CRegKey for parent
  167. // Merely opens the key, if exist
  168. //
  169. // Arguments: [prkParent] - ptr to Parent CRegKey
  170. // [dwErr] - Error code returned here.
  171. // [pszPath] - pathname to key
  172. // [samDesiredAccess] - desired access rights to the key
  173. //
  174. // Signals: Internal Error state is set if error occures during construction
  175. //
  176. // Returns: nothing
  177. //
  178. // History: 09/22/93 AlokS Created
  179. //
  180. // Notes: Check error status to determine if constructor succeeded
  181. //
  182. //--------------------------------------------------------------------------
  183. CRegKey::CRegKey (
  184. const CRegKey &crkParent,
  185. DWORD *pdwErr,
  186. LPCSTR pszPath,
  187. REGSAM samDesiredAccess )
  188. :_hkParent(crkParent.GetHandle()),
  189. _hkThis(NULL),
  190. _dwErr(ERROR_SUCCESS)
  191. {
  192. *pdwErr = _dwErr = OpenKey ( _hkParent, pszPath, samDesiredAccess );
  193. }
  194. //+-------------------------------------------------------------------------
  195. //
  196. // Member: CRegKey::~CRegKey, public
  197. //
  198. // Synopsis: Destructor for registry key object
  199. //
  200. // Arguments: none
  201. //
  202. // Signals: nothing
  203. //
  204. // Returns: nothing
  205. //
  206. // History: 09/30/92 Rickhi Created
  207. //
  208. // Notes:
  209. //
  210. //--------------------------------------------------------------------------
  211. CRegKey::~CRegKey()
  212. {
  213. if (_hkThis != NULL)
  214. RegCloseKey(_hkThis);
  215. }
  216. //+-------------------------------------------------------------------------
  217. //
  218. // Member: CRegKey::CreateKey, private
  219. //
  220. // Synopsis: This method does the real work of the constructors.
  221. //
  222. // Arguments: [hkParent] - handle to parent key
  223. // [pszPath] - pathname to key
  224. // [samDesiredAccess] - desired access rights to the key
  225. // [pszClass] - class for the key
  226. // [dwOptions] - options for the key eg volatile or not
  227. // [pdwDisposition] - to find out if key was opened or created
  228. // [pSecurityAttributes] - used only if the key is created
  229. //
  230. // Signals: -none-
  231. //
  232. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  233. // or from Memory allocation
  234. //
  235. // History: 09/30/92 Rickhi Created
  236. //
  237. // Notes: All parameters are required.
  238. //
  239. //--------------------------------------------------------------------------
  240. DWORD CRegKey::CreateKey (
  241. HKEY hkParent,
  242. LPCSTR pszPath,
  243. REGSAM samDesiredAccess,
  244. LPCSTR pszClass,
  245. DWORD dwOptions,
  246. DWORD *pdwDisposition,
  247. const LPSECURITY_ATTRIBUTES pSecurityAttributes )
  248. {
  249. DWORD dwDisposition;
  250. DWORD dwRc;
  251. DWORD dwErr = ERROR_SUCCESS;
  252. LPSECURITY_ATTRIBUTES lpsec = pSecurityAttributes;
  253. // create/open the key
  254. if ((dwRc = RegCreateKeyEx(hkParent,
  255. (LPSTR) pszPath, // path to key
  256. 0, // title index
  257. (LPSTR) pszClass, // class of key
  258. dwOptions, // key options
  259. samDesiredAccess, // desired access
  260. lpsec, // if created
  261. &_hkThis, // handle
  262. &dwDisposition) // opened/created
  263. )==ERROR_SUCCESS)
  264. {
  265. // save away the name
  266. _cszName.Set((PCHAR) pszPath);
  267. // setup the return parameters
  268. if (pdwDisposition != NULL)
  269. *pdwDisposition = dwDisposition;
  270. }
  271. else
  272. dwErr = Creg_ERROR(dwRc);
  273. return(dwErr);
  274. }
  275. //+-------------------------------------------------------------------------
  276. //
  277. // Member: CRegKey::OpenKey, private
  278. //
  279. // Synopsis: This method does the real work of the constructors.
  280. //
  281. // Arguments: [hkParent] - handle to parent key
  282. // [pszPath] - pathname to key
  283. // [samDesiredAccess] - desired access rights to the key
  284. //
  285. // Signals: -none-
  286. //
  287. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  288. // or from Memory allocation
  289. //
  290. // History: 09/22/93 AlokS Created
  291. //
  292. // Notes: All parameters are required.
  293. //
  294. //--------------------------------------------------------------------------
  295. DWORD CRegKey::OpenKey (
  296. HKEY hkParent,
  297. LPCSTR pszPath,
  298. REGSAM samDesiredAccess )
  299. {
  300. DWORD dwRc;
  301. DWORD dwErr = ERROR_SUCCESS;
  302. // open the key
  303. if ((dwRc = RegOpenKeyEx(hkParent,
  304. pszPath, // path to key
  305. 0, // reserved
  306. samDesiredAccess, // desired access
  307. &_hkThis // handle
  308. ))==ERROR_SUCCESS)
  309. {
  310. // save away the name
  311. _cszName.Set((PCHAR) pszPath);
  312. }
  313. else
  314. dwErr = Creg_ERROR(dwRc);
  315. return(dwErr);
  316. }
  317. //+-------------------------------------------------------------------------
  318. //
  319. // Member: CRegKey::Delete, public
  320. //
  321. // Synopsis: Deletes an existing key from the registry. Note that
  322. // the key object still exists, the destructor must be
  323. // called seperately.
  324. //
  325. // Arguments: none
  326. //
  327. // Signals: -none-
  328. //
  329. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  330. // or from Memory allocation
  331. //
  332. // History: 09/30/92 Rickhi Created
  333. //
  334. // Notes:
  335. //
  336. //--------------------------------------------------------------------------
  337. DWORD CRegKey::Delete(void)
  338. {
  339. DWORD dwErr = ERROR_SUCCESS;
  340. DWORD dwRc;
  341. SRegKeySet *pChildren;
  342. dwErr = this->EnumKeys(&pChildren);
  343. if (dwErr == ERROR_SUCCESS) {
  344. ULONG i;
  345. DWORD dwErrDelete = ERROR_SUCCESS;
  346. for(i = 0; i < pChildren->cKeys; i++) {
  347. dwErr = pChildren->aprkKey[i]->Delete();
  348. if (dwErr != ERROR_SUCCESS) {
  349. dwErrDelete = dwErr;
  350. }
  351. delete pChildren->aprkKey[i];
  352. }
  353. if (dwErrDelete == ERROR_SUCCESS) {
  354. if (( dwRc= RegDeleteKey(_hkThis, NULL))!=ERROR_SUCCESS) {
  355. dwErr = Creg_ERROR(dwRc);
  356. }
  357. } else {
  358. dwErr = dwErrDelete;
  359. }
  360. delete pChildren;
  361. }
  362. return(dwErr);
  363. }
  364. //+-------------------------------------------------------------------------
  365. //
  366. // Member: CRegKey::EnumValues, public
  367. //
  368. // Synopsis: Enumerates the values stored in an open registry key.
  369. //
  370. // Arguments: [pprvs] - SRegValueSet allocated and returned by this
  371. // method. The caller is responsible for releasing
  372. // the allocated CRegValue objects via delete and the
  373. // SRegValueSet structure via CRegKey::MemFree.
  374. //
  375. // Signals: none
  376. //
  377. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  378. // or from Memory allocation
  379. //
  380. // History: 09/30/92 Rickhi Created
  381. //
  382. // Notes: The data associated with each Value is not returned. The
  383. // caller may invoke the GetValue method of each CRegValue
  384. // returned to get it's associated data.
  385. //
  386. //--------------------------------------------------------------------------
  387. DWORD CRegKey::EnumValues(SRegValueSet **pprvs)
  388. {
  389. DWORD dwErr = ERROR_SUCCESS;
  390. // figure out how many values are currently stored in this key
  391. // and allocate a buffer to hold the return results.
  392. CHAR szClass[MAX_PATH];
  393. ULONG cbClass = sizeof(szClass);
  394. ULONG cSubKeys, cbMaxSubKeyLen, cbMaxClassLen;
  395. ULONG cValues, cbMaxValueIDLen, cbMaxValueLen;
  396. SECURITY_DESCRIPTOR SecDescriptor;
  397. FILETIME ft;
  398. DWORD dwRc = RegQueryInfoKey(_hkThis,
  399. szClass,
  400. &cbClass,
  401. NULL,
  402. &cSubKeys,
  403. &cbMaxSubKeyLen,
  404. &cbMaxClassLen,
  405. &cValues,
  406. &cbMaxValueIDLen,
  407. &cbMaxValueLen,
  408. (DWORD *)&SecDescriptor,
  409. &ft );
  410. if ( dwRc == ERROR_SUCCESS )
  411. {
  412. *pprvs = (SRegValueSet *) new BYTE [ sizeof(SRegValueSet)+
  413. cValues*sizeof(CRegValue *) ];
  414. if ( *pprvs == NULL )
  415. {
  416. dwErr = ERROR_OUTOFMEMORY;
  417. }
  418. }
  419. else
  420. {
  421. // QueryInfo failed.
  422. dwErr = Creg_ERROR(dwRc);
  423. }
  424. if (dwErr != ERROR_SUCCESS)
  425. {
  426. return(dwErr);
  427. }
  428. // loop enumerating and creating a RegValue object for each value
  429. DWORD dwIndex=0;
  430. do
  431. {
  432. CHAR szValueID[MAX_PATH];
  433. ULONG cbValueID = sizeof(szValueID);
  434. DWORD dwTypeCode;
  435. CRegValue *pRegVal;
  436. if ((dwRc = RegEnumValue(_hkThis, // handle
  437. dwIndex, // index
  438. szValueID, // value id
  439. &cbValueID, // length of value name
  440. NULL, // title index
  441. &dwTypeCode, // data type
  442. NULL, // data buffer
  443. NULL // size of data buffer
  444. ))==ERROR_SUCCESS)
  445. {
  446. // create the appropriate class of value object
  447. switch (dwTypeCode)
  448. {
  449. case REG_SZ:
  450. pRegVal = (CRegValue *) new CRegSZ((const CRegKey &)*this, szValueID);
  451. break;
  452. case REG_DWORD:
  453. pRegVal = (CRegValue *) new CRegDWORD((const CRegKey &)*this, szValueID);
  454. break;
  455. case REG_BINARY:
  456. pRegVal = (CRegValue *) new CRegBINARY((const CRegKey &)*this, szValueID);
  457. break;
  458. default:
  459. pRegVal = (CRegValue *) new CRegBINARY((const CRegKey &)*this, szValueID);
  460. break;
  461. }
  462. // save ptr to value object and count another entry
  463. (*pprvs)->aprvValue[dwIndex++] = pRegVal;
  464. }
  465. else
  466. {
  467. // error, we're done with the enumeration
  468. break;
  469. }
  470. } while (dwIndex < cValues);
  471. // finished the enumeration, check the results
  472. if (dwRc == ERROR_NO_MORE_ITEMS || dwRc == ERROR_SUCCESS)
  473. {
  474. // set the return count
  475. (*pprvs)->cValues = dwIndex;
  476. }
  477. else
  478. {
  479. // Cleanup and return an error
  480. while (dwIndex)
  481. {
  482. delete (*pprvs)->aprvValue[--dwIndex];
  483. }
  484. delete [] *pprvs;
  485. dwErr = Creg_ERROR(dwRc);
  486. }
  487. return(dwErr);
  488. }
  489. //+-------------------------------------------------------------------------
  490. //
  491. // Member: CRegKey::EnumKeys, public
  492. //
  493. // Synopsis: Enumerates the subkeys of an open registry key.
  494. //
  495. // Arguments: [pprks] - SRegKeySet allocated and returned by this method.
  496. // The caller is responsible for releasing all the
  497. // allocated CRegKey objects and the SRegKeySet
  498. // structure.
  499. //
  500. // Signals: none
  501. //
  502. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  503. // or from Memory allocation
  504. //
  505. // History: 09/30/92 Rickhi Created
  506. //
  507. // Notes:
  508. //
  509. //--------------------------------------------------------------------------
  510. DWORD CRegKey::EnumKeys(SRegKeySet **pprks)
  511. {
  512. // figure out how many keys are currently stored in this key
  513. // and allocate a buffer to hold the return results.
  514. CHAR szClass[MAX_PATH];
  515. ULONG cbClass = sizeof(szClass);
  516. ULONG cSubKeys, cbMaxSubKeyLen, cbMaxClassLen;
  517. ULONG cValues, cbMaxValueIDLen, cbMaxValueLen;
  518. SECURITY_DESCRIPTOR SecDescriptor;
  519. FILETIME ft;
  520. DWORD dwErr = ERROR_SUCCESS;
  521. DWORD dwRc = RegQueryInfoKey(_hkThis,
  522. szClass,
  523. &cbClass,
  524. NULL,
  525. &cSubKeys,
  526. &cbMaxSubKeyLen,
  527. &cbMaxClassLen,
  528. &cValues,
  529. &cbMaxValueIDLen,
  530. &cbMaxValueLen,
  531. (DWORD *)&SecDescriptor,
  532. &ft);
  533. if ( dwRc == ERROR_SUCCESS )
  534. {
  535. *pprks = (SRegKeySet*) new BYTE [sizeof(SRegKeySet)+cSubKeys*sizeof(CRegKey *)];
  536. if ( *pprks == NULL )
  537. {
  538. dwErr = ERROR_OUTOFMEMORY;
  539. }
  540. }
  541. else
  542. {
  543. // QueryInfo failed..
  544. dwErr = Creg_ERROR(dwRc);
  545. }
  546. if (dwErr != ERROR_SUCCESS)
  547. {
  548. return(dwErr);
  549. }
  550. // loop enumerating and creating a RegKey object for each subkey
  551. DWORD dwIndex=0;
  552. do
  553. {
  554. CHAR szKeyName[MAX_PATH];
  555. ULONG cbKeyName = sizeof(szKeyName);
  556. CHAR szClass[MAX_PATH];
  557. ULONG cbClass = sizeof(szClass);
  558. FILETIME ft;
  559. if ((dwRc = RegEnumKeyEx(_hkThis, // handle
  560. dwIndex, // index
  561. szKeyName, // key name
  562. &cbKeyName, // length of key name
  563. NULL, // title index
  564. szClass, // class
  565. &cbClass, // length of class
  566. &ft // last write time
  567. ))==ERROR_SUCCESS)
  568. {
  569. // Create a CRegKey object for the subkey
  570. CRegKey *pRegKey = (CRegKey *) new CRegKey((const CRegKey &)*this, szKeyName);
  571. if (ERROR_SUCCESS != (dwErr = pRegKey->QueryErrorStatus()))
  572. {
  573. break;
  574. }
  575. (*pprks)->aprkKey[dwIndex++] = pRegKey;
  576. }
  577. else
  578. {
  579. // error, we're done with the enumeration
  580. break;
  581. }
  582. } while (dwIndex < cSubKeys);
  583. // finished the enumeration, check the results
  584. if ((dwErr == ERROR_SUCCESS) &&
  585. ((dwRc == ERROR_NO_MORE_ITEMS || dwRc == ERROR_SUCCESS)))
  586. {
  587. // set the return count
  588. (*pprks)->cKeys = dwIndex;
  589. }
  590. else
  591. {
  592. // Cleanup and return an error
  593. while (dwIndex)
  594. {
  595. delete (*pprks)->aprkKey[--dwIndex];
  596. }
  597. delete [] *pprks;
  598. dwErr = Creg_ERROR(dwRc);
  599. }
  600. return(dwErr);
  601. }
  602. //+-------------------------------------------------------------------------
  603. //
  604. // Member: CRegValue::GetValue, public
  605. //
  606. // Purpose: Returns the data associated with a registry value.
  607. //
  608. // Arguements: [pbData] - ptr to buffer supplied by caller.
  609. // [cbData] - size of data buffer supplied.
  610. // [pdwTypeCode] - type of data returned.
  611. //
  612. // Signals:
  613. //
  614. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  615. // or from Memory allocation
  616. //
  617. // History: 09/30/92 Rickhi Created
  618. //
  619. // Notes:
  620. //
  621. //
  622. //
  623. //--------------------------------------------------------------------------
  624. DWORD CRegValue::GetValue(LPBYTE pbData, ULONG* pcbData, DWORD *pdwTypeCode)
  625. {
  626. DWORD dwRc = RegQueryValueEx(GetParentHandle(),
  627. (LPSTR)_cszValueID, // value id
  628. NULL, // title index
  629. pdwTypeCode, // type of data returned
  630. pbData, // data
  631. pcbData); // size of data
  632. return(dwRc);
  633. }
  634. //+-------------------------------------------------------------------------
  635. //
  636. // Member: CRegValue::SetValue
  637. //
  638. // Purpose: Writes the data associated with a registry value.
  639. //
  640. // Arguements: [pbData] - ptr to data to write.
  641. // [cbData] - size of data to write.
  642. // [dwTypeCode] - type of data to write.
  643. //
  644. // Signals: -none-
  645. //
  646. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  647. // or from Memory allocation
  648. //
  649. // History: 09/30/92 Rickhi Created
  650. //
  651. // Notes:
  652. //
  653. //--------------------------------------------------------------------------
  654. DWORD CRegValue::SetValue(const LPBYTE pbData, ULONG cbData, DWORD dwTypeCode)
  655. {
  656. DWORD dwRc;
  657. DWORD dwErr = ERROR_SUCCESS;
  658. if ((dwRc = RegSetValueEx(GetParentHandle(), // key handle
  659. (LPSTR)_cszValueID, // value id
  660. NULL, // title index
  661. dwTypeCode, // type of info in buffer
  662. pbData, // data
  663. cbData) // size of data
  664. )!= ERROR_SUCCESS)
  665. {
  666. dwErr = Creg_ERROR(dwRc);
  667. }
  668. return(dwErr);
  669. }
  670. //+-------------------------------------------------------------------------
  671. //
  672. // Function: DelRegKeyTree
  673. //
  674. // Purpose: Deletes a key and any of it's children. This is like
  675. // delnode for registry
  676. //
  677. // Arguements: [hParent] - Handle to Parent Key
  678. // [lpszKeyPath] - Path (relative to Parent) of the key
  679. //
  680. // Signals:
  681. //
  682. // Returns: ERROR_SUCCESS on success. Else error from either Registry APIs
  683. // or from Memory allocation
  684. //
  685. // History: 09/30/93 AlokS Created
  686. //
  687. // Notes:
  688. //
  689. //--------------------------------------------------------------------------
  690. DWORD DelRegKeyTree ( HKEY hParent, LPSTR lpszKeyPath)
  691. {
  692. DWORD dwErr = ERROR_SUCCESS;
  693. CRegKey cregKey ( hParent,
  694. lpszKeyPath
  695. );
  696. if (ERROR_SUCCESS != (dwErr = cregKey.QueryErrorStatus()))
  697. {
  698. return(dwErr);
  699. }
  700. // Enumerate the children of the key. We will
  701. // not propogate to the caller errors from enumeration
  702. SRegKeySet *pRegKeySet = NULL;
  703. if (ERROR_SUCCESS == (dwErr = cregKey.EnumKeys ( & pRegKeySet)))
  704. {
  705. // Now we have set of Keys which need to be deleted in depth
  706. // first manner
  707. for (ULONG i = 0; i < pRegKeySet->cKeys; i++ )
  708. {
  709. dwErr = DelRegKeyTree ( cregKey.GetHandle(),
  710. (LPSTR) pRegKeySet->aprkKey[i]->GetName()
  711. );
  712. // Delete the key itself
  713. delete pRegKeySet->aprkKey[i];
  714. }
  715. // Delete the enumerator structure
  716. delete pRegKeySet;
  717. }
  718. // Finally delete this key
  719. dwErr = cregKey.Delete();
  720. return(dwErr);
  721. }