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.

758 lines
18 KiB

  1. /*
  2. Copyright (c) Microsoft Corporation
  3. */
  4. #include "stdinc.h"
  5. #include "util.h"
  6. #include "fusionhandle.h"
  7. #define MAX_REG_RETRY_COUNT (10)
  8. #define FIND_ERROR_IN_ACCEPTABLE_LIST(err, tgtlasterror, vcount) do { \
  9. SIZE_T i; \
  10. va_list ap; \
  11. va_start(ap, vcount); \
  12. (tgtlasterror) = (err); \
  13. for (i = 0; i < (vcount); i++) { \
  14. if ((err) == va_arg(ap, LONG)) \
  15. break; \
  16. } \
  17. va_end(ap); \
  18. if (i == (vcount)) { \
  19. ::FusionpDbgPrintEx(FUSION_DBG_LEVEL_ERROR, "SXS.DLL: %s(%d) Err 0x%08lx not acceptable", __FUNCTION__, __LINE__, (err)); \
  20. ORIGINATE_WIN32_FAILURE_AND_EXIT(__FUNCTION__, err); \
  21. } \
  22. } while (0)
  23. BOOL
  24. FusionpRegQueryBinaryValueEx(
  25. DWORD dwFlags,
  26. HKEY hKey,
  27. PCWSTR lpValueName,
  28. CFusionArray<BYTE> &rbBuffer,
  29. DWORD &rdwLastError,
  30. SIZE_T cExceptionalLastErrors,
  31. ...
  32. )
  33. {
  34. FN_PROLOG_WIN32
  35. LONG lResult = NO_ERROR;
  36. DWORD dwType = 0;
  37. DWORD dwChances;
  38. lResult = rdwLastError = ERROR_SUCCESS;
  39. PARAMETER_CHECK((dwFlags & ~FUSIONP_REG_QUERY_BINARY_NO_FAIL_IF_NON_BINARY) == 0);
  40. PARAMETER_CHECK(hKey != NULL);
  41. PARAMETER_CHECK(lpValueName != NULL);
  42. for (dwChances = 0; dwChances < MAX_REG_RETRY_COUNT; dwChances++)
  43. {
  44. DWORD dwDataSize = rbBuffer.GetSizeAsDWORD();
  45. LPBYTE pvData = rbBuffer.GetArrayPtr();
  46. lResult = ::RegQueryValueExW(
  47. hKey,
  48. lpValueName,
  49. NULL,
  50. &dwType,
  51. pvData,
  52. &dwDataSize);
  53. // If we are to fail because the type is wrong (ie: don't magically convert
  54. // from a reg-sz to a binary blob), then fail.
  55. //
  56. // HACKHACK: This is to get around a spectacular bug in RegQueryValueEx,
  57. // which is even documented as 'correct' in MSDN.
  58. //
  59. // RegQueryValueEx returns ERROR_SUCCESS when the data target pointer
  60. // was NULL but the size value was "too small." So, we'll just claim
  61. // ERROR_MORE_DATA instead, and go around again, letting the buffer
  62. // get resized.
  63. //
  64. if ((pvData == NULL) && (lResult == ERROR_SUCCESS))
  65. {
  66. //
  67. // Yes, but if there's no data we need to stop and quit looking -
  68. // zero-length binary strings are a gotcha here.
  69. //
  70. if ( dwDataSize == 0 )
  71. break;
  72. lResult = ERROR_MORE_DATA;
  73. }
  74. if (lResult == ERROR_SUCCESS)
  75. {
  76. if ((dwFlags & FUSIONP_REG_QUERY_BINARY_NO_FAIL_IF_NON_BINARY) == 0)
  77. PARAMETER_CHECK(dwType == REG_BINARY);
  78. break;
  79. }
  80. else if (lResult == ERROR_MORE_DATA)
  81. {
  82. IFW32FALSE_EXIT(
  83. rbBuffer.Win32SetSize(
  84. dwDataSize,
  85. CFusionArray<BYTE>::eSetSizeModeExact));
  86. }
  87. else
  88. {
  89. break; // must break from for loop
  90. }
  91. }
  92. if (lResult != ERROR_SUCCESS)
  93. {
  94. SIZE_T i = 0;
  95. va_list ap;
  96. va_start(ap, cExceptionalLastErrors);
  97. ::SetLastError(lResult);
  98. rdwLastError = lResult;
  99. for (i=0; i<cExceptionalLastErrors; i++)
  100. {
  101. if (lResult == va_arg(ap, LONG))
  102. break;
  103. }
  104. va_end(ap);
  105. if (i == cExceptionalLastErrors)
  106. {
  107. ::FusionpDbgPrintEx(
  108. FUSION_DBG_LEVEL_ERROR,
  109. "SXS.DLL: %s(%ls)\n",
  110. __FUNCTION__,
  111. lpValueName
  112. );
  113. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegQueryValueExW, lResult);
  114. }
  115. }
  116. FN_EPILOG
  117. }
  118. BOOL
  119. FusionpRegQueryBinaryValueEx(
  120. DWORD dwFlags,
  121. HKEY hKey,
  122. PCWSTR lpValueName,
  123. CFusionArray<BYTE> &rbBuffer
  124. )
  125. {
  126. DWORD dwLastError = NO_ERROR;
  127. return ::FusionpRegQueryBinaryValueEx(dwFlags, hKey, lpValueName, rbBuffer, dwLastError, 0);
  128. }
  129. BOOL
  130. FusionpRegQuerySzValueEx(
  131. DWORD dwFlags,
  132. HKEY hKey,
  133. PCWSTR lpValueName,
  134. CBaseStringBuffer &rBuffer,
  135. DWORD &rdwLastError,
  136. SIZE_T cExceptionalLastErrorValues,
  137. ...
  138. )
  139. {
  140. FN_PROLOG_WIN32
  141. LONG lResult = ERROR_SUCCESS;
  142. CStringBufferAccessor acc;
  143. DWORD cbBuffer;
  144. DWORD dwType = 0;
  145. rdwLastError = ERROR_SUCCESS;
  146. rBuffer.Clear();
  147. PARAMETER_CHECK((dwFlags & ~(FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING)) == 0);
  148. acc.Attach(&rBuffer);
  149. if (acc.GetBufferCb() > MAXDWORD)
  150. {
  151. cbBuffer = MAXDWORD;
  152. }
  153. else
  154. {
  155. //
  156. // ISSUE:2002-3-29:jonwis - Shouldn't we have done something smarter here? Shouldn't we have
  157. // adjusted for the terminating NULL character?
  158. //
  159. cbBuffer = static_cast<DWORD>(acc.GetBufferCb()) - sizeof(WCHAR);
  160. }
  161. lResult = ::RegQueryValueExW(hKey, lpValueName, NULL, &dwType, (LPBYTE) acc.GetBufferPtr(), &cbBuffer);
  162. //
  163. // The value wasn't found, but the flag to just return a NULL string was set. Set the length
  164. // of the string to zero (stick a NULL as the first character) and return.
  165. //
  166. if ((lResult == ERROR_FILE_NOT_FOUND) && (dwFlags & FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING))
  167. {
  168. FN_SUCCESSFUL_EXIT();
  169. }
  170. //
  171. // If we got back "more data", expand out to the size that they want, and try again
  172. //
  173. else if (lResult == ERROR_MORE_DATA)
  174. {
  175. //
  176. // Resize the buffer to contain the string plus a NULL terminator.
  177. //
  178. acc.Detach();
  179. IFW32FALSE_EXIT(rBuffer.Win32ResizeBuffer(1 + (cbBuffer / sizeof(WCHAR)), eDoNotPreserveBufferContents));
  180. acc.Attach(&rBuffer);
  181. if (acc.GetBufferCb() > MAXDWORD)
  182. {
  183. cbBuffer = MAXDWORD;
  184. }
  185. else
  186. {
  187. cbBuffer = static_cast<DWORD>(acc.GetBufferCb());
  188. }
  189. lResult = ::RegQueryValueExW(hKey, lpValueName, NULL, &dwType, (LPBYTE)acc.GetBufferPtr(), &cbBuffer);
  190. }
  191. if (lResult != ERROR_SUCCESS)
  192. {
  193. FIND_ERROR_IN_ACCEPTABLE_LIST(lResult, rdwLastError, cExceptionalLastErrorValues);
  194. }
  195. else
  196. {
  197. if (dwType != REG_SZ)
  198. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegistryValueNotREG_SZ, ERROR_INVALID_DATA);
  199. }
  200. FN_EPILOG
  201. }
  202. BOOL
  203. FusionpRegQuerySzValueEx(
  204. DWORD dwFlags,
  205. HKEY hKey,
  206. PCWSTR lpValueName,
  207. CBaseStringBuffer &rBuffer
  208. )
  209. {
  210. DWORD dw = 0;
  211. return ::FusionpRegQuerySzValueEx(dwFlags, hKey, lpValueName, rBuffer, dw, 0);
  212. }
  213. BOOL
  214. FusionpRegQueryDwordValueEx(
  215. DWORD dwFlags,
  216. HKEY hKey,
  217. PCWSTR wszValueName,
  218. PDWORD pdwValue,
  219. DWORD dwDefaultValue
  220. )
  221. {
  222. FN_PROLOG_WIN32
  223. BOOL bMissingValueOk = TRUE;
  224. DWORD dwType = 0;
  225. DWORD dwSize = 0;
  226. ULONG ulResult = 0;
  227. if (pdwValue != NULL)
  228. *pdwValue = dwDefaultValue;
  229. PARAMETER_CHECK(pdwValue != NULL);
  230. PARAMETER_CHECK((dwFlags & ~FUSIONP_REG_QUERY_DWORD_MISSING_VALUE_IS_FAILURE) == 0);
  231. PARAMETER_CHECK(hKey != NULL);
  232. bMissingValueOk = ((dwFlags & FUSIONP_REG_QUERY_DWORD_MISSING_VALUE_IS_FAILURE) != 0);
  233. ulResult = ::RegQueryValueExW(
  234. hKey,
  235. wszValueName,
  236. NULL,
  237. &dwType,
  238. (PBYTE)pdwValue,
  239. &(dwSize = sizeof(*pdwValue)));
  240. //
  241. // If the user said that missing values are not an error, then fake up some
  242. // state stuff and continue.
  243. //
  244. if ((ulResult == ERROR_FILE_NOT_FOUND) && bMissingValueOk)
  245. {
  246. *pdwValue = dwDefaultValue;
  247. dwType = REG_DWORD;
  248. ulResult = ERROR_SUCCESS;
  249. }
  250. //
  251. // Got an error? Send it back
  252. //
  253. if (ulResult != ERROR_SUCCESS)
  254. {
  255. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegQueryValueExW, ulResult);
  256. }
  257. //
  258. // If the type wasn't a dword, then that's a problem.
  259. //
  260. if ((dwType != REG_DWORD) || (dwSize != sizeof(*pdwValue)))
  261. {
  262. *pdwValue = dwDefaultValue;
  263. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegQueryValueExW, ERROR_INVALID_DATA);
  264. }
  265. FN_EPILOG
  266. }
  267. BOOL
  268. CRegKey::DestroyKeyTree()
  269. {
  270. FN_PROLOG_WIN32
  271. CStringBuffer buffTemp;
  272. //
  273. // First go down and delete all our child subkeys
  274. //
  275. while (true)
  276. {
  277. BOOL fFlagTemp = FALSE;
  278. CRegKey hkSubKey;
  279. IFW32FALSE_EXIT( this->EnumKey( 0, buffTemp, NULL, &fFlagTemp ) );
  280. if ( fFlagTemp )
  281. break;
  282. //
  283. // There's more to delete than meets the eye. But don't follow links
  284. // while wandering the registry.
  285. //
  286. IFW32FALSE_EXIT( this->OpenSubKey(
  287. hkSubKey,
  288. buffTemp, KEY_ALL_ACCESS | FUSIONP_KEY_WOW64_64KEY, REG_OPTION_OPEN_LINK) );
  289. if (hkSubKey == this->GetInvalidValue())
  290. {
  291. continue;
  292. }
  293. IFW32FALSE_EXIT( hkSubKey.DestroyKeyTree() );
  294. //
  295. // Delete the key, ignore errors
  296. //
  297. IFW32FALSE_EXIT_UNLESS( this->DeleteKey( buffTemp ),
  298. ( ::FusionpGetLastWin32Error() == ERROR_PATH_NOT_FOUND ) ||
  299. ( ::FusionpGetLastWin32Error() == ERROR_FILE_NOT_FOUND ),
  300. fFlagTemp );
  301. }
  302. // Clear out the entries in the key as well - values as well
  303. while ( true )
  304. {
  305. BOOL fFlagTemp = FALSE;
  306. IFW32FALSE_EXIT( this->EnumValue( 0, buffTemp, NULL, &fFlagTemp ) );
  307. if ( fFlagTemp )
  308. {
  309. break;
  310. }
  311. IFW32FALSE_EXIT_UNLESS( this->DeleteValue( buffTemp ),
  312. ( ::FusionpGetLastWin32Error() == ERROR_PATH_NOT_FOUND ) ||
  313. ( ::FusionpGetLastWin32Error() == ERROR_FILE_NOT_FOUND ),
  314. fFlagTemp );
  315. }
  316. FN_EPILOG
  317. }
  318. BOOL
  319. CRegKey::DeleteValue(
  320. IN PCWSTR pcwszValueName,
  321. OUT DWORD &rdwWin32Error,
  322. IN SIZE_T cExceptionalWin32Errors,
  323. ...
  324. ) const
  325. {
  326. FN_PROLOG_WIN32
  327. LONG l;
  328. rdwWin32Error = ERROR_SUCCESS;
  329. l = ::RegDeleteValueW(*this, pcwszValueName);
  330. if (l != ERROR_SUCCESS)
  331. {
  332. FIND_ERROR_IN_ACCEPTABLE_LIST(l, rdwWin32Error, cExceptionalWin32Errors);
  333. }
  334. FN_EPILOG
  335. }
  336. BOOL
  337. CRegKey::DeleteValue(
  338. IN PCWSTR pcwszValueName
  339. ) const
  340. {
  341. DWORD dw;
  342. return this->DeleteValue(pcwszValueName, dw, 0);
  343. }
  344. BOOL
  345. CRegKey::SetValue(
  346. IN PCWSTR pcwszValueName,
  347. IN DWORD dwValue
  348. ) const
  349. {
  350. return this->SetValue(pcwszValueName, REG_DWORD, (PBYTE) &dwValue, sizeof(dwValue));
  351. }
  352. BOOL
  353. CRegKey::SetValue(
  354. IN PCWSTR pcwszValueName,
  355. IN const CBaseStringBuffer &rcbuffValueValue
  356. ) const
  357. {
  358. return this->SetValue(
  359. pcwszValueName,
  360. REG_SZ,
  361. (PBYTE) (static_cast<PCWSTR>(rcbuffValueValue)),
  362. rcbuffValueValue.GetCbAsDWORD() + sizeof(WCHAR));
  363. }
  364. BOOL
  365. CRegKey::SetValue(
  366. IN PCWSTR pcwszValueName,
  367. IN DWORD dwRegType,
  368. IN const BYTE *pbData,
  369. IN SIZE_T cbData
  370. ) const
  371. {
  372. FN_PROLOG_WIN32
  373. IFREGFAILED_ORIGINATE_AND_EXIT(
  374. ::RegSetValueExW(
  375. *this,
  376. pcwszValueName,
  377. 0,
  378. dwRegType,
  379. pbData,
  380. (DWORD)cbData));
  381. FN_EPILOG
  382. }
  383. BOOL
  384. CRegKey::GetValue(
  385. IN const CBaseStringBuffer &rbuffValueName,
  386. OUT CBaseStringBuffer &rbuffValueData
  387. )
  388. {
  389. return this->GetValue(static_cast<PCWSTR>(rbuffValueName), rbuffValueData);
  390. }
  391. BOOL
  392. CRegKey::GetValue(
  393. IN PCWSTR pcwszValueName,
  394. OUT CBaseStringBuffer &rbuffValueData
  395. )
  396. {
  397. return FusionpRegQuerySzValueEx(0, *this, pcwszValueName, rbuffValueData);
  398. }
  399. BOOL
  400. CRegKey::GetValue(
  401. IN const CBaseStringBuffer &rbuffValueName,
  402. CFusionArray<BYTE> &rbBuffer
  403. )
  404. {
  405. return this->GetValue(static_cast<PCWSTR>(rbuffValueName), rbBuffer);
  406. }
  407. BOOL
  408. CRegKey::GetValue(
  409. IN PCWSTR pcwszValueName,
  410. CFusionArray<BYTE> &rbBuffer
  411. )
  412. {
  413. return ::FusionpRegQueryBinaryValueEx(0, *this, pcwszValueName, rbBuffer);
  414. }
  415. BOOL
  416. CRegKey::EnumValue(
  417. IN DWORD dwIndex,
  418. OUT CBaseStringBuffer &rbuffValueName,
  419. OUT LPDWORD lpdwType,
  420. OUT PBOOL pfDone
  421. )
  422. {
  423. FN_PROLOG_WIN32
  424. DWORD dwMaxRequiredValueNameLength = 0;
  425. DWORD dwMaxRequiredDataLength = 0;
  426. CStringBufferAccessor sbaValueNameAccess;
  427. DWORD dwError = 0;
  428. bool fRetried = false;
  429. if ( pfDone != NULL )
  430. *pfDone = FALSE;
  431. Again:
  432. sbaValueNameAccess.Attach( &rbuffValueName );
  433. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS(
  434. ::RegEnumValueW(
  435. *this,
  436. dwIndex,
  437. sbaValueNameAccess.GetBufferPtr(),
  438. &(dwMaxRequiredValueNameLength = sbaValueNameAccess.GetBufferCbAsDWORD()),
  439. NULL,
  440. lpdwType,
  441. NULL,
  442. NULL),
  443. LIST_2(ERROR_NO_MORE_ITEMS, ERROR_MORE_DATA),
  444. dwError);
  445. if ((dwError == ERROR_MORE_DATA) && !fRetried)
  446. {
  447. sbaValueNameAccess.Detach();
  448. IFW32FALSE_EXIT(
  449. rbuffValueName.Win32ResizeBuffer(
  450. dwMaxRequiredValueNameLength + 1,
  451. eDoNotPreserveBufferContents));
  452. fRetried = true;
  453. goto Again;
  454. }
  455. //
  456. // Otherwise, if the error is "nothing more"
  457. //
  458. else if (dwError == ERROR_NO_MORE_ITEMS)
  459. {
  460. if (pfDone != NULL)
  461. *pfDone = TRUE;
  462. }
  463. //
  464. // Uhoh, we might have failed a second time through or we failed for some other reason -
  465. // originate and exit.
  466. //
  467. else if (dwError != ERROR_SUCCESS)
  468. {
  469. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegEnumValueW, dwError);
  470. }
  471. FN_EPILOG
  472. }
  473. BOOL
  474. CRegKey::LargestSubItemLengths(
  475. PDWORD pdwSubkeyLength,
  476. PDWORD pdwValueLength
  477. ) const
  478. {
  479. FN_PROLOG_WIN32
  480. IFREGFAILED_ORIGINATE_AND_EXIT( ::RegQueryInfoKeyW(
  481. *this, // hkey
  482. NULL, // lpclass
  483. NULL, // lpcbclass
  484. NULL, // lpreserved
  485. NULL, // lpcSubKeys
  486. pdwSubkeyLength, // lpcbMaxSubkeyLength
  487. NULL, // lpcbMaxClassLength
  488. NULL, // lpcValues
  489. pdwValueLength, // lpcbMaxValueNameLength
  490. NULL,
  491. NULL,
  492. NULL));
  493. FN_EPILOG
  494. }
  495. BOOL
  496. CRegKey::EnumKey(
  497. IN DWORD dwIndex,
  498. OUT CBaseStringBuffer &rbuffKeyName,
  499. OUT PFILETIME pftLastWriteTime,
  500. OUT PBOOL pfDone
  501. ) const
  502. {
  503. FN_PROLOG_WIN32
  504. CStringBufferAccessor sba;
  505. DWORD dwLargestKeyName = 0;
  506. BOOL fOutOfItems;
  507. if (pfDone != NULL)
  508. *pfDone = FALSE;
  509. //
  510. // ISSUE: jonwis 3/12/2002 - In a posting to win32prg, it's been noted that on NT/2k/XP
  511. // the RegEnumKeyExW will return ERROR_MORE_DATA when the lpName buffer is
  512. // too small. So, this gross "get longest length, resize" hack can be
  513. // removed, and we can use the normal "attempt, if too small resize reattempt"
  514. // pattern.
  515. //
  516. IFW32FALSE_EXIT(this->LargestSubItemLengths(&dwLargestKeyName, NULL));
  517. if (dwLargestKeyName >= rbuffKeyName.GetBufferCch())
  518. IFW32FALSE_EXIT(
  519. rbuffKeyName.Win32ResizeBuffer(
  520. dwLargestKeyName + 1,
  521. eDoNotPreserveBufferContents));
  522. sba.Attach(&rbuffKeyName);
  523. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS2(
  524. ::RegEnumKeyExW(
  525. *this,
  526. dwIndex,
  527. sba.GetBufferPtr(),
  528. &(dwLargestKeyName = sba.GetBufferCbAsDWORD()),
  529. NULL,
  530. NULL,
  531. NULL,
  532. pftLastWriteTime ),
  533. {ERROR_NO_MORE_ITEMS},
  534. fOutOfItems );
  535. if ( fOutOfItems && ( pfDone != NULL ) )
  536. {
  537. *pfDone = TRUE;
  538. }
  539. FN_EPILOG
  540. }
  541. BOOL
  542. CRegKey::OpenOrCreateSubKey(
  543. OUT CRegKey &Target,
  544. IN PCWSTR SubKeyName,
  545. IN REGSAM rsDesiredAccess,
  546. IN DWORD dwOptions,
  547. IN PDWORD pdwDisposition,
  548. IN PWSTR pwszClass
  549. ) const
  550. {
  551. FN_PROLOG_WIN32
  552. HKEY hKeyNew = NULL;
  553. IFREGFAILED_ORIGINATE_AND_EXIT(
  554. ::RegCreateKeyExW(
  555. *this,
  556. SubKeyName,
  557. 0,
  558. pwszClass,
  559. dwOptions,
  560. rsDesiredAccess | FUSIONP_KEY_WOW64_64KEY,
  561. NULL,
  562. &hKeyNew,
  563. pdwDisposition));
  564. Target = hKeyNew;
  565. FN_EPILOG
  566. }
  567. BOOL
  568. CRegKey::OpenSubKey(
  569. OUT CRegKey &Target,
  570. IN PCWSTR SubKeyName,
  571. IN REGSAM rsDesiredAccess,
  572. IN DWORD ulOptions
  573. ) const
  574. {
  575. FN_PROLOG_WIN32
  576. BOOL fFilePathNotFound;
  577. HKEY hKeyNew = NULL;
  578. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS2( ::RegOpenKeyExW(
  579. *this,
  580. SubKeyName,
  581. ulOptions,
  582. rsDesiredAccess | FUSIONP_KEY_WOW64_64KEY,
  583. &hKeyNew),
  584. LIST_2(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND),
  585. fFilePathNotFound );
  586. if (fFilePathNotFound)
  587. hKeyNew = this->GetInvalidValue();
  588. Target = hKeyNew;
  589. FN_EPILOG
  590. }
  591. BOOL
  592. CRegKey::DeleteKey(
  593. IN PCWSTR pcwszSubkeyName
  594. )
  595. {
  596. FN_PROLOG_WIN32
  597. #if !defined(FUSION_WIN)
  598. IFREGFAILED_ORIGINATE_AND_EXIT(::RegDeleteKeyW(*this, pcwszSubkeyName));
  599. #else
  600. //
  601. // Be sure to delete out of the native (64bit) registry.
  602. // The Win32 call doesn't have a place to pass the flag.
  603. //
  604. CRegKey ChildKey;
  605. NTSTATUS Status = STATUS_SUCCESS;
  606. IFW32FALSE_EXIT(this->OpenSubKey(ChildKey, pcwszSubkeyName, DELETE));
  607. //
  608. // make sure that the Key does exist, OpenSubKey return TRUE for non-existed Key
  609. //
  610. if (ChildKey != this->GetInvalidValue())
  611. {
  612. if (!NT_SUCCESS(Status = NtDeleteKey(ChildKey)))
  613. {
  614. RtlSetLastWin32ErrorAndNtStatusFromNtStatus(Status);
  615. goto Exit;
  616. }
  617. }
  618. #endif
  619. FN_EPILOG
  620. }
  621. BOOL
  622. CRegKey::Save(
  623. IN PCWSTR pcwszTargetFilePath,
  624. IN DWORD dwFlags,
  625. IN LPSECURITY_ATTRIBUTES pSAttrs
  626. )
  627. {
  628. FN_PROLOG_WIN32
  629. IFREGFAILED_ORIGINATE_AND_EXIT(::RegSaveKeyExW(*this, pcwszTargetFilePath, pSAttrs, dwFlags));
  630. FN_EPILOG
  631. }
  632. BOOL
  633. CRegKey::Restore(
  634. IN PCWSTR pcwszSourceFileName,
  635. IN DWORD dwFlags
  636. )
  637. {
  638. FN_PROLOG_WIN32
  639. IFREGFAILED_ORIGINATE_AND_EXIT(::RegRestoreKeyW(*this, pcwszSourceFileName, dwFlags));
  640. FN_EPILOG
  641. }