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.

1550 lines
27 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name :
  4. registry.cpp
  5. Abstract:
  6. Registry classes
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Project:
  10. Internet Services Manager
  11. Revision History:
  12. --*/
  13. //
  14. // Include Files
  15. //
  16. #include "stdafx.h"
  17. #include <stdlib.h>
  18. #include <memory.h>
  19. #include <ctype.h>
  20. #include "comprop.h"
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char BASED_CODE THIS_FILE[] = __FILE__;
  24. #endif
  25. CRMCRegKey::CRMCRegKey (
  26. IN HKEY hKeyBase,
  27. IN LPCTSTR lpszSubKey OPTIONAL,
  28. IN REGSAM regSam OPTIONAL,
  29. IN LPCTSTR lpszServerName OPTIONAL
  30. )
  31. /*++
  32. Routine Description:
  33. Constructor registry key object for an existing key. Optionally provide
  34. a computer name to open a registry key on a remote computer.
  35. Arguments:
  36. HKEY hKeyBase : Base key handle
  37. LPCTSTR lpszSubKey : Name of the subkey
  38. REGSAM regSam : Security access mask for registry key
  39. LPCTSTR lpszServerName : Optional computer name whose registry to open
  40. Return Value:
  41. N/A
  42. --*/
  43. : m_hKey(NULL),
  44. m_dwDisposition(REG_OPENED_EXISTING_KEY)
  45. {
  46. HKEY hkBase = NULL;
  47. CError err;
  48. //
  49. // Change to NULL if server name is really local
  50. //
  51. lpszServerName = ::NormalizeServerName(lpszServerName);
  52. if (m_fLocal = (lpszServerName != NULL))
  53. {
  54. //
  55. // Remote connection.
  56. //
  57. err = ::RegConnectRegistry((LPTSTR)lpszServerName, hKeyBase, &hkBase);
  58. if (err.Failed())
  59. {
  60. hkBase = NULL;
  61. }
  62. }
  63. else
  64. {
  65. hkBase = hKeyBase;
  66. }
  67. if (err.Succeeded())
  68. {
  69. if (lpszSubKey != NULL)
  70. {
  71. err = ::RegOpenKeyEx(hkBase, lpszSubKey, 0, regSam, &m_hKey);
  72. }
  73. else
  74. {
  75. m_hKey = hkBase;
  76. hkBase = NULL;
  77. }
  78. if (hkBase && hkBase != hKeyBase)
  79. {
  80. ::RegCloseKey(hkBase);
  81. }
  82. }
  83. if (err.Failed())
  84. {
  85. m_hKey = NULL;
  86. }
  87. }
  88. CRMCRegKey::CRMCRegKey(
  89. OUT BOOL * pfNewKeyCreated OPTIONAL,
  90. IN HKEY hKeyBase,
  91. IN LPCTSTR lpszSubKey OPTIONAL,
  92. IN DWORD dwOptions OPTIONAL,
  93. IN REGSAM regSam OPTIONAL,
  94. IN LPSECURITY_ATTRIBUTES pSecAttr OPTIONAL,
  95. IN LPCTSTR lpszServerName OPTIONAL
  96. )
  97. /*++
  98. Routine Description:
  99. Constructor registry key object to create a new key. Optionally provide
  100. a computer name to open a registry key on a remote computer.
  101. Arguments:
  102. BOOL * pfNewKeyCreated : If specified, returns TRUE if a new key
  103. was created, FALSE if an existing one was
  104. opened.
  105. HKEY hKeyBase : Base key handle
  106. LPCTSTR lpszSubKey : Name of the subkey
  107. DWORD dwOptions : Option flags
  108. REGSAM regSam : Security access mask for registry key
  109. LPSECURITY_ATTRIBUTES pSecAttr : Security attributes
  110. LPCTSTR lpszServerName : Optional computer name whose registry to
  111. open
  112. Return Value:
  113. N/A
  114. --*/
  115. : m_hKey(NULL),
  116. m_dwDisposition(0L)
  117. {
  118. HKEY hkBase = NULL;
  119. CError err;
  120. //
  121. // Change to NULL if server name is really local
  122. //
  123. lpszServerName = NormalizeServerName(lpszServerName);
  124. if (m_fLocal = (lpszServerName != NULL))
  125. {
  126. //
  127. // Remote connection.
  128. //
  129. err = ::RegConnectRegistry((LPTSTR)lpszServerName, hKeyBase, &hkBase);
  130. if (err.Failed())
  131. {
  132. hkBase = NULL;
  133. }
  134. }
  135. else
  136. {
  137. hkBase = hKeyBase;
  138. }
  139. if (err.Succeeded())
  140. {
  141. LPCTSTR szEmpty = _T("");
  142. err = ::RegCreateKeyEx(
  143. hkBase,
  144. lpszSubKey,
  145. 0, // Reserved
  146. (LPTSTR)szEmpty,
  147. dwOptions,
  148. regSam,
  149. pSecAttr,
  150. &m_hKey,
  151. &m_dwDisposition
  152. );
  153. }
  154. if (err.Failed())
  155. {
  156. m_hKey = NULL;
  157. }
  158. if (pfNewKeyCreated)
  159. {
  160. *pfNewKeyCreated = m_dwDisposition == REG_CREATED_NEW_KEY;
  161. }
  162. }
  163. #ifdef _DEBUG
  164. /* virtual */
  165. void
  166. CRMCRegKey::AssertValid() const
  167. /*++
  168. Routine Description:
  169. Assert the object is in a valid state.
  170. Arguments:
  171. None
  172. Return Value:
  173. None
  174. --*/
  175. {
  176. ASSERT(m_hKey != NULL);
  177. }
  178. /* virtual */
  179. void
  180. CRMCRegKey::Dump(
  181. IN OUT CDumpContext & dc
  182. ) const
  183. /*++
  184. Routine Description:
  185. Dump the contents of the object to the debug string
  186. Arguments:
  187. CDumpContext & dc : debug context
  188. Return Value:
  189. None
  190. --*/
  191. {
  192. dc << _T("HKEY = ")
  193. << m_hKey
  194. << _T("Disposition = ")
  195. << m_dwDisposition
  196. << _T(" \r\n");
  197. }
  198. #endif // _DEBUG
  199. CRMCRegKey::~CRMCRegKey()
  200. /*++
  201. Routine Description:
  202. Destructor. Close the key if it's open.
  203. Arguments:
  204. N/A
  205. Return Value:
  206. N/A
  207. --*/
  208. {
  209. if (m_hKey != NULL)
  210. {
  211. ::RegCloseKey(m_hKey);
  212. }
  213. }
  214. /* protected */
  215. DWORD
  216. CRMCRegKey::PrepareValue(
  217. IN LPCTSTR lpszValueName,
  218. OUT DWORD * pdwType,
  219. OUT DWORD * pcbSize,
  220. OUT BYTE ** ppbData
  221. )
  222. /*++
  223. Routine Description:
  224. Prepare to read a value by finding the value's size.
  225. Arguments:
  226. LPCTSTR lpszValueName : Name of the value
  227. DWORD * pdwType : Returns the type registry value
  228. DWORD * pcbSize : Returns the size of the value
  229. BYTE ** ppbData : Will allocate and return the the value here
  230. Return Value:
  231. Error return code.
  232. --*/
  233. {
  234. CError err;
  235. BYTE chDummy[2];
  236. DWORD cbData = 0L;
  237. do
  238. {
  239. //
  240. // Set the resulting buffer size to 0.
  241. //
  242. *pcbSize = 0;
  243. *ppbData = NULL;
  244. err = ::RegQueryValueEx(
  245. *this,
  246. (LPTSTR)lpszValueName,
  247. 0,
  248. pdwType,
  249. chDummy,
  250. &cbData
  251. );
  252. //
  253. // The only error we should get here is ERROR_MORE_DATA, but
  254. // we may get no error if the value has no data.
  255. //
  256. if (err.Succeeded())
  257. {
  258. //
  259. // Just a fudgy number
  260. //
  261. cbData = sizeof(LONG);
  262. }
  263. else
  264. {
  265. if (err.Win32Error() != ERROR_MORE_DATA)
  266. {
  267. break;
  268. }
  269. }
  270. //
  271. // Allocate a buffer large enough for the data.
  272. //
  273. *ppbData = (LPBYTE)AllocMem((*pcbSize = cbData) + sizeof(LONG));
  274. if (*ppbData == NULL)
  275. {
  276. err = ERROR_NOT_ENOUGH_MEMORY;
  277. break;
  278. }
  279. //
  280. // Now that have a buffer, re-fetch the value.
  281. //
  282. err = ::RegQueryValueEx(
  283. *this,
  284. (LPTSTR)lpszValueName,
  285. 0,
  286. pdwType,
  287. *ppbData,
  288. pcbSize
  289. );
  290. }
  291. while(FALSE);
  292. if (err.Failed() && *ppbData != NULL)
  293. {
  294. FreeMem(*ppbData);
  295. }
  296. return err;
  297. }
  298. //
  299. // Overloaded value query members; each returns ERROR_INVALID_PARAMETER
  300. // if data exists but not in correct form to deliver into result object.
  301. //
  302. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  303. DWORD
  304. CRMCRegKey::QueryValue(
  305. IN LPCTSTR lpszValueName,
  306. OUT CString & strResult,
  307. IN BOOL fAutoExpand, OPTIONAL
  308. OUT BOOL * pfExpanded OPTIONAL
  309. )
  310. /*++
  311. Routine Description:
  312. Get a CString registry value.
  313. Arguments:
  314. LPCTSTR lpszValueName : Name of the value
  315. CString & strResult : String return value
  316. BOOL fAutoExpand : If TRUE auto expand REG_EXPAND_SZ on local
  317. computer.
  318. BOOL * pfExpanded : Optionally returns TRUE if expanded
  319. Return Value:
  320. Error return code.
  321. --*/
  322. {
  323. CError err;
  324. DWORD dwType;
  325. DWORD cbData;
  326. BYTE * pabData = NULL;
  327. try
  328. {
  329. do
  330. {
  331. err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData);
  332. if (err.Failed())
  333. {
  334. break;
  335. }
  336. //
  337. // Guarantee that the data looks like a string
  338. //
  339. pabData[cbData] = 0;
  340. switch(dwType)
  341. {
  342. case REG_EXPAND_SZ:
  343. if (IsLocal() && fAutoExpand)
  344. {
  345. int cchBuff = (cbData / sizeof(TCHAR)) + 2048;
  346. int cchRequired;
  347. while(TRUE)
  348. {
  349. cchRequired = ExpandEnvironmentStrings(
  350. (LPCTSTR)pabData,
  351. strResult.GetBuffer(cchBuff),
  352. cchBuff
  353. );
  354. if (cchRequired == 0)
  355. {
  356. //
  357. // Never a valid result (even an empty
  358. // string has a terminating null).
  359. //
  360. err.GetLastWinError();
  361. break;
  362. }
  363. if (cchRequired > cchBuff)
  364. {
  365. //
  366. // Buffer too small -- try again
  367. //
  368. cchBuff = cchRequired;
  369. continue;
  370. }
  371. //
  372. // Successfully expanded environment string.
  373. //
  374. strResult.ReleaseBuffer();
  375. break;
  376. }
  377. if (err.Succeeded() && pfExpanded)
  378. {
  379. *pfExpanded = TRUE;
  380. }
  381. break;
  382. }
  383. //
  384. // Fall through
  385. //
  386. case REG_SZ:
  387. strResult = (LPTSTR)pabData;
  388. if (pfExpanded)
  389. {
  390. *pfExpanded = FALSE;
  391. }
  392. break;
  393. default:
  394. err = ERROR_INVALID_PARAMETER;
  395. break;
  396. }
  397. }
  398. while(FALSE);
  399. }
  400. catch(CMemoryException * e)
  401. {
  402. err = ERROR_NOT_ENOUGH_MEMORY;
  403. e->Delete();
  404. }
  405. if (pabData)
  406. {
  407. FreeMem(pabData);
  408. }
  409. return err;
  410. }
  411. DWORD
  412. CRMCRegKey::QueryValue(
  413. IN LPCTSTR lpszValueName,
  414. OUT CStringListEx & strList
  415. )
  416. /*++
  417. Routine Description:
  418. Read REG_MULTI_SZ as a CStringListEx
  419. Arguments:
  420. LPCTSTR lpszValueName : Name of the value
  421. CStringListEx & strList : String list return value
  422. Return Value:
  423. Error return code.
  424. --*/
  425. {
  426. CError err;
  427. DWORD dwType;
  428. DWORD cbData;
  429. BYTE * pabData = NULL;
  430. LPTSTR pbTemp, pbTempLimit;
  431. do
  432. {
  433. err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData);
  434. if (err.Failed())
  435. {
  436. break;
  437. }
  438. ASSERT(dwType == REG_MULTI_SZ);
  439. if (dwType != REG_MULTI_SZ)
  440. {
  441. err = ERROR_INVALID_PARAMETER;
  442. break;
  443. }
  444. //
  445. // Guarantee that the trailing data looks like a string
  446. //
  447. pabData[cbData] = 0;
  448. pbTemp = (LPTSTR)pabData;
  449. pbTempLimit = &(pbTemp[cbData]);
  450. try
  451. {
  452. while (pbTemp < pbTempLimit)
  453. {
  454. strList.AddTail(pbTemp);
  455. pbTemp += ::_tcslen(pbTemp) + 1;
  456. }
  457. }
  458. catch(CMemoryException * e)
  459. {
  460. err = ERROR_NOT_ENOUGH_MEMORY;
  461. e->Delete();
  462. }
  463. }
  464. while (FALSE);
  465. if (pabData)
  466. {
  467. FreeMem(pabData);
  468. }
  469. return err;
  470. }
  471. DWORD
  472. CRMCRegKey::QueryValue(
  473. IN LPCTSTR lpszValueName,
  474. OUT DWORD & dwResult
  475. )
  476. /*++
  477. Routine Description:
  478. Read a DWORD from the registry value
  479. Arguments:
  480. LPCTSTR lpszValueName : Name of the value
  481. DWORD & dwResult : DWORD to be returned
  482. Return Value:
  483. Error return code.
  484. --*/
  485. {
  486. CError err;
  487. DWORD dwType;
  488. DWORD cbData;
  489. BYTE * pabData = NULL;
  490. do
  491. {
  492. err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData);
  493. if (err.Failed())
  494. {
  495. break;
  496. }
  497. ASSERT(dwType == REG_DWORD && cbData == sizeof(dwResult));
  498. if (dwType != REG_DWORD || cbData != sizeof(dwResult))
  499. {
  500. err = ERROR_INVALID_PARAMETER;
  501. break;
  502. }
  503. dwResult = *((DWORD *)pabData);
  504. }
  505. while (FALSE);
  506. if (pabData)
  507. {
  508. FreeMem(pabData);
  509. }
  510. return err;
  511. }
  512. DWORD
  513. CRMCRegKey::QueryValue(
  514. IN LPCTSTR lpszValueName,
  515. OUT CByteArray & abResult
  516. )
  517. /*++
  518. Routine Description:
  519. Read a byte stream from the registry as a CByteArray
  520. Arguments:
  521. LPCTSTR lpszValueName : Name of the value
  522. CByteArray & abResult : Byte array result
  523. Return Value:
  524. Error return code.
  525. --*/
  526. {
  527. CError err;
  528. DWORD dwType;
  529. DWORD cbData;
  530. BYTE * pabData = NULL;
  531. do
  532. {
  533. err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData);
  534. if (err.Failed())
  535. {
  536. break;
  537. }
  538. ASSERT(dwType == REG_BINARY);
  539. if (dwType != REG_BINARY)
  540. {
  541. err = ERROR_INVALID_PARAMETER;
  542. break;
  543. }
  544. try
  545. {
  546. abResult.SetSize(cbData);
  547. }
  548. catch(CMemoryException * e)
  549. {
  550. err = ERROR_NOT_ENOUGH_MEMORY;
  551. e->Delete();
  552. }
  553. if (err.Failed())
  554. {
  555. break;
  556. }
  557. //
  558. // Move the data to the result array.
  559. //
  560. for (DWORD i = 0; i < cbData; ++i)
  561. {
  562. abResult[i] = pabData[i];
  563. }
  564. }
  565. while (FALSE);
  566. if (pabData)
  567. {
  568. FreeMem(pabData);
  569. }
  570. return err;
  571. }
  572. DWORD
  573. CRMCRegKey::QueryValue(
  574. IN LPCTSTR lpszValueName,
  575. IN void * pvResult,
  576. IN DWORD cbSize
  577. )
  578. /*++
  579. Routine Description:
  580. Read a byte stream from the registry into a previously allocated
  581. buffer.
  582. Arguments:
  583. LPCTSTR lpszValueName : Name of the value
  584. void * pvResult : Generic buffer
  585. DWORD cbSize : Size of the buffer
  586. Return Value:
  587. Error return code.
  588. --*/
  589. {
  590. CError err;
  591. DWORD dwType;
  592. DWORD cbData;
  593. BYTE * pabData = NULL;
  594. do
  595. {
  596. err = PrepareValue(lpszValueName, &dwType, &cbData, &pabData);
  597. if (err.Failed())
  598. {
  599. break;
  600. }
  601. ASSERT(dwType == REG_BINARY && pvResult != NULL);
  602. if (dwType != REG_BINARY || pvResult == NULL)
  603. {
  604. err = ERROR_INVALID_PARAMETER;
  605. break;
  606. }
  607. if (cbSize < cbData)
  608. {
  609. err = ERROR_MORE_DATA;
  610. break;
  611. }
  612. ::CopyMemory(pvResult, pabData, cbData);
  613. }
  614. while (FALSE);
  615. if (pabData)
  616. {
  617. FreeMem(pabData);
  618. }
  619. return err;
  620. }
  621. //
  622. // Overloaded value setting members.
  623. //
  624. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  625. DWORD
  626. CRMCRegKey::SetValue(
  627. IN LPCTSTR lpszValueName,
  628. IN CString & strResult,
  629. IN BOOL fAutoDeflate, OPTIONAL
  630. IN OUT BOOL * pfDeflated OPTIONAL
  631. )
  632. /*++
  633. Routine Description:
  634. Write a CString as REG_SZ or REG_EXPAND_SZ registry value.
  635. Arguments:
  636. LPCTSTR lpszValueName : Name of the value
  637. CString & strResult : String to be written
  638. BOOL fAutoDeflate : If TRUE write as REG_EXPAND_SZ and
  639. try using %SystemRoot% path
  640. BOOL * pfDeflated : Optionally return whether item was
  641. deflated.
  642. If *TRUE on input, use REG_EXPAND_SZ
  643. regardless.
  644. Return Value:
  645. Error return code.
  646. --*/
  647. {
  648. TRACEEOLID(strResult);
  649. CError err;
  650. DWORD dwType = REG_SZ;
  651. if (fAutoDeflate || (pfDeflated && *pfDeflated))
  652. {
  653. err = DeflateEnvironmentVariablePath(
  654. _T("SystemRoot"),
  655. strResult
  656. );
  657. if (err.Failed())
  658. {
  659. err = DeflateEnvironmentVariablePath(
  660. _T("SystemDrive"),
  661. strResult
  662. );
  663. }
  664. dwType = REG_EXPAND_SZ;
  665. }
  666. return ::RegSetValueEx(
  667. *this,
  668. lpszValueName,
  669. 0, // Reserved
  670. dwType,
  671. (const LPBYTE)(LPCTSTR)strResult,
  672. (strResult.GetLength() + 1) * sizeof(TCHAR)
  673. );
  674. }
  675. DWORD
  676. CRMCRegKey::SetValue(
  677. IN LPCTSTR lpszValueName,
  678. IN CStringListEx & strList
  679. )
  680. /*++
  681. Routine Description:
  682. Write a CStringListEx as REG_MULTI_SZ registry value.
  683. Arguments:
  684. LPCTSTR lpszValueName : Name of the value
  685. CStringListEx & strList : Strings to be written
  686. Return Value:
  687. Error return code.
  688. --*/
  689. {
  690. DWORD cbSize;
  691. BYTE * pbData = NULL;
  692. CError err(FlattenValue(strList, &cbSize, &pbData));
  693. if (err.Succeeded())
  694. {
  695. err = ::RegSetValueEx(
  696. *this,
  697. lpszValueName,
  698. 0, // Reserved
  699. REG_MULTI_SZ,
  700. pbData,
  701. cbSize
  702. );
  703. }
  704. if (pbData != NULL)
  705. {
  706. FreeMem(pbData);
  707. }
  708. return err;
  709. }
  710. DWORD
  711. CRMCRegKey::SetValue(
  712. IN LPCTSTR lpszValueName,
  713. IN DWORD & dwResult
  714. )
  715. /*++
  716. Routine Description:
  717. Write a DWORD to the registry value
  718. Arguments:
  719. LPCTSTR lpszValueName : Name of the value
  720. DWORD & dwResult : DWORD to be written
  721. Return Value:
  722. Error return code.
  723. --*/
  724. {
  725. return ::RegSetValueEx(
  726. *this,
  727. lpszValueName,
  728. 0, // Reserved
  729. REG_DWORD,
  730. (const LPBYTE)&dwResult,
  731. sizeof(dwResult)
  732. );
  733. }
  734. DWORD
  735. CRMCRegKey::SetValue(
  736. IN LPCTSTR lpszValueName,
  737. IN CByteArray & abResult
  738. )
  739. /*++
  740. Routine Description:
  741. Write a CByteArray of bytes to the registry value
  742. Arguments:
  743. LPCTSTR lpszValueName : Name of the value
  744. CByteArray & abResult : Bytes to be written
  745. Return Value:
  746. Error return code.
  747. --*/
  748. {
  749. DWORD cbSize;
  750. BYTE * pbData = NULL;
  751. CError err(FlattenValue(abResult, &cbSize, &pbData));
  752. if (err.Succeeded())
  753. {
  754. err = ::RegSetValueEx(
  755. *this,
  756. lpszValueName,
  757. 0, // Reserved
  758. REG_BINARY,
  759. pbData,
  760. cbSize
  761. );
  762. }
  763. if (pbData != NULL)
  764. {
  765. FreeMem(pbData);
  766. }
  767. return err;
  768. }
  769. DWORD
  770. CRMCRegKey::SetValue(
  771. IN LPCTSTR lpszValueName,
  772. IN void * pvResult,
  773. IN DWORD cbSize
  774. )
  775. /*++
  776. Routine Description:
  777. Write a generic stream of bytes to the registry value
  778. Arguments:
  779. LPCTSTR lpszValueName : Name of the value
  780. CByteArray & abResult : Bytes to be written
  781. Return Value:
  782. Error return code.
  783. --*/
  784. {
  785. return ::RegSetValueEx(
  786. *this,
  787. lpszValueName,
  788. 0, // Reserved
  789. REG_BINARY,
  790. (const LPBYTE)pvResult,
  791. cbSize
  792. );
  793. }
  794. /* static */
  795. /* protected */
  796. /* INTRINSA suppress=null_pointers, uninitialized */
  797. DWORD
  798. CRMCRegKey::FlattenValue(
  799. IN CStringListEx & strList,
  800. OUT DWORD * pcbSize,
  801. OUT BYTE ** ppbData
  802. )
  803. /*++
  804. Routine Description:
  805. Spread out the stringlist over a generic buffer. Buffer will
  806. be allocated by this function.
  807. Arguments:
  808. CStringListEx & strList : List of strings to be used
  809. DWORD * pcbSize : Returns the byte size of the buffer allocated
  810. BYTE ** ppbData : Buffer which will be allocated
  811. Return Value:
  812. Error return code.
  813. --*/
  814. {
  815. CError err;
  816. POSITION pos;
  817. CString * pstr;
  818. int cbTotal = 0;
  819. //
  820. // CODEWORK: Try using ConvertStringListToDoubleNullList here
  821. //
  822. //
  823. // Walk the list accumulating sizes
  824. //
  825. for (pos = strList.GetHeadPosition();
  826. pos != NULL && (pstr = & strList.GetNext(pos));
  827. /**/
  828. )
  829. {
  830. cbTotal += (pstr->GetLength() + 1) * sizeof(TCHAR);
  831. }
  832. //
  833. // Allocate and fill a temporary buffer
  834. //
  835. if (*pcbSize = cbTotal)
  836. {
  837. try
  838. {
  839. *ppbData = (LPBYTE)AllocMem(*pcbSize);
  840. BYTE * pbData = *ppbData;
  841. if (pbData == NULL) {
  842. err = ERROR_NOT_ENOUGH_MEMORY;
  843. }
  844. //
  845. // Populate the buffer with the strings.
  846. //
  847. else for (pos = strList.GetHeadPosition();
  848. pos != NULL && (pstr = & strList.GetNext(pos));
  849. /**/
  850. )
  851. {
  852. int cb = (pstr->GetLength() + 1) * sizeof(TCHAR);
  853. ::CopyMemory(pbData, (LPCTSTR)*pstr, cb);
  854. pbData += cb;
  855. }
  856. }
  857. catch(CMemoryException * e)
  858. {
  859. err = ERROR_NOT_ENOUGH_MEMORY;
  860. e->Delete();
  861. }
  862. }
  863. else
  864. {
  865. *ppbData = NULL;
  866. }
  867. return err;
  868. }
  869. /* static */
  870. /* protected */
  871. /* INTRINSA suppress=null_pointers, uninitialized */
  872. DWORD
  873. CRMCRegKey::FlattenValue(
  874. IN CByteArray & abData,
  875. OUT DWORD * pcbSize,
  876. OUT BYTE ** ppbData
  877. )
  878. /*++
  879. Routine Description:
  880. Spread out the CByteArray over a generic buffer. Buffer will
  881. be allocated by this function.
  882. Arguments:
  883. CByteArray * abData : Byte stream
  884. DWORD * pcbSize : Returns the byte size of the buffer allocated
  885. BYTE ** ppbData : Buffer which will be allocated
  886. Return Value:
  887. Error return code.
  888. --*/
  889. {
  890. CError err;
  891. //
  892. // Allocate and fill a temporary buffer
  893. //
  894. if (*pcbSize = (DWORD) abData.GetSize())
  895. {
  896. try
  897. {
  898. *ppbData = (LPBYTE)AllocMem(*pcbSize);
  899. if (*ppbData == NULL) {
  900. err = ERROR_NOT_ENOUGH_MEMORY;
  901. }
  902. else for (DWORD i = 0; i < *pcbSize; i++)
  903. {
  904. (*ppbData)[i] = abData[i];
  905. }
  906. }
  907. catch(CMemoryException * e)
  908. {
  909. err = ERROR_NOT_ENOUGH_MEMORY;
  910. e->Delete();
  911. }
  912. }
  913. else
  914. {
  915. *ppbData = NULL;
  916. }
  917. return err;
  918. }
  919. DWORD
  920. CRMCRegKey::QueryKeyInfo(
  921. OUT CREGKEY_KEY_INFO * pRegKeyInfo
  922. )
  923. /*++
  924. Routine Description:
  925. Find out information about this given key.
  926. Arguments:
  927. CREGKEY_KEY_INFO * pRegKeyInfo : Registry key structure
  928. Return Value:
  929. Error return code.
  930. --*/
  931. {
  932. ASSERT(pRegKeyInfo != NULL);
  933. if (pRegKeyInfo == NULL)
  934. {
  935. return ERROR_INVALID_PARAMETER;
  936. }
  937. pRegKeyInfo->dwClassNameSize = sizeof(pRegKeyInfo->chBuff) - 1;
  938. return ::RegQueryInfoKey(
  939. *this,
  940. pRegKeyInfo->chBuff,
  941. &pRegKeyInfo->dwClassNameSize,
  942. NULL,
  943. &pRegKeyInfo->dwNumSubKeys,
  944. &pRegKeyInfo->dwMaxSubKey,
  945. &pRegKeyInfo->dwMaxClass,
  946. &pRegKeyInfo->dwMaxValues,
  947. &pRegKeyInfo->dwMaxValueName,
  948. &pRegKeyInfo->dwMaxValueData,
  949. &pRegKeyInfo->dwSecDesc,
  950. &pRegKeyInfo->ftKey
  951. );
  952. }
  953. CRMCRegKeyIter::CRMCRegKeyIter(
  954. IN CRMCRegKey & regKey
  955. )
  956. /*++
  957. Routine Description:
  958. Constructor for the registry keys iteration class.
  959. Arguments:
  960. CRMCRegKey & regKey : Parent registry key to be enumerated.
  961. Return Value:
  962. N/A
  963. --*/
  964. : m_rkIter(regKey),
  965. m_pBuffer(NULL),
  966. m_cbBuffer(0)
  967. {
  968. CRMCRegKey::CREGKEY_KEY_INFO regKeyInfo;
  969. Reset();
  970. CError err(regKey.QueryKeyInfo(&regKeyInfo));
  971. if (err.Succeeded())
  972. {
  973. try
  974. {
  975. m_cbBuffer = regKeyInfo.dwMaxSubKey + sizeof(DWORD);
  976. m_pBuffer = AllocTString(m_cbBuffer);
  977. }
  978. catch(CMemoryException * e)
  979. {
  980. err = ERROR_NOT_ENOUGH_MEMORY;
  981. e->Delete();
  982. }
  983. }
  984. err.MessageBoxOnFailure();
  985. }
  986. CRMCRegKeyIter::~CRMCRegKeyIter()
  987. /*++
  988. Routine Description:
  989. Destructor for key iteration class
  990. Arguments:
  991. N/A
  992. Return Value:
  993. N/A
  994. --*/
  995. {
  996. if (m_pBuffer != NULL)
  997. {
  998. FreeMem(m_pBuffer);
  999. }
  1000. }
  1001. DWORD
  1002. CRMCRegKeyIter::Next(
  1003. OUT CString * pstrName,
  1004. OUT CTime * pTime OPTIONAL
  1005. )
  1006. /*++
  1007. Routine Description:
  1008. Get the name (and optional last write time) of the next key.
  1009. Arguments:
  1010. CString * pstrName : Next key name
  1011. CTime * pTime : Time structure or NULL
  1012. Return Value:
  1013. ERROR_SUCCESS if the next key was found, ERROR_NO_MORE_ITEMS
  1014. if no further items are available.
  1015. --*/
  1016. {
  1017. if (m_pBuffer == NULL)
  1018. {
  1019. return ERROR_NO_MORE_ITEMS;
  1020. }
  1021. FILETIME ftDummy;
  1022. DWORD dwNameSize = m_cbBuffer;
  1023. CError err(::RegEnumKeyEx(
  1024. m_rkIter,
  1025. m_dwIndex,
  1026. m_pBuffer,
  1027. &dwNameSize,
  1028. NULL,
  1029. NULL,
  1030. NULL,
  1031. &ftDummy
  1032. ));
  1033. if (err.Succeeded())
  1034. {
  1035. ++m_dwIndex;
  1036. if (pTime != NULL)
  1037. {
  1038. *pTime = ftDummy;
  1039. }
  1040. try
  1041. {
  1042. *pstrName = m_pBuffer;
  1043. }
  1044. catch(CMemoryException * e)
  1045. {
  1046. err = ERROR_NOT_ENOUGH_MEMORY;
  1047. e->Delete();
  1048. }
  1049. }
  1050. return err;
  1051. }
  1052. CRMCRegValueIter::CRMCRegValueIter(
  1053. IN CRMCRegKey & regKey
  1054. )
  1055. /*++
  1056. Routine Description:
  1057. Constructor for the Iterate through registry values class.
  1058. Arguments:
  1059. CRMCRegKey & regKey : Parent registry key to be enumerated.
  1060. Return Value:
  1061. N/A
  1062. --*/
  1063. : m_rkIter(regKey),
  1064. m_pBuffer(NULL),
  1065. m_cbBuffer(0)
  1066. {
  1067. CRMCRegKey::CREGKEY_KEY_INFO regKeyInfo;
  1068. Reset();
  1069. CError err(regKey.QueryKeyInfo(&regKeyInfo));
  1070. if (err.Succeeded())
  1071. {
  1072. try
  1073. {
  1074. m_cbBuffer = regKeyInfo.dwMaxValueName + sizeof(DWORD);
  1075. m_pBuffer = AllocTString(m_cbBuffer);
  1076. }
  1077. catch(CMemoryException * e)
  1078. {
  1079. err = ERROR_NOT_ENOUGH_MEMORY;
  1080. e->Delete();
  1081. }
  1082. }
  1083. err.MessageBoxOnFailure();
  1084. }
  1085. CRMCRegValueIter::~CRMCRegValueIter()
  1086. /*++
  1087. Routine Description:
  1088. Destructor for values iteration class
  1089. Arguments:
  1090. N/A
  1091. Return Value:
  1092. N/A
  1093. --*/
  1094. {
  1095. if (m_pBuffer != NULL)
  1096. {
  1097. FreeMem(m_pBuffer);
  1098. }
  1099. }
  1100. DWORD
  1101. CRMCRegValueIter::Next(
  1102. OUT CString * pstrName,
  1103. OUT DWORD * pdwType
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. Get the name and type of the next registry value
  1108. Arguments:
  1109. CString * pstrName : Next value name
  1110. DWORD * pdwType : Registry value type
  1111. Return Value:
  1112. ERROR_SUCCESS if the next key was found, ERROR_NO_MORE_ITEMS
  1113. if no further items are available.
  1114. --*/
  1115. {
  1116. if (m_pBuffer == NULL)
  1117. {
  1118. return ERROR_NO_MORE_ITEMS;
  1119. }
  1120. DWORD dwNameLength = m_cbBuffer;
  1121. CError err(::RegEnumValue(
  1122. m_rkIter,
  1123. m_dwIndex,
  1124. m_pBuffer,
  1125. &dwNameLength,
  1126. NULL,
  1127. pdwType,
  1128. NULL,
  1129. NULL
  1130. ));
  1131. if (err.Succeeded())
  1132. {
  1133. ++m_dwIndex;
  1134. try
  1135. {
  1136. *pstrName = m_pBuffer;
  1137. }
  1138. catch(CMemoryException * e)
  1139. {
  1140. err = ERROR_NOT_ENOUGH_MEMORY;
  1141. e->Delete();
  1142. }
  1143. }
  1144. return err;
  1145. }