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.

825 lines
22 KiB

  1. //#pragma title( "TReg.cpp - NT registry class" )
  2. /*
  3. Copyright (c) 1995-1998, Mission Critical Software, Inc. All rights reserved.
  4. ===============================================================================
  5. Module - TReg.cpp
  6. System - Common
  7. Author - Tom Bernhardt, Rich Denham
  8. Created - 1995-09-01
  9. Description - NT registry class.
  10. Updates -
  11. ===============================================================================
  12. */
  13. #ifdef USE_STDAFX
  14. # include "stdafx.h"
  15. #else
  16. # include <windows.h>
  17. #endif
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <time.h>
  21. #include "Common.hpp"
  22. #include "UString.hpp"
  23. #include "Err.hpp"
  24. #include "TNode.hpp"
  25. #include "TReg.hpp"
  26. // Short term solution
  27. #define MAX_REG_NAMELEN 512
  28. #define MAX_REG_VALUELEN 2048
  29. // Destructor function was formerly inline.
  30. // It is here to facilitate handle leak tracing.
  31. TRegKey::~TRegKey()
  32. {
  33. Close();
  34. };
  35. // Close function was formerly inline.
  36. // It is here to facilitate handle leak tracing.
  37. void
  38. TRegKey::Close()
  39. {
  40. if ( hKey != INVALID_HANDLE_VALUE )
  41. {
  42. RegCloseKey( hKey );
  43. hKey = (HKEY) INVALID_HANDLE_VALUE;
  44. }
  45. };
  46. // open registry on remote computer
  47. DWORD
  48. TRegKey::Connect(
  49. HKEY hPreDefined ,// in -must be HKEY_LOCAL_MACHINE or HKEY_USERS
  50. TCHAR const * machineName // in -remote computer name
  51. )
  52. {
  53. DWORD rc; // return code
  54. if ( hKey != INVALID_HANDLE_VALUE )
  55. {
  56. Close();
  57. }
  58. rc = RegConnectRegistry( const_cast<TCHAR *>(machineName), hPreDefined, &hKey );
  59. if ( rc )
  60. {
  61. hKey = (HKEY) INVALID_HANDLE_VALUE;
  62. }
  63. return rc;
  64. }
  65. // create new key
  66. DWORD
  67. TRegKey::Create(
  68. TCHAR const * keyname ,// in -name/path of key to create/open
  69. HKEY hParent ,// in -handle of parent key
  70. DWORD * pDisp ,// out-disposition of create
  71. DWORD access // in -security access mask for key
  72. )
  73. {
  74. DWORD disp;
  75. DWORD rc;
  76. if ( hKey != INVALID_HANDLE_VALUE )
  77. {
  78. Close();
  79. }
  80. rc = RegCreateKeyEx( hParent,
  81. keyname,
  82. 0,
  83. NULL,
  84. REG_OPTION_NON_VOLATILE,
  85. access,
  86. NULL,
  87. &hKey,
  88. (pDisp!=NULL) ? pDisp : &disp );
  89. if ( rc )
  90. {
  91. hKey = (HKEY) INVALID_HANDLE_VALUE;
  92. }
  93. return rc;
  94. }
  95. // create new key (using backup/restore)
  96. DWORD
  97. TRegKey::CreateBR(
  98. TCHAR const * keyname ,// in -name/path of key to create/open
  99. HKEY hParent ,// in -handle of parent key
  100. DWORD * pDisp ,// out-disposition of create
  101. DWORD access // in -security access mask for key
  102. )
  103. {
  104. DWORD disp;
  105. DWORD rc;
  106. if ( hKey != INVALID_HANDLE_VALUE )
  107. {
  108. Close();
  109. }
  110. rc = RegCreateKeyEx( hParent,
  111. keyname,
  112. 0,
  113. NULL,
  114. REG_OPTION_BACKUP_RESTORE,
  115. access,
  116. NULL,
  117. &hKey,
  118. (pDisp!=NULL) ? pDisp : &disp );
  119. if ( rc )
  120. {
  121. hKey = (HKEY) INVALID_HANDLE_VALUE;
  122. }
  123. return rc;
  124. }
  125. // open existing key
  126. DWORD
  127. TRegKey::Open(
  128. TCHAR const * keyname ,// in -name/path of key to create/open
  129. HKEY hParent ,// in -handle of parent key
  130. DWORD access // in -security access mask for key
  131. )
  132. {
  133. DWORD rc;
  134. if ( hKey != INVALID_HANDLE_VALUE )
  135. {
  136. Close();
  137. }
  138. rc = RegOpenKeyEx( hParent,
  139. keyname,
  140. 0,
  141. access,
  142. &hKey );
  143. if ( rc )
  144. {
  145. hKey = (HKEY) INVALID_HANDLE_VALUE;
  146. }
  147. return rc;
  148. }
  149. // Gets the subkey value of the specified index number
  150. DWORD // ret-os return code
  151. TRegKey::SubKeyEnum(
  152. DWORD n ,// in -ordinal number of subkey
  153. TCHAR * keyname ,// out-key name
  154. DWORD keylen // in -max length of key name
  155. ) const
  156. {
  157. DWORD rc;
  158. DWORD keyLen = keylen;
  159. FILETIME lastWrite;
  160. rc = RegEnumKeyEx( hKey,
  161. n,
  162. keyname,
  163. &keyLen,
  164. 0,
  165. NULL,
  166. NULL,
  167. &lastWrite );
  168. return rc;
  169. }
  170. // Enumerate value
  171. // Note that "namelen" must be "sizeof name", not "DIM(name)"
  172. // Same for "valuelen"
  173. DWORD // ret-0 or error code
  174. TRegKey::ValueEnum(
  175. DWORD index ,// in -ordinal number of subkey
  176. TCHAR * name ,// out-name
  177. DWORD namelen ,// in -name length
  178. void * value ,// out-value
  179. DWORD * valuelen ,// i/o-value length
  180. DWORD * type // out-value type code
  181. ) const
  182. {
  183. return RegEnumValue( hKey, index, name, &namelen, NULL, type, (BYTE *) value, valuelen );
  184. }
  185. // Get REG_DWORD value
  186. DWORD // ret-OS return code
  187. TRegKey::ValueGetDWORD(
  188. TCHAR const * name ,// in -value name
  189. DWORD * value // out-returned DWORD value
  190. ) const
  191. {
  192. DWORD osRc; // OS return code
  193. DWORD type; // type of value
  194. DWORD len = sizeof *value; // value length
  195. osRc = RegQueryValueEx( hKey, name, NULL, &type, (BYTE *) value, &len );
  196. if ( !osRc && (type != REG_DWORD) )
  197. {
  198. osRc = ERROR_FILE_NOT_FOUND;
  199. }
  200. return osRc;
  201. }
  202. // Get REG_SZ value
  203. DWORD // ret-OS return code
  204. TRegKey::ValueGetStr(
  205. TCHAR const * name ,// in -value name
  206. TCHAR * value ,// out-value buffer
  207. DWORD maxlen // in -sizeof value buffer
  208. ) const
  209. {
  210. DWORD osRc; // OS return code
  211. DWORD type; // type of value
  212. DWORD len; // value length
  213. // force maxlen to an integral number of TEXT characters
  214. maxlen = maxlen / (sizeof value[0]) * (sizeof value[0]);
  215. if ( !maxlen )
  216. {
  217. osRc = ERROR_FILE_NOT_FOUND;
  218. }
  219. else
  220. {
  221. len = maxlen;
  222. osRc = RegQueryValueEx( hKey, name, NULL, &type, (BYTE *) value, &len );
  223. len = len / (sizeof value[0]) * (sizeof value[0]);
  224. if ( !osRc && (type != REG_SZ) )
  225. {
  226. osRc = ERROR_FILE_NOT_FOUND;
  227. }
  228. if ( osRc )
  229. {
  230. value[0] = TEXT('\0');
  231. }
  232. else
  233. { // return of a null-terminated string is not guaranteed by API!
  234. // force null-terminated string, truncate string if necessary.
  235. if ( len >= maxlen )
  236. {
  237. len = maxlen - sizeof value[0];
  238. }
  239. value[len/(sizeof value[0])] = TEXT('\0');
  240. }
  241. }
  242. return osRc;
  243. }
  244. DWORD
  245. TRegKey::ValueGet(
  246. TCHAR const * name ,// in -name
  247. void * value ,// out-value
  248. DWORD * lenvalue ,// i/o-length of value
  249. DWORD * typevalue // out-type of value
  250. ) const
  251. {
  252. return RegQueryValueEx( hKey, name, 0, typevalue, (UCHAR *) value, lenvalue );
  253. }
  254. // Set REG_SZ value
  255. DWORD
  256. TRegKey::ValueSetStr(
  257. TCHAR const * name ,// in -value name
  258. TCHAR const * value ,// out-value
  259. DWORD type // in -value type
  260. ) const
  261. {
  262. return RegSetValueEx( hKey,
  263. name,
  264. NULL,
  265. type,
  266. (LPBYTE) value,
  267. (UStrLen(value) + 1) * sizeof value[0] );
  268. }
  269. DWORD
  270. TRegKey::ValueSet(
  271. TCHAR const * name ,// in -name
  272. void const * value ,// in -value
  273. DWORD lenvalue ,// in -length of value
  274. DWORD typevalue // in -type of value
  275. ) const
  276. {
  277. return RegSetValueEx( hKey,
  278. name,
  279. 0,
  280. typevalue,
  281. (UCHAR const *) value,
  282. lenvalue );
  283. }
  284. DWORD // ret-0 or error code
  285. TRegKey::ValueDel(
  286. TCHAR const * name // in -value name
  287. ) const
  288. {
  289. DWORD rc;
  290. rc = RegDeleteValue(hKey, name);
  291. return rc;
  292. }
  293. DWORD // ret-OS return code
  294. TRegKey::HiveCopy(
  295. TRegKey const * source // in -source hive
  296. )
  297. {
  298. DWORD retval=0; // returned value
  299. DWORD index; // key/value index
  300. TCHAR name[MAX_REG_NAMELEN]; // key name
  301. TCHAR value[MAX_REG_VALUELEN]; // value name
  302. DWORD valuelen; // value length
  303. DWORD type; // value type
  304. TRegKey srcNest; // nested source registry
  305. TRegKey trgNest; // nested target registry
  306. // process values at this level
  307. for ( index = 0;
  308. !retval;
  309. index++ )
  310. {
  311. valuelen = sizeof value;
  312. retval = source->ValueEnum( index, name, sizeof name, value, &valuelen, &type );
  313. if ( !retval )
  314. {
  315. retval = this->ValueSet( name, value, valuelen, type );
  316. }
  317. else if ( retval == ERROR_MORE_DATA )
  318. {
  319. retval = 0;
  320. }
  321. }
  322. if ( retval == ERROR_NO_MORE_ITEMS )
  323. {
  324. retval = 0;
  325. }
  326. // process keys at this level; for each key make a recursive call
  327. for ( index = 0;
  328. !retval;
  329. index++ )
  330. {
  331. retval = source->SubKeyEnum( index, name, sizeof name );
  332. if ( !retval )
  333. {
  334. retval = srcNest.Open( name, source );
  335. if ( !retval )
  336. {
  337. retval = trgNest.Create( name, this );
  338. if ( !retval )
  339. {
  340. retval = trgNest.HiveCopy( &srcNest );
  341. trgNest.Close();
  342. }
  343. srcNest.Close();
  344. }
  345. }
  346. }
  347. if ( retval == ERROR_NO_MORE_ITEMS )
  348. {
  349. retval = 0;
  350. }
  351. return retval;
  352. }
  353. DWORD // ret-OS return code
  354. TRegKey::HiveDel()
  355. {
  356. DWORD retval = 0; // returned value
  357. DWORD index; // value/key index
  358. TCHAR name[300]; // name
  359. DWORD namelen; // name length
  360. BYTE value[300]; // value
  361. DWORD valuelen; // value length
  362. DWORD type; // value type code
  363. TRegKey trgNest; // nested target registry
  364. // delete values at this level
  365. for ( index = 0;
  366. !retval;
  367. /* index++ */ ) // note that index remains at zero
  368. {
  369. namelen = sizeof name;
  370. valuelen = sizeof value;
  371. retval = ValueEnum( index, name, namelen, value, &valuelen, &type );
  372. if ( retval == ERROR_MORE_DATA )
  373. {
  374. retval = 0;
  375. }
  376. if ( !retval )
  377. {
  378. retval = ValueDel( name );
  379. }
  380. }
  381. if ( retval == ERROR_NO_MORE_ITEMS )
  382. {
  383. retval = 0;
  384. }
  385. // process keys at this level; for each key make a recursive call
  386. for ( index = 0;
  387. !retval;
  388. /* index++ */ ) // note that index remains at zero
  389. {
  390. retval = SubKeyEnum( index, name, sizeof name );
  391. if ( !retval )
  392. {
  393. retval = trgNest.Open( name, this );
  394. if ( !retval )
  395. {
  396. retval = trgNest.HiveDel();
  397. trgNest.Close();
  398. }
  399. retval = SubKeyDel( name );
  400. }
  401. }
  402. if ( retval == ERROR_NO_MORE_ITEMS )
  403. {
  404. retval = 0;
  405. }
  406. return retval;
  407. }
  408. // These four classes are used only by TRegReplicate
  409. // Class to represent one registry key
  410. class RKey : public TNode
  411. {
  412. friend class RKeyList;
  413. private:
  414. TCHAR * name; // key name
  415. protected:
  416. public:
  417. RKey() { name = NULL; };
  418. ~RKey() { if ( name ) delete name; };
  419. BOOL New( TCHAR const * aname );
  420. TCHAR const * GetName() const { return name; };
  421. };
  422. BOOL
  423. RKey::New(
  424. TCHAR const * aname // in -key name
  425. )
  426. {
  427. name = new TCHAR[UStrLen(aname)+1];
  428. if ( name )
  429. {
  430. UStrCpy( name, aname );
  431. }
  432. return !!name;
  433. }
  434. // Class to represent the set of registry keys at one level
  435. class RKeyList : public TNodeListSortable
  436. {
  437. private:
  438. static TNodeCompare( Compare ) { return UStrICmp(
  439. ((RKey const *) v1)->name,
  440. ((RKey const *) v2)->name ); }
  441. protected:
  442. public:
  443. RKeyList() : TNodeListSortable( Compare ) {}
  444. ~RKeyList();
  445. };
  446. // RKeyList object destructor
  447. RKeyList::~RKeyList()
  448. {
  449. DeleteAllListItems( RKey );
  450. }
  451. // Class to represent one registry value
  452. class RValue : public TNode
  453. {
  454. friend class RValueList;
  455. private:
  456. TCHAR * name; // value's name
  457. BYTE * value; // value's value
  458. DWORD valuelen; // value's value length
  459. DWORD type; // value's type
  460. protected:
  461. public:
  462. RValue() { name = NULL; value = NULL; valuelen = type = 0; };
  463. ~RValue() { if ( name ) delete name;
  464. if ( value ) delete value; };
  465. BOOL New( TCHAR const * aname, BYTE const * avalue, DWORD valuelen, DWORD type );
  466. TCHAR const * GetName() const { return name; };
  467. BYTE const * GetValue() const { return value; };
  468. DWORD GetValueLen() const { return valuelen; };
  469. DWORD GetType() const { return type; };
  470. };
  471. BOOL
  472. RValue::New(
  473. TCHAR const * aname ,// in -value's name
  474. BYTE const * avalue ,// in -value's value
  475. DWORD avaluelen ,// in -value's value length
  476. DWORD atype // in -value's type
  477. )
  478. {
  479. name = new TCHAR[UStrLen(aname)+1];
  480. if ( name )
  481. {
  482. UStrCpy( name, aname );
  483. }
  484. value = new BYTE[avaluelen];
  485. if ( value )
  486. {
  487. memcpy( value, avalue, avaluelen );
  488. }
  489. valuelen = avaluelen;
  490. type = atype;
  491. return name && value;
  492. }
  493. // Class to represent the set of registry values at one level
  494. class RValueList : public TNodeListSortable
  495. {
  496. private:
  497. static TNodeCompare( Compare ) { return UStrICmp(
  498. ((RValue const *)v1)->name,
  499. ((RValue const *)v2)->name ); }
  500. protected:
  501. public:
  502. RValueList() : TNodeListSortable( Compare ) {}
  503. ~RValueList();
  504. };
  505. // RValueList object destructor
  506. RValueList::~RValueList()
  507. {
  508. DeleteAllListItems( RValue );
  509. }
  510. // Static subroutine used only by TRegReplicate
  511. // collect all values at one registry level into a RValueList
  512. DWORD static
  513. CollectValues(
  514. RValueList * pValueList ,// out-value list to be built
  515. TRegKey const * pRegKey // in -registry key
  516. )
  517. {
  518. DWORD retval=0; // returned value
  519. DWORD index; // value enum index
  520. TCHAR name[MAX_REG_NAMELEN]; // value name
  521. BYTE value[MAX_REG_VALUELEN]; // value value
  522. DWORD valuelen; // value length
  523. DWORD type; // value type
  524. RValue * pValue; // new value
  525. for ( index = 0;
  526. !retval;
  527. index++ )
  528. {
  529. valuelen = sizeof value;
  530. retval = pRegKey->ValueEnum( index, name, sizeof name, value, &valuelen, &type );
  531. if ( !retval )
  532. {
  533. pValue = new RValue;
  534. if ( pValue )
  535. {
  536. if ( pValue->New( name, value, valuelen, type ) )
  537. {
  538. pValueList->Insert( pValue );
  539. }
  540. else
  541. {
  542. delete pValue;
  543. pValue = NULL;
  544. }
  545. }
  546. if ( !pValue )
  547. {
  548. retval = ERROR_NOT_ENOUGH_MEMORY;
  549. }
  550. }
  551. else if ( retval == ERROR_MORE_DATA )
  552. {
  553. retval = 0;
  554. }
  555. }
  556. if ( retval == ERROR_NO_MORE_ITEMS )
  557. {
  558. retval = 0;
  559. }
  560. return retval;
  561. }
  562. // Static subroutine used only by TRegReplicate
  563. // collect all keys at one registry level into a RKeyList
  564. DWORD static
  565. CollectKeys(
  566. RKeyList * pKeyList ,// out-key list to be built
  567. TRegKey const * pRegKey // in -registry key
  568. )
  569. {
  570. DWORD retval=0; // returned value
  571. DWORD index; // key enum index
  572. TCHAR name[MAX_REG_NAMELEN]; // key name
  573. RKey * pKey; // new key object
  574. for ( index = 0;
  575. !retval;
  576. index++ )
  577. {
  578. retval = pRegKey->SubKeyEnum( index, name, sizeof name );
  579. if ( !retval )
  580. {
  581. pKey = new RKey;
  582. if ( pKey )
  583. {
  584. if ( pKey->New( name ) )
  585. {
  586. pKeyList->Insert( pKey );
  587. }
  588. else
  589. {
  590. delete pKey;
  591. pKey = NULL;
  592. }
  593. }
  594. if ( !pKey )
  595. {
  596. retval = ERROR_NOT_ENOUGH_MEMORY;
  597. }
  598. }
  599. }
  600. if ( retval == ERROR_NO_MORE_ITEMS )
  601. {
  602. retval = 0;
  603. }
  604. return retval;
  605. }
  606. // Replicate registry hive
  607. DWORD // ret-OS return code
  608. TRegKey::HiveReplicate(
  609. TRegKey const * source // in -source hive
  610. )
  611. {
  612. DWORD retval=0; // returned value
  613. RValueList srcValues; // source values
  614. RValueList trgValues; // target values
  615. TNodeListEnum eSrcValue; // enumerate source values
  616. RValue const * pSrcValue; // source value
  617. TNodeListEnum eTrgValue; // enumerate target values
  618. RValue const * pTrgValue; // target value
  619. RKeyList srcKeys; // source keys
  620. RKeyList trgKeys; // target keys
  621. TNodeListEnum eSrcKey; // enumerate source keys
  622. RKey const * pSrcKey; // source key
  623. TNodeListEnum eTrgKey; // enumerate target keys
  624. RKey const * pTrgKey; // target key
  625. int cmpRc; // compare return code
  626. TRegKey srcNest; // nested source registry
  627. TRegKey trgNest; // nested target registry
  628. // handle replication of values at this level
  629. CollectValues( &srcValues, source );
  630. CollectValues( &trgValues, this );
  631. // now merge the values
  632. pSrcValue = (RValue const *) eSrcValue.OpenFirst( &srcValues );
  633. pTrgValue = (RValue const *) eTrgValue.OpenFirst( &trgValues );
  634. while ( !retval && (pSrcValue || pTrgValue) )
  635. {
  636. if ( !pTrgValue )
  637. {
  638. cmpRc = -1;
  639. }
  640. else if ( !pSrcValue )
  641. {
  642. cmpRc = 1;
  643. }
  644. else
  645. {
  646. cmpRc = UStrICmp( pSrcValue->GetName(), pTrgValue->GetName() );
  647. }
  648. if ( cmpRc < 0 )
  649. { // source value only (copy)
  650. retval = this->ValueSet( pSrcValue->GetName(), pSrcValue->GetValue(),
  651. pSrcValue->GetValueLen(), pSrcValue->GetType() );
  652. pSrcValue = (RValue const *) eSrcValue.Next();
  653. }
  654. else if ( cmpRc > 0 )
  655. { // target value only (delete)
  656. retval = this->ValueDel( pTrgValue->GetName() );
  657. pTrgValue = (RValue const *) eTrgValue.Next();
  658. }
  659. else /* if ( cmpRc == 0 ) */
  660. { // identical value names (replicate)
  661. retval = this->ValueSet( pSrcValue->GetName(), pSrcValue->GetValue(),
  662. pSrcValue->GetValueLen(), pSrcValue->GetType() );
  663. pSrcValue = (RValue const *) eSrcValue.Next();
  664. pTrgValue = (RValue const *) eTrgValue.Next();
  665. }
  666. }
  667. eSrcValue.Close();
  668. eTrgValue.Close();
  669. // handle replication of keys at this level
  670. CollectKeys( &srcKeys, source );
  671. CollectKeys( &trgKeys, this );
  672. // now merge the values
  673. pSrcKey = (RKey const *) eSrcKey.OpenFirst( &srcKeys );
  674. pTrgKey = (RKey const *) eTrgKey.OpenFirst( &trgKeys );
  675. while ( !retval && (pSrcKey || pTrgKey) )
  676. {
  677. if ( !pTrgKey )
  678. {
  679. cmpRc = -1;
  680. }
  681. else if ( !pSrcKey )
  682. {
  683. cmpRc = 1;
  684. }
  685. else
  686. {
  687. cmpRc = UStrICmp( pSrcKey->GetName(), pTrgKey->GetName() );
  688. }
  689. if ( cmpRc < 0 )
  690. { // source key only (copy hive)
  691. retval = srcNest.Open( pSrcKey->GetName(), source );
  692. if ( !retval )
  693. {
  694. retval = trgNest.Create( pSrcKey->GetName(), this );
  695. if ( !retval )
  696. {
  697. retval = trgNest.HiveCopy( &srcNest );
  698. trgNest.Close();
  699. }
  700. srcNest.Close();
  701. }
  702. pSrcKey = (RKey const *) eSrcKey.Next();
  703. }
  704. else if ( cmpRc > 0 )
  705. { // target key only (delete hive)
  706. retval = trgNest.Open( pTrgKey->GetName(), this );
  707. if ( !retval )
  708. {
  709. retval = trgNest.HiveDel();
  710. trgNest.Close();
  711. }
  712. retval = SubKeyDel( pTrgKey->GetName() );
  713. pTrgKey = (RKey const *) eTrgKey.Next();
  714. }
  715. else /* if ( cmpRc == 0 ) */
  716. { // identical keys (replicate hive)
  717. retval = srcNest.Open( pSrcKey->GetName(), source );
  718. if ( !retval )
  719. {
  720. retval = trgNest.Open( pSrcKey->GetName(), this );
  721. if ( !retval )
  722. {
  723. retval = trgNest.HiveReplicate( &srcNest );
  724. trgNest.Close();
  725. }
  726. srcNest.Close();
  727. }
  728. pSrcKey = (RKey const *) eSrcKey.Next();
  729. pTrgKey = (RKey const *) eTrgKey.Next();
  730. }
  731. }
  732. eSrcKey.Close();
  733. eTrgKey.Close();
  734. return retval;
  735. }
  736. // TReg.cpp - end of file