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.

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