Leaked source code of windows server 2003
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.

720 lines
20 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CRegistryKey.cpp
  7. //
  8. // Description:
  9. // Contains the definition of the CRegistryKey class.
  10. //
  11. // Maintained By:
  12. // David Potter (DavidP) 14-JU-2001
  13. // Vij Vasu (Vvasu) 08-MAR-2000
  14. //
  15. //////////////////////////////////////////////////////////////////////////////
  16. //////////////////////////////////////////////////////////////////////////////
  17. // Include Files
  18. //////////////////////////////////////////////////////////////////////////////
  19. // The precompiled header.
  20. #include "Pch.h"
  21. //////////////////////////////////////////////////////////////////////////////
  22. //++
  23. //
  24. // CRegistryKey::CRegistryKey
  25. //
  26. // Description:
  27. // Default constructor of the CRegistryKey class
  28. //
  29. // Arguments:
  30. // None.
  31. //
  32. // Return Value:
  33. // None.
  34. //
  35. // Exceptions Thrown:
  36. // None.
  37. //
  38. //--
  39. //////////////////////////////////////////////////////////////////////////////
  40. CRegistryKey::CRegistryKey( void ) throw()
  41. {
  42. TraceFunc( "" );
  43. TraceFuncExit();
  44. } //*** CRegistryKey::CRegistryKey
  45. //////////////////////////////////////////////////////////////////////////////
  46. //++
  47. //
  48. // CRegistryKey::CRegistryKey
  49. //
  50. // Description:
  51. // Constructor of the CRegistryKey class. Opens the specified key.
  52. //
  53. // Arguments:
  54. // hKeyParentIn
  55. // Handle to the parent key.
  56. //
  57. // pszSubKeyNameIn
  58. // Name of the subkey.
  59. //
  60. // samDesiredIn
  61. // Access rights desired. Defaults to KEY_ALL_ACCESS
  62. //
  63. // Return Value:
  64. // None.
  65. //
  66. // Exceptions Thrown:
  67. // Any thrown by functions called.
  68. //
  69. //--
  70. //////////////////////////////////////////////////////////////////////////////
  71. CRegistryKey::CRegistryKey(
  72. HKEY hKeyParentIn
  73. , const WCHAR * pszSubKeyNameIn
  74. , REGSAM samDesiredIn
  75. )
  76. {
  77. TraceFunc1( "pszSubKeyNameIn = '%ws'", pszSubKeyNameIn );
  78. OpenKey( hKeyParentIn, pszSubKeyNameIn, samDesiredIn );
  79. TraceFuncExit();
  80. } //*** CRegistryKey::CRegistryKey
  81. //////////////////////////////////////////////////////////////////////////////
  82. //++
  83. //
  84. // CRegistryKey::~CRegistryKey
  85. //
  86. // Description:
  87. // Default destructor of the CRegistryKey class
  88. //
  89. // Arguments:
  90. // None.
  91. //
  92. // Return Value:
  93. // None.
  94. //
  95. // Exceptions Thrown:
  96. // None.
  97. //
  98. //--
  99. //////////////////////////////////////////////////////////////////////////////
  100. CRegistryKey::~CRegistryKey( void ) throw()
  101. {
  102. TraceFunc( "" );
  103. TraceFuncExit();
  104. } //*** CRegistryKey::~CRegistryKey
  105. //////////////////////////////////////////////////////////////////////////////
  106. //++
  107. //
  108. // CRegistryKey::OpenKey
  109. //
  110. // Description:
  111. // Opens the specified key.
  112. //
  113. // Arguments:
  114. // hKeyParentIn
  115. // Handle to the parent key.
  116. //
  117. // pszSubKeyNameIn
  118. // Name of the subkey.
  119. //
  120. // samDesiredIn
  121. // Access rights desired. Defaults to KEY_ALL_ACCESS
  122. //
  123. // Return Value:
  124. // None.
  125. //
  126. // Exceptions Thrown:
  127. // CRuntimeError
  128. // If any of the APIs fail.
  129. //
  130. //--
  131. //////////////////////////////////////////////////////////////////////////////
  132. void
  133. CRegistryKey::OpenKey(
  134. HKEY hKeyParentIn
  135. , const WCHAR * pszSubKeyNameIn
  136. , REGSAM samDesiredIn
  137. )
  138. {
  139. TraceFunc3( "hKeyParentIn = %p, pszSubKeyNameIn = '%ws', samDesiredIn = %#x", hKeyParentIn, pszSubKeyNameIn == NULL ? L"<null>" : pszSubKeyNameIn, samDesiredIn );
  140. HKEY hTempKey = NULL;
  141. LONG lRetVal;
  142. lRetVal = TW32( RegOpenKeyExW(
  143. hKeyParentIn
  144. , pszSubKeyNameIn
  145. , 0
  146. , samDesiredIn
  147. , &hTempKey
  148. ) );
  149. // Was the key opened properly?
  150. if ( lRetVal != ERROR_SUCCESS )
  151. {
  152. LogMsg( "[BC] RegOpenKeyExW( '%ws' ) retured error %#08x. Throwing an exception.", pszSubKeyNameIn, lRetVal );
  153. THROW_RUNTIME_ERROR(
  154. HRESULT_FROM_WIN32( lRetVal )
  155. , IDS_ERROR_REGISTRY_OPEN
  156. );
  157. } // if: RegOpenKeyEx failed.
  158. TraceFlow1( "Handle to key = %p", hTempKey );
  159. // Store the opened key in the member variable.
  160. m_shkKey.Assign( hTempKey );
  161. TraceFuncExit();
  162. } //*** CRegistryKey::OpenKey
  163. //////////////////////////////////////////////////////////////////////////////
  164. //++
  165. //
  166. // CRegistryKey::CreateKey
  167. //
  168. // Description:
  169. // Creates the specified key. If the key already exists, this functions
  170. // opens the key.
  171. //
  172. // Arguments:
  173. // hKeyParentIn
  174. // Handle to the parent key.
  175. //
  176. // pszSubKeyNameIn
  177. // Name of the subkey.
  178. //
  179. // samDesiredIn
  180. // Access rights desired. Defaults to KEY_ALL_ACCESS
  181. //
  182. // Return Value:
  183. // None.
  184. //
  185. // Exceptions Thrown:
  186. // CRuntimeError
  187. // If any of the APIs fail.
  188. //
  189. //--
  190. //////////////////////////////////////////////////////////////////////////////
  191. void
  192. CRegistryKey::CreateKey(
  193. HKEY hKeyParentIn
  194. , const WCHAR * pszSubKeyNameIn
  195. , REGSAM samDesiredIn
  196. )
  197. {
  198. TraceFunc3( "hKeyParentIn = %p, pszSubKeyNameIn = '%ws', samDesiredIn = %#x", hKeyParentIn, pszSubKeyNameIn == NULL ? L"<null>" : pszSubKeyNameIn, samDesiredIn );
  199. if ( pszSubKeyNameIn == NULL )
  200. {
  201. LogMsg( "[BC] CreateKey() - Key = NULL. This is an error! Throwing exception." );
  202. THROW_ASSERT( E_INVALIDARG, "The name of the subkey cannot be NULL." );
  203. }
  204. HKEY hTempKey = NULL;
  205. LONG lRetVal;
  206. lRetVal = TW32( RegCreateKeyExW(
  207. hKeyParentIn
  208. , pszSubKeyNameIn
  209. , 0
  210. , NULL
  211. , REG_OPTION_NON_VOLATILE
  212. , samDesiredIn
  213. , NULL
  214. , &hTempKey
  215. , NULL
  216. ) );
  217. // Was the key opened properly?
  218. if ( lRetVal != ERROR_SUCCESS )
  219. {
  220. LogMsg( "[BC] RegCreateKeyExW( '%ws' ) retured error %#08x. Throwing an exception.", pszSubKeyNameIn, lRetVal );
  221. THROW_RUNTIME_ERROR(
  222. HRESULT_FROM_WIN32( lRetVal )
  223. , IDS_ERROR_REGISTRY_CREATE
  224. );
  225. } // if: RegCreateKeyEx failed.
  226. TraceFlow1( "Handle to key = %p", hTempKey );
  227. // Store the opened key in the member variable.
  228. m_shkKey.Assign( hTempKey );
  229. TraceFuncExit();
  230. } //*** CRegistryKey::CreateKey
  231. //////////////////////////////////////////////////////////////////////////////
  232. //++
  233. //
  234. // CRegistryKey::QueryValue
  235. //
  236. // Description:
  237. // Reads a value under this key. The memory for this value is allocated
  238. // by this function. The caller is responsible for freeing this memory.
  239. //
  240. // Arguments:
  241. // pszValueNameIn
  242. // Name of the value to read.
  243. //
  244. // ppbDataOut
  245. // Pointer to the pointer to the data. Cannot be NULL.
  246. //
  247. // pdwDataSizeInBytesOut
  248. // Number of bytes allocated in the data buffer. Cannot be NULL.
  249. //
  250. // pdwTypeOut
  251. // Pointer to the type of the value.
  252. //
  253. // Return Value:
  254. // None.
  255. //
  256. // Exceptions Thrown:
  257. // CRuntimeError
  258. // If any of the APIs fail.
  259. //
  260. // CAssert
  261. // If the parameters are incorrect.
  262. //
  263. //--
  264. //////////////////////////////////////////////////////////////////////////////
  265. void
  266. CRegistryKey::QueryValue(
  267. const WCHAR * pszValueNameIn
  268. , LPBYTE * ppbDataOut
  269. , LPDWORD pdwDataSizeBytesOut
  270. , LPDWORD pdwTypeOut
  271. ) const
  272. {
  273. TraceFunc1( "pszValueNameIn = '%ws'", pszValueNameIn == NULL ? L"<null>" : pszValueNameIn );
  274. LONG lRetVal = ERROR_SUCCESS;
  275. DWORD cbBufferSize = 0;
  276. DWORD cbTempBufferSize = 0;
  277. DWORD dwType = REG_SZ;
  278. // Check parameters
  279. if ( ( pdwDataSizeBytesOut == NULL )
  280. || ( ppbDataOut == NULL )
  281. )
  282. {
  283. LogMsg( "[BC] One of the required input pointers is NULL. Throwing an exception." );
  284. THROW_ASSERT(
  285. E_INVALIDARG
  286. , "CRegistryKey::QueryValue() => Required input pointer in NULL"
  287. );
  288. } // if: parameters are invalid.
  289. // Initialize outputs.
  290. *ppbDataOut = NULL;
  291. *pdwDataSizeBytesOut = 0;
  292. // Get the required size of the buffer.
  293. lRetVal = TW32( RegQueryValueExW(
  294. m_shkKey.HHandle() // handle to key to query
  295. , pszValueNameIn // address of name of value to query
  296. , 0 // reserved
  297. , &dwType // address of buffer for value type
  298. , NULL // address of data buffer
  299. , &cbBufferSize // address of data buffer size
  300. ) );
  301. if ( lRetVal != ERROR_SUCCESS )
  302. {
  303. LogMsg( "[BC] RegQueryValueExW( '%ws' ) retured error %#08x. Throwing an exception.", pszValueNameIn, lRetVal );
  304. THROW_RUNTIME_ERROR(
  305. HRESULT_FROM_WIN32( lRetVal )
  306. , IDS_ERROR_REGISTRY_QUERY
  307. );
  308. }
  309. cbTempBufferSize = cbBufferSize;
  310. // String should be double NULL terminated if REG_MULTI_SZ type
  311. // String should be NULL terminated if REG_SZ or REG_EXPAND_SZ type
  312. if ( dwType == REG_MULTI_SZ )
  313. {
  314. cbTempBufferSize = cbBufferSize + ( 2 * sizeof( WCHAR ) );
  315. }
  316. else if ( ( dwType == REG_SZ ) || ( dwType == REG_EXPAND_SZ ) )
  317. {
  318. cbTempBufferSize = cbBufferSize + ( 1 * sizeof( WCHAR ) );
  319. }
  320. // Allocate a byte array with enough size for null termination if not already null terminated.
  321. SmartByteArray sbaBuffer( new BYTE[ cbTempBufferSize ] );
  322. if ( sbaBuffer.FIsEmpty() )
  323. {
  324. LogMsg( "[BC] CRegistryKey::QueryValue() - Could not allocate %d bytes of memory. Throwing an exception", lRetVal );
  325. THROW_RUNTIME_ERROR(
  326. THR( E_OUTOFMEMORY )
  327. , IDS_ERROR_REGISTRY_QUERY
  328. );
  329. }
  330. // Read the value.
  331. lRetVal = TW32( RegQueryValueExW(
  332. m_shkKey.HHandle() // handle to key to query
  333. , pszValueNameIn // address of name of value to query
  334. , 0 // reserved
  335. , &dwType // address of buffer for value type
  336. , sbaBuffer.PMem() // address of data buffer
  337. , &cbBufferSize // address of data buffer size
  338. ) );
  339. // Was the key read properly?
  340. if ( lRetVal != ERROR_SUCCESS )
  341. {
  342. LogMsg( "[BC] RegQueryValueExW( '%ws' ) retured error %#08x. Throwing an exception.", pszValueNameIn, lRetVal );
  343. THROW_RUNTIME_ERROR(
  344. HRESULT_FROM_WIN32( lRetVal )
  345. , IDS_ERROR_REGISTRY_QUERY
  346. );
  347. } // if: RegQueryValueEx failed.
  348. // Are we dealing with a string?
  349. if ( ( dwType == REG_MULTI_SZ ) || ( dwType == REG_EXPAND_SZ ) || ( dwType == REG_SZ ) )
  350. {
  351. // We are expecting a Unicode string
  352. Assert( ( cbBufferSize % 2 ) == 0 );
  353. WCHAR * pszData = reinterpret_cast< WCHAR * >( sbaBuffer.PMem() );
  354. size_t cch = cbBufferSize / sizeof( *pszData );
  355. switch ( dwType )
  356. {
  357. // Null terminate the string if not already null terminated
  358. case REG_SZ:
  359. case REG_EXPAND_SZ:
  360. if ( pszData[ cch - 1 ] != L'\0' )
  361. {
  362. pszData[ cch ] = L'\0';
  363. cbBufferSize += ( 1 * sizeof( *pszData ) );
  364. }
  365. break;
  366. // Double null terminate the REG_MULTI_SZ string if not already null terminated
  367. case REG_MULTI_SZ:
  368. if ( pszData[ cch - 2 ] != L'\0' )
  369. {
  370. pszData[ cch ] = L'\0';
  371. cbBufferSize += ( 1 * sizeof( *pszData ) );
  372. }
  373. cch++;
  374. if ( pszData[ cch - 2 ] != L'\0' )
  375. {
  376. pszData[ cch ] = L'\0';
  377. cbBufferSize += ( 1 * sizeof( *pszData ) );
  378. }
  379. break;
  380. } // switch ( dwType )
  381. } // if: ( ( dwType == REG_MULTI_SZ ) || ( dwType == REG_EXPAND_SZ ) || ( dwType == REG_SZ ) )
  382. *ppbDataOut = sbaBuffer.PRelease();
  383. *pdwDataSizeBytesOut = cbBufferSize;
  384. if ( pdwTypeOut != NULL )
  385. {
  386. *pdwTypeOut = dwType;
  387. }
  388. TraceFuncExit();
  389. } //*** CRegistryKey::QueryValue
  390. //////////////////////////////////////////////////////////////////////////////
  391. //++
  392. //
  393. // CRegistryKey::SetValue
  394. //
  395. // Description:
  396. // Writes a value under this key.
  397. //
  398. // Arguments:
  399. // pszValueNameIn
  400. // Name of the value to be set.
  401. //
  402. // cpbDataIn
  403. // Pointer to the pointer to the data buffer.
  404. //
  405. // dwDataSizeInBytesIn
  406. // Number of bytes in the data buffer.
  407. //
  408. // pdwTypeIn
  409. // Type of the value.
  410. //
  411. // Return Value:
  412. // None.
  413. //
  414. // Exceptions Thrown:
  415. // CRuntimeError
  416. // If any of the APIs fail.
  417. //
  418. //--
  419. //////////////////////////////////////////////////////////////////////////////
  420. void
  421. CRegistryKey::SetValue(
  422. const WCHAR * pszValueNameIn
  423. , DWORD dwTypeIn
  424. , const BYTE * cpbDataIn
  425. , DWORD dwDataSizeBytesIn
  426. ) const
  427. {
  428. TraceFunc5(
  429. "HKEY = %p, pszValueNameIn = '%ws', dwTypeIn = %d, cpbDataIn = %p, dwDataSizeBytesIn = %d."
  430. , m_shkKey.HHandle()
  431. , pszValueNameIn
  432. , dwTypeIn
  433. , cpbDataIn
  434. , dwDataSizeBytesIn
  435. );
  436. DWORD scRetVal = ERROR_SUCCESS;
  437. #ifdef DEBUG
  438. // Are we dealing with a string?
  439. if ( ( dwTypeIn == REG_MULTI_SZ ) || ( dwTypeIn == REG_EXPAND_SZ ) || ( dwTypeIn == REG_SZ ) )
  440. {
  441. // We are expecting a unicode string
  442. Assert( ( dwDataSizeBytesIn % 2 ) == 0 );
  443. const WCHAR * pszData = reinterpret_cast< const WCHAR * >( cpbDataIn );
  444. size_t cch = dwDataSizeBytesIn / sizeof( *pszData );
  445. // Assert if the string we are writing to the registry is not null terminated.
  446. switch ( dwTypeIn )
  447. {
  448. case REG_SZ:
  449. case REG_EXPAND_SZ:
  450. Assert( pszData[ cch - 1 ] == L'\0' );
  451. break;
  452. case REG_MULTI_SZ :
  453. Assert( pszData[ cch - 2 ] == L'\0' );
  454. Assert( pszData[ cch - 1 ] == L'\0' );
  455. break;
  456. } // switch ( dwType )
  457. } // if: ( ( dwType == REG_MULTI_SZ ) || ( dwType == REG_EXPAND_SZ ) || ( dwType == REG_SZ ) )
  458. #endif
  459. scRetVal = TW32( RegSetValueExW(
  460. m_shkKey.HHandle()
  461. , pszValueNameIn
  462. , 0
  463. , dwTypeIn
  464. , cpbDataIn
  465. , dwDataSizeBytesIn
  466. ) );
  467. if ( scRetVal != ERROR_SUCCESS )
  468. {
  469. LogMsg( "[BC] RegSetValueExW( '%s' ) retured error %#08x. Throwing an exception.", pszValueNameIn, scRetVal );
  470. THROW_RUNTIME_ERROR(
  471. HRESULT_FROM_WIN32( scRetVal )
  472. , IDS_ERROR_REGISTRY_SET
  473. );
  474. } // if: RegSetValueExW failed
  475. TraceFuncExit();
  476. } //*** CRegistryKey::SetValue
  477. //////////////////////////////////////////////////////////////////////////////
  478. //++
  479. //
  480. // CRegistryKey::RenameKey
  481. //
  482. // Description:
  483. // Rename this key.
  484. //
  485. // Arguments:
  486. // pszNewNameIn
  487. // The new name for this key.
  488. //
  489. // Return Value:
  490. // None.
  491. //
  492. // Exceptions Thrown:
  493. // CRuntimeError
  494. // If any of the APIs fail.
  495. //
  496. // IMPORTANT NOTE:
  497. // This function calls the NtRenameKey API with the handle returned by
  498. // RegOpenKeyEx. This will work as long as we are not dealing with a
  499. // remote registry key.
  500. //
  501. //--
  502. //////////////////////////////////////////////////////////////////////////////
  503. void
  504. CRegistryKey::RenameKey(
  505. const WCHAR * pszNewNameIn
  506. )
  507. {
  508. TraceFunc2(
  509. "HKEY = %p, pszNewNameIn = '%s'."
  510. , m_shkKey.HHandle()
  511. , pszNewNameIn
  512. );
  513. UNICODE_STRING ustrNewName;
  514. DWORD dwRetVal = ERROR_SUCCESS;
  515. RtlInitUnicodeString( &ustrNewName, pszNewNameIn );
  516. // Begin_Replace00
  517. //
  518. // BUGBUG: Vij Vasu (Vvasu) 10-APR-2000
  519. // Dynamically linking to NtDll.dll to allow testing on Win2K
  520. // Replace the section below ( Begin_Replace00 to End-Replace00 ) with
  521. // the single marked statment ( Begin_Replacement00 to End_Replacement00 ).
  522. //
  523. {
  524. typedef CSmartResource<
  525. CHandleTrait<
  526. HMODULE
  527. , BOOL
  528. , FreeLibrary
  529. , reinterpret_cast< HMODULE >( NULL )
  530. >
  531. > SmartModuleHandle;
  532. SmartModuleHandle smhNtDll( LoadLibrary( L"NtDll.dll" ) );
  533. if ( smhNtDll.FIsInvalid() )
  534. {
  535. dwRetVal = GetLastError();
  536. LogMsg( "[BC] LoadLibrary( 'NtDll.dll' ) retured error %#08x. Throwing an exception.", dwRetVal );
  537. THROW_RUNTIME_ERROR(
  538. dwRetVal // NTSTATUS codes are compatible with HRESULTS
  539. , IDS_ERROR_REGISTRY_RENAME
  540. );
  541. } // if: LoadLibrary failed.
  542. FARPROC pNtRenameKey = GetProcAddress( smhNtDll.HHandle(), "NtRenameKey" );
  543. if ( pNtRenameKey == NULL )
  544. {
  545. dwRetVal = GetLastError();
  546. LogMsg( "[BC] GetProcAddress() retured error %#08x. Throwing an exception.", dwRetVal );
  547. THROW_RUNTIME_ERROR(
  548. dwRetVal // NTSTATUS codes are compatible with HRESULTS
  549. , IDS_ERROR_REGISTRY_RENAME
  550. );
  551. } // if: GetProcAddress() failed
  552. dwRetVal = ( reinterpret_cast< NTSTATUS (*)( HANDLE, PUNICODE_STRING ) >( pNtRenameKey ) )(
  553. m_shkKey.HHandle()
  554. , &ustrNewName
  555. );
  556. }
  557. // End_Replace00
  558. /* Begin_Replacement00 - delete this line
  559. dwRetVal = NtRenameKey(
  560. m_shkKey.HHandle()
  561. , &ustrNewName
  562. );
  563. End_Replacement00 - delete this line */
  564. if ( NT_ERROR( dwRetVal ) )
  565. {
  566. TraceFlow2( "NtRenameKey( '%ws' ) retured error %#08x. Throwing an exception.", pszNewNameIn, dwRetVal );
  567. LogMsg( "[BC] Error %#08x occurred renaming a key to '%ws' )", dwRetVal, pszNewNameIn );
  568. THROW_RUNTIME_ERROR(
  569. dwRetVal // NTSTATUS codes are compatible with HRESULTS
  570. , IDS_ERROR_REGISTRY_RENAME
  571. );
  572. } // if: RegRenameKeyEx failed.
  573. TraceFuncExit();
  574. } //*** CRegistryKey::RenameKey
  575. //////////////////////////////////////////////////////////////////////////////
  576. //++
  577. //
  578. // CRegistryKey::DeleteValue
  579. //
  580. // Description:
  581. // Delete a value under this key.
  582. //
  583. // Arguments:
  584. // pszValueNameIn
  585. // Name of the value to be deleted.
  586. //
  587. // Return Value:
  588. // None.
  589. //
  590. // Exceptions Thrown:
  591. // CRuntimeError
  592. // If any of the APIs fail.
  593. //
  594. //--
  595. //////////////////////////////////////////////////////////////////////////////
  596. void
  597. CRegistryKey::DeleteValue(
  598. const WCHAR * pszValueNameIn
  599. ) const
  600. {
  601. TraceFunc2(
  602. "HKEY = %p, pszValueNameIn = '%ws'."
  603. , m_shkKey.HHandle()
  604. , pszValueNameIn
  605. );
  606. DWORD dwRetVal = TW32( RegDeleteValueW(
  607. m_shkKey.HHandle()
  608. , pszValueNameIn
  609. ) );
  610. if ( dwRetVal != ERROR_SUCCESS )
  611. {
  612. LogMsg( "[BC] RegDeleteValueW( '%s' ) retured error %#08x. Throwing an exception.", pszValueNameIn, dwRetVal );
  613. THROW_RUNTIME_ERROR(
  614. HRESULT_FROM_WIN32( dwRetVal )
  615. , IDS_ERROR_REGISTRY_DELETE
  616. );
  617. } // if: RegDeleteValue failed.
  618. TraceFuncExit();
  619. } //*** CRegistryKey::DeleteValue