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.

802 lines
22 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996.
  5. //
  6. // registry.cxx
  7. //
  8. // Registry related routines
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "act.hxx"
  12. #ifdef SERVER_HANDLER
  13. BOOL gbDisableEmbeddingServerHandler = FALSE;
  14. #endif // SERVER_HANDLER
  15. BOOL gbSAFERROTChecksEnabled = TRUE;
  16. BOOL gbSAFERAAAChecksEnabled = TRUE;
  17. BOOL gbDynamicIPChangesEnabled = TRUE; // On in whistler; was off by default in W2K
  18. DWORD gdwTimeoutPeriodForStaleMids = 10 * 60 * 1000; // ten minutes
  19. //-------------------------------------------------------------------------
  20. //
  21. // ReadStringValue
  22. //
  23. // Returns the named value string under the specified open registry key.
  24. //
  25. // Returns :
  26. //
  27. // ERROR_SUCCESS, ERROR_FILE_NOT_FOUND, ERROR_BAD_FORMAT, ERROR_OUTOFMEMORY,
  28. // ERROR_BAD_PATHNAME, or other more esoteric win32 error code.
  29. //
  30. //-------------------------------------------------------------------------
  31. DWORD
  32. ReadStringValue(
  33. IN HKEY hKey,
  34. IN WCHAR * pwszValueName,
  35. OUT WCHAR ** ppwszString )
  36. {
  37. DWORD Status;
  38. DWORD Type;
  39. DWORD StringSize;
  40. WCHAR * pwszScan;
  41. WCHAR * pwszSource;
  42. WCHAR wszString[64];
  43. *ppwszString = 0;
  44. StringSize = sizeof(wszString);
  45. Status = RegQueryValueEx(
  46. hKey,
  47. pwszValueName,
  48. NULL,
  49. &Type,
  50. (BYTE *) wszString,
  51. &StringSize );
  52. if ( (ERROR_SUCCESS == Status) &&
  53. (Type != REG_SZ) && (Type != REG_MULTI_SZ) && (Type != REG_EXPAND_SZ) )
  54. Status = ERROR_BAD_FORMAT;
  55. if ( (Status != ERROR_SUCCESS) && (Status != ERROR_MORE_DATA) )
  56. return Status;
  57. // Allocate one extra WCHAR for an extra null at the end.
  58. *ppwszString = (WCHAR *) PrivMemAlloc( StringSize + sizeof(WCHAR) );
  59. if ( ! *ppwszString )
  60. return ERROR_OUTOFMEMORY;
  61. if ( ERROR_MORE_DATA == Status )
  62. {
  63. Status = RegQueryValueEx(
  64. hKey,
  65. pwszValueName,
  66. NULL,
  67. &Type,
  68. (BYTE *) *ppwszString,
  69. &StringSize );
  70. if ( Status != ERROR_SUCCESS )
  71. {
  72. PrivMemFree( *ppwszString );
  73. *ppwszString = 0;
  74. return Status;
  75. }
  76. }
  77. else
  78. {
  79. memcpy( *ppwszString, wszString, StringSize );
  80. }
  81. //
  82. // Put an extra null at the end. This allows using identical logic for both
  83. // REG_SZ and REG_MULTI_SZ values like RemoteServerNames instead of special
  84. // casing it.
  85. //
  86. (*ppwszString)[StringSize/sizeof(WCHAR)] = 0;
  87. //
  88. // Don't bother with any of the following conversions for multi strings.
  89. // They better be in the correct format.
  90. //
  91. if ( REG_MULTI_SZ == Type )
  92. return Status;
  93. pwszScan = pwszSource = *ppwszString;
  94. //
  95. // The original OLE sources had logic for stripping out a quoted
  96. // value. I have no idea on the origin of this or if it is still
  97. // important. It shouldn't hurt anything to keep it in to save
  98. // us from some nasty compatability problem.
  99. // - DKays, 8/96
  100. //
  101. if ( L'\"' == *pwszScan )
  102. {
  103. pwszScan++;
  104. // Copy everything between the quotes.
  105. while ( *pwszScan && (*pwszScan != L'\"') )
  106. *pwszSource++ = *pwszScan++;
  107. *pwszSource = 0;
  108. }
  109. //
  110. // Leading and trailing whitespace would hose us for some values, like
  111. // RemoteServerName or RunAs. These are stripped here. Once again, only
  112. // good things can happen if we put this logic in.
  113. //
  114. pwszScan = *ppwszString;
  115. while ( *pwszScan && ((L' ' == *pwszScan) || (L'\t' == *pwszScan)) )
  116. pwszScan++;
  117. if ( ! *pwszScan )
  118. {
  119. PrivMemFree( *ppwszString );
  120. *ppwszString = 0;
  121. return ERROR_BAD_PATHNAME;
  122. }
  123. if ( *ppwszString < pwszScan )
  124. lstrcpyW( *ppwszString, pwszScan );
  125. pwszScan = *ppwszString + lstrlenW(*ppwszString);
  126. while ( (pwszScan != *ppwszString) &&
  127. ((L' ' == pwszScan[-1]) || (L'\t' == pwszScan[-1])) )
  128. pwszScan--;
  129. *pwszScan = 0;
  130. //
  131. // Finally, handle environment string expansion if necessary.
  132. // Remember to add the extra trailing null again.
  133. //
  134. if ( REG_EXPAND_SZ == Type )
  135. {
  136. WCHAR * pwszExpandedString;
  137. DWORD ExpandedStringSize;
  138. pwszExpandedString = 0;
  139. StringSize /= sizeof(WCHAR);
  140. for (;;)
  141. {
  142. PrivMemFree( pwszExpandedString );
  143. pwszExpandedString = (WCHAR *) PrivMemAlloc( (StringSize + 1) * sizeof(WCHAR) );
  144. if ( ! pwszExpandedString )
  145. {
  146. Status = ERROR_OUTOFMEMORY;
  147. break;
  148. }
  149. ExpandedStringSize = ExpandEnvironmentStrings(
  150. *ppwszString,
  151. pwszExpandedString,
  152. StringSize );
  153. if ( ! ExpandedStringSize )
  154. {
  155. Status = GetLastError();
  156. break;
  157. }
  158. if ( ExpandedStringSize > StringSize )
  159. {
  160. StringSize = ExpandedStringSize;
  161. continue;
  162. }
  163. Status = ERROR_SUCCESS;
  164. break;
  165. }
  166. PrivMemFree( *ppwszString );
  167. if ( ERROR_SUCCESS == Status )
  168. {
  169. pwszExpandedString[lstrlenW(pwszExpandedString)+1] = 0;
  170. *ppwszString = pwszExpandedString;
  171. }
  172. else
  173. {
  174. PrivMemFree( pwszExpandedString );
  175. *ppwszString = 0;
  176. }
  177. }
  178. return Status;
  179. }
  180. //-------------------------------------------------------------------------
  181. //
  182. // ReadStringKeyValue
  183. //
  184. // Reads the unnamed named value string for the specified subkey name
  185. // under the given open registry key.
  186. //
  187. //-------------------------------------------------------------------------
  188. DWORD
  189. ReadStringKeyValue(
  190. IN HKEY hKey,
  191. IN WCHAR * pwszKeyName,
  192. OUT WCHAR ** ppwszString )
  193. {
  194. DWORD Status;
  195. HKEY hSubKey;
  196. Status = RegOpenKeyEx(
  197. hKey,
  198. pwszKeyName,
  199. NULL,
  200. KEY_READ,
  201. &hSubKey );
  202. if ( Status != ERROR_SUCCESS )
  203. return Status;
  204. Status = ReadStringValue( hSubKey, L"", ppwszString );
  205. RegCloseKey( hSubKey );
  206. return Status;
  207. }
  208. //-------------------------------------------------------------------------
  209. //
  210. // ReadSecurityDescriptor
  211. //
  212. // Converts a security descriptor from self relative to absolute form.
  213. // Stuffs in an owner and a group.
  214. //
  215. // Notes :
  216. //
  217. // REGDB_E_INVALIDVALUE is returned when there is something
  218. // at the specified value, but it is not a security descriptor.
  219. //
  220. //-------------------------------------------------------------------------
  221. DWORD
  222. ReadSecurityDescriptor(
  223. IN HKEY hKey,
  224. IN WCHAR * pwszValue,
  225. OUT CSecDescriptor ** ppCSecDescriptor )
  226. {
  227. PSID pGroupSid;
  228. PSID pOwnerSid;
  229. DWORD Size;
  230. DWORD Type;
  231. DWORD Status;
  232. DWORD Size2;
  233. SECURITY_DESCRIPTOR* pSD = NULL;
  234. CSecDescriptor* pCSecDescriptor = NULL;
  235. // Find put how much memory to allocate for the security descriptor.
  236. Size = 0;
  237. *ppCSecDescriptor = NULL;
  238. Status = RegQueryValueEx( hKey, pwszValue, 0, &Type, 0, &Size );
  239. Size2 = Size;
  240. if ( Status != ERROR_SUCCESS )
  241. return Status;
  242. if ( Type != REG_BINARY || (Size < sizeof(SECURITY_DESCRIPTOR)) )
  243. return ERROR_BAD_FORMAT;
  244. //
  245. // Allocate memory for the security descriptor plus the owner and
  246. // group SIDs.
  247. //
  248. #ifdef _WIN64
  249. {
  250. DWORD deltaSize = sizeof( SECURITY_DESCRIPTOR ) - sizeof( SECURITY_DESCRIPTOR_RELATIVE );
  251. ASSERT( deltaSize < sizeof( SECURITY_DESCRIPTOR ) );
  252. deltaSize = (DWORD) OLE2INT_ROUND_UP( deltaSize, sizeof(PVOID) );
  253. Size2 += deltaSize;
  254. }
  255. #endif // _WIN64
  256. // Allocate sd buffer and wrapper class
  257. pSD = (SECURITY_DESCRIPTOR *) PrivMemAlloc( Size2 );
  258. if (!pSD)
  259. return ERROR_OUTOFMEMORY;
  260. // Read the security descriptor.
  261. Status = RegQueryValueEx( hKey, pwszValue, 0, &Type, (PBYTE) pSD, &Size );
  262. if ( Status != ERROR_SUCCESS )
  263. goto ReadSecurityDescriptorEnd;
  264. if ( Type != REG_BINARY )
  265. {
  266. Status = ERROR_BAD_FORMAT;
  267. goto ReadSecurityDescriptorEnd;
  268. }
  269. //
  270. // Fix up the security descriptor.
  271. //
  272. #ifdef _WIN64
  273. if ( MakeAbsoluteSD2( pSD, &Size2 ) == FALSE ) {
  274. Status = ERROR_BAD_FORMAT;
  275. goto ReadSecurityDescriptorEnd;
  276. }
  277. #else // !_WIN64
  278. pSD->Control &= ~SE_SELF_RELATIVE;
  279. pSD->Sacl = NULL;
  280. if ( pSD->Dacl != NULL )
  281. {
  282. if ( (Size < sizeof(ACL) + sizeof(SECURITY_DESCRIPTOR)) ||
  283. ((ULONG) pSD->Dacl > Size - sizeof(ACL)) )
  284. {
  285. Status = ERROR_BAD_FORMAT;
  286. goto ReadSecurityDescriptorEnd;
  287. }
  288. pSD->Dacl = (ACL *) (((char *) pSD) + ((ULONG) pSD->Dacl));
  289. if ( pSD->Dacl->AclSize + sizeof(SECURITY_DESCRIPTOR) > Size )
  290. {
  291. Status = ERROR_BAD_FORMAT;
  292. goto ReadSecurityDescriptorEnd;
  293. }
  294. }
  295. // Set up the owner and group SIDs.
  296. if ( pSD->Group == 0 ||
  297. ((ULONG)pSD->Group) + sizeof(SID) > Size ||
  298. pSD->Owner == 0 ||
  299. ((ULONG)pSD->Owner) + sizeof(SID) > Size )
  300. {
  301. Status = ERROR_BAD_FORMAT;
  302. goto ReadSecurityDescriptorEnd;
  303. }
  304. pSD->Group = (SID *) (((BYTE *) pSD) + (ULONG) (pSD)->Group);
  305. pSD->Owner = (SID *) (((BYTE *) pSD) + (ULONG) (pSD)->Owner);
  306. #endif // !_WIN64
  307. ReadSecurityDescriptorEnd:
  308. if ( Status != ERROR_SUCCESS )
  309. {
  310. if ( pSD )
  311. PrivMemFree( pSD );
  312. return Status;
  313. }
  314. // Allocate wrapper class for refcount semantics
  315. pCSecDescriptor = new CSecDescriptor(pSD);
  316. if (!pCSecDescriptor)
  317. {
  318. PrivMemFree(pSD);
  319. return ERROR_OUTOFMEMORY;
  320. }
  321. ASSERT( IsValidSecurityDescriptor( pCSecDescriptor->GetSD()) );
  322. // New class has refcount of 1, owned by the caller
  323. *ppCSecDescriptor = pCSecDescriptor;
  324. return ERROR_SUCCESS;
  325. }
  326. //-------------------------------------------------------------------------
  327. //
  328. // InitSCMRegistry
  329. //
  330. // Opens global registry keys and settings.
  331. //
  332. //-------------------------------------------------------------------------
  333. HRESULT
  334. InitSCMRegistry()
  335. {
  336. HRESULT hr;
  337. LONG err;
  338. DWORD dwDisp;
  339. ReadRemoteActivationKeys();
  340. ReadRemoteBindingHandleCacheKeys();
  341. ReadSAFERKeys();
  342. ReadDynamicIPChangesKeys();
  343. // Now read the actual values from the registry
  344. // Check if Embedding Server Handler is enabled
  345. #ifdef SERVER_HANDLER
  346. HKEY hkeyOle;
  347. err = RegOpenKeyExA( HKEY_LOCAL_MACHINE,
  348. "SOFTWARE\\Microsoft\\OLE\\DisableEmbeddingServerHandler",
  349. NULL,
  350. KEY_QUERY_VALUE,
  351. &hkeyOle );
  352. if (err == ERROR_SUCCESS)
  353. {
  354. gbDisableEmbeddingServerHandler=TRUE;
  355. RegCloseKey(hkeyOle);
  356. }
  357. #endif // SERVER_HANDLER
  358. return S_OK;
  359. }
  360. //-------------------------------------------------------------------------
  361. //
  362. // ReadRemoteActivationKeys
  363. //
  364. //-------------------------------------------------------------------------
  365. void ReadRemoteActivationKeys()
  366. {
  367. DWORD err;
  368. HKEY hOle;
  369. // Read the DefaultLaunchPermission value (if present) from the registry
  370. if ((err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ,
  371. &hOle)) == ERROR_SUCCESS)
  372. {
  373. DWORD dwStatus;
  374. CSecDescriptor* pSecDescriptor = NULL;
  375. dwStatus = ReadSecurityDescriptor( hOle,
  376. L"DefaultLaunchPermission",
  377. &pSecDescriptor);
  378. if (dwStatus == ERROR_SUCCESS)
  379. {
  380. ASSERT(pSecDescriptor);
  381. SetDefaultLaunchPermissions(pSecDescriptor);
  382. pSecDescriptor->DecRefCount();
  383. }
  384. else
  385. {
  386. // In case of a non-existent or malformed descriptor, reset
  387. // current perms to NULL - this blocks everybody.
  388. ASSERT(!pSecDescriptor);
  389. SetDefaultLaunchPermissions(NULL);
  390. }
  391. RegCloseKey(hOle);
  392. }
  393. }
  394. //-------------------------------------------------------------------------
  395. //
  396. // GetActivationFailureLoggingLevel
  397. //
  398. // Returns current activation failure logging level as specified
  399. // by a certain key in the Registry.
  400. //
  401. // History:
  402. //
  403. // a-sergiv 6-17-99 Created
  404. //
  405. // Returns :
  406. //
  407. // 0 = Discretionary logging. Log by default, client can override
  408. // 1 = Always log. Log all errors no matter what client specified
  409. // 2 = Never log. Never log error no matter what client speciied
  410. //
  411. //-------------------------------------------------------------------------
  412. DWORD
  413. GetActivationFailureLoggingLevel()
  414. {
  415. DWORD err;
  416. DWORD dwSize;
  417. DWORD dwType;
  418. HKEY hOle;
  419. DWORD dwLevel = 0;
  420. if ((err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE", NULL, KEY_READ,
  421. &hOle)) == ERROR_SUCCESS)
  422. {
  423. dwSize = sizeof(DWORD);
  424. if ((err = RegQueryValueEx(hOle, L"ActivationFailureLoggingLevel",
  425. NULL, &dwType, (BYTE *) &dwLevel, &dwSize))
  426. == ERROR_SUCCESS)
  427. {
  428. // Valid values are 0, 1 and 2. The variable is unsigned.
  429. // Assume 0 if invalid value is specified.
  430. if(dwLevel > 2)
  431. dwLevel = 0;
  432. }
  433. else
  434. {
  435. // Assume 0 if not specified
  436. dwLevel = 0;
  437. }
  438. RegCloseKey(hOle);
  439. }
  440. return dwLevel;
  441. }
  442. //
  443. // ReadRegistryIntegerValue
  444. //
  445. // Tries to read a numeric value from the specified value under the key.
  446. // Returns FALSE if it doesn't exist or is of the wrong type, TRUE
  447. // otherwise.
  448. //
  449. BOOL ReadRegistryIntegerValue(HKEY hkey, WCHAR* pwszValue, DWORD* pdwValue)
  450. {
  451. BOOL bResult = FALSE;
  452. DWORD error;
  453. DWORD dwSize = sizeof(DWORD);
  454. DWORD dwType;
  455. DWORD dwValue;
  456. error = RegQueryValueExW(hkey,
  457. pwszValue,
  458. NULL,
  459. &dwType,
  460. (BYTE*)&dwValue,
  461. &dwSize);
  462. if (error == ERROR_SUCCESS &&
  463. dwType == REG_DWORD)
  464. {
  465. *pdwValue = dwValue;
  466. bResult = TRUE;
  467. }
  468. return bResult;
  469. }
  470. //-------------------------------------------------------------------------
  471. //
  472. // ReadRemoteBindingHandleCacheKeys
  473. //
  474. // Reads optional values from the registry to control the behavior of the
  475. // remote binding handle cache (gpRemoteMachineList).
  476. //
  477. //-------------------------------------------------------------------------
  478. void
  479. ReadRemoteBindingHandleCacheKeys()
  480. {
  481. HKEY hOle;
  482. DWORD error;
  483. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  484. L"SOFTWARE\\Microsoft\\OLE",
  485. NULL,
  486. KEY_READ,
  487. &hOle);
  488. if (error == ERROR_SUCCESS)
  489. {
  490. DWORD dwValue;
  491. if (ReadRegistryIntegerValue(hOle, L"RemoteHandleCacheMaxSize", &dwValue))
  492. {
  493. gdwRemoteBindingHandleCacheMaxSize = dwValue;
  494. }
  495. if (ReadRegistryIntegerValue(hOle, L"RemoteHandleCacheMaxLifetime", &dwValue))
  496. {
  497. gdwRemoteBindingHandleCacheMaxLifetime = dwValue;
  498. }
  499. if (ReadRegistryIntegerValue(hOle, L"RemoteHandleCacheMaxIdleTimeout", &dwValue))
  500. {
  501. gdwRemoteBindingHandleCacheIdleTimeout = dwValue;
  502. }
  503. // This one not really a "binding handle cache" knob.
  504. // CODEWORK: all of this registry knob reading code needs to be
  505. // cleaned-up and rewritten.
  506. if (ReadRegistryIntegerValue(hOle, L"StaleMidTimeout", &dwValue))
  507. {
  508. gdwTimeoutPeriodForStaleMids = dwValue;
  509. }
  510. RegCloseKey(hOle);
  511. }
  512. return;
  513. }
  514. //-------------------------------------------------------------------------
  515. //
  516. // ReadSAFERKeys
  517. //
  518. // Reads optional values from the registry to control aspects of our
  519. // SAFER windows support
  520. //
  521. //-------------------------------------------------------------------------
  522. void
  523. ReadSAFERKeys()
  524. {
  525. HKEY hOle;
  526. DWORD error;
  527. DWORD dwType;
  528. DWORD dwSize;
  529. WCHAR wszYN[5];
  530. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  531. L"SOFTWARE\\Microsoft\\OLE",
  532. NULL,
  533. KEY_READ,
  534. &hOle);
  535. if (error == ERROR_SUCCESS)
  536. {
  537. dwSize = sizeof(wszYN) / sizeof(WCHAR);
  538. error = RegQueryValueEx(hOle,
  539. L"SRPRunningObjectChecks",
  540. NULL,
  541. &dwType,
  542. (BYTE*)wszYN,
  543. &dwSize);
  544. if (error == ERROR_SUCCESS && (wszYN[0] == L'n' || wszYN[0] == L'N'))
  545. {
  546. gbSAFERROTChecksEnabled = FALSE;
  547. }
  548. dwSize = sizeof(wszYN) / sizeof(WCHAR);
  549. error = RegQueryValueEx(hOle,
  550. L"SRPActivateAsActivatorChecks",
  551. NULL,
  552. &dwType,
  553. (BYTE*)wszYN,
  554. &dwSize);
  555. if (error == ERROR_SUCCESS && (wszYN[0] == L'n' || wszYN[0] == L'N'))
  556. {
  557. gbSAFERAAAChecksEnabled = FALSE;
  558. }
  559. CloseHandle(hOle);
  560. }
  561. return;
  562. }
  563. //-------------------------------------------------------------------------
  564. //
  565. // ReadDynamicIPChangesKeys
  566. //
  567. // Reads optional values from the registry to control aspects of our
  568. // dynamic IP change support.
  569. //
  570. //-------------------------------------------------------------------------
  571. void
  572. ReadDynamicIPChangesKeys()
  573. {
  574. HKEY hOle;
  575. DWORD error;
  576. DWORD dwType;
  577. DWORD dwSize;
  578. WCHAR wszYN[5];
  579. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  580. L"SOFTWARE\\Microsoft\\OLE",
  581. NULL,
  582. KEY_READ,
  583. &hOle);
  584. if (error == ERROR_SUCCESS)
  585. {
  586. dwSize = sizeof(wszYN) / sizeof(WCHAR);
  587. error = RegQueryValueEx(hOle,
  588. L"EnableSystemDynamicIPTracking",
  589. NULL,
  590. &dwType,
  591. (BYTE*)wszYN,
  592. &dwSize);
  593. // note: in w2k, this code turned the flag on only if the registry
  594. // value was "y" or "Y". In whistler I have reversed these semantics.
  595. if (error == ERROR_SUCCESS && (wszYN[0] == L'n' || wszYN[0] == L'N'))
  596. {
  597. gbDynamicIPChangesEnabled = FALSE;
  598. }
  599. CloseHandle(hOle);
  600. }
  601. return;
  602. }
  603. //-------------------------------------------------------------------------
  604. //
  605. // CRegistryWatcher::CRegistryWatcher
  606. //
  607. // Constructor for CRegistryWatcher.
  608. //
  609. // If allocation of the event fails, or opening the key fails, or registering
  610. // for the notify fails, then Changed() always returns S_OK (yes, it changed).
  611. // This doesn't affect correctness, only speed.
  612. //
  613. //-------------------------------------------------------------------------
  614. CRegistryWatcher::CRegistryWatcher(HKEY hKeyRoot, const WCHAR *wszSubKey)
  615. {
  616. _fValid = FALSE;
  617. _hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
  618. if (!_hEvent)
  619. return;
  620. LONG res = RegOpenKeyEx(hKeyRoot, wszSubKey, 0, KEY_NOTIFY, &_hWatchedKey);
  621. if (res != ERROR_SUCCESS)
  622. {
  623. Cleanup();
  624. return;
  625. }
  626. _fValid = TRUE;
  627. }
  628. //-------------------------------------------------------------------------
  629. //
  630. // CRegistryWatcher::CRegistryWatcher
  631. //
  632. // Determine if the registry key being watched has changed. Returns
  633. // S_OK if it has changed, S_FALSE if not, and an error if something
  634. // failed.
  635. //
  636. //-------------------------------------------------------------------------
  637. HRESULT CRegistryWatcher::Changed()
  638. {
  639. if (!_fValid)
  640. return S_OK;
  641. // _hEvent is auto-reset, so only one thread will re-register.
  642. if (WAIT_OBJECT_0 == WaitForSingleObject(_hEvent, 0))
  643. {
  644. LONG res = RegNotifyChangeKeyValue(_hWatchedKey,
  645. TRUE,
  646. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  647. _hEvent,
  648. TRUE);
  649. if (res != ERROR_SUCCESS)
  650. {
  651. // Could not re-register, so we can't watch the key anymore.
  652. _fValid = FALSE;
  653. return HRESULT_FROM_WIN32(res);
  654. }
  655. else
  656. return S_OK;
  657. }
  658. else
  659. return S_FALSE;
  660. }
  661. void CRegistryWatcher::Cleanup()
  662. {
  663. if (_hEvent)
  664. {
  665. CloseHandle(_hEvent);
  666. _hEvent = NULL;
  667. }
  668. if (_hWatchedKey)
  669. {
  670. RegCloseKey(_hWatchedKey);
  671. _hWatchedKey = NULL;
  672. }
  673. }