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.

1273 lines
35 KiB

  1. /*****************************************************************************
  2. *
  3. * DIRegUtl.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Registry utility functions.
  10. *
  11. * Contents:
  12. *
  13. *
  14. *****************************************************************************/
  15. #include "dinputpr.h"
  16. /*****************************************************************************
  17. *
  18. * The sqiffle for this file.
  19. *
  20. *****************************************************************************/
  21. #define sqfl sqflRegUtils
  22. /*****************************************************************************
  23. *
  24. * @doc INTERNAL
  25. *
  26. * @func LONG | RegQueryString |
  27. *
  28. * Wrapper for <f RegQueryValueEx> that reads a
  29. * string value from the registry. An annoying quirk
  30. * is that on Windows NT, the returned string might
  31. * not end in a null terminator, so we might need to add
  32. * one manually.
  33. *
  34. * @parm IN HKEY | hk |
  35. *
  36. * Parent registry key.
  37. *
  38. * @parm LPCTSTR | ptszValue |
  39. *
  40. * Value name.
  41. *
  42. * @parm LPTSTR | ptsz |
  43. *
  44. * Output buffer.
  45. *
  46. * @parm DWORD | ctchBuf |
  47. *
  48. * Size of output buffer.
  49. *
  50. * @returns
  51. *
  52. * Registry error code.
  53. *
  54. *****************************************************************************/
  55. LONG EXTERNAL
  56. RegQueryString(HKEY hk, LPCTSTR ptszValue, LPTSTR ptszBuf, DWORD ctchBuf)
  57. {
  58. LONG lRc;
  59. DWORD reg;
  60. #ifdef UNICODE
  61. DWORD cb;
  62. /*
  63. * NT quirk: Non-null terminated strings can exist.
  64. */
  65. cb = cbCtch(ctchBuf);
  66. lRc = RegQueryValueEx(hk, ptszValue, 0, &reg, (PV)ptszBuf, &cb);
  67. if(lRc == ERROR_SUCCESS)
  68. {
  69. if(reg == REG_SZ)
  70. {
  71. /*
  72. * Check the last character. If it is not NULL, then
  73. * append a NULL if there is room.
  74. */
  75. DWORD ctch = ctchCb(cb);
  76. if(ctch == 0)
  77. {
  78. ptszBuf[ctch] = TEXT('\0');
  79. } else if(ptszBuf[ctch-1] != TEXT('\0'))
  80. {
  81. if(ctch < ctchBuf)
  82. {
  83. ptszBuf[ctch] = TEXT('\0');
  84. } else
  85. {
  86. lRc = ERROR_MORE_DATA;
  87. }
  88. }
  89. } else
  90. {
  91. lRc = ERROR_INVALID_DATA;
  92. }
  93. }
  94. #else
  95. /*
  96. * This code is executed only on Win95, so we don't have to worry
  97. * about the NT quirk.
  98. */
  99. lRc = RegQueryValueEx(hk, ptszValue, 0, &reg, (PV)ptszBuf, &ctchBuf);
  100. if(lRc == ERROR_SUCCESS && reg != REG_SZ)
  101. {
  102. lRc = ERROR_INVALID_DATA;
  103. }
  104. #endif
  105. return lRc;
  106. }
  107. /*****************************************************************************
  108. *
  109. * @doc INTERNAL
  110. *
  111. * @func LONG | RegQueryStringValueW |
  112. *
  113. * Wrapper for <f RegQueryValueEx> that handles ANSI/UNICODE
  114. * issues, as well as treating a nonexistent key as if it
  115. * were a null string.
  116. *
  117. * Note that the value name is still a <t LPCTSTR>.
  118. *
  119. * It is assumed that the thing being read is a string.
  120. * Don't use this function to read binary data.
  121. *
  122. * You cannot use this function to query the necessary
  123. * buffer size (again, because I'm lazy). It's not as
  124. * simple as doubling the ansi size, because DBCS may
  125. * result in a non-linear translation function.
  126. *
  127. * @parm IN HKEY | hk |
  128. *
  129. * Parent registry key.
  130. *
  131. * @parm LPCTSTR | ptszValue |
  132. *
  133. * Value name.
  134. *
  135. * @parm LPWSTR | pwsz |
  136. *
  137. * UNICODE output buffer.
  138. *
  139. * @parm LPDWORD | pcbBuf |
  140. *
  141. * Size of UNICODE output buffer. May not exceed
  142. * cbCwch(MAX_PATH).
  143. *
  144. * @returns
  145. *
  146. * Registry error code. On error, the output buffer is
  147. * set to a null string. On an ERROR_MORE_DATA, the
  148. * output buffer is null-terimated.
  149. *
  150. *****************************************************************************/
  151. LONG EXTERNAL
  152. RegQueryStringValueW(HKEY hk, LPCTSTR ptszValue,
  153. LPWSTR pwszBuf, LPDWORD pcbBuf)
  154. {
  155. LONG lRc;
  156. #ifdef UNICODE
  157. AssertF(*pcbBuf > 0);
  158. AssertF(*pcbBuf <= cbCwch(MAX_PATH));
  159. /*
  160. * NT quirk: Non-null terminated strings can exist.
  161. */
  162. lRc = RegQueryString(hk, ptszValue, pwszBuf, ctchCb(*pcbBuf));
  163. #else
  164. /*
  165. * NT quirk: Non-null terminated strings can exist. Fortunately,
  166. * this code is executed only on Win95, which terminates properly.
  167. */
  168. DWORD cb;
  169. TCHAR tszBuf[MAX_PATH];
  170. AssertF(*pcbBuf > 0);
  171. AssertF(*pcbBuf <= cbCwch(MAX_PATH));
  172. /*
  173. * ISSUE-2001/03/29-timgill Incorrect size returned in single case
  174. * Note that we do not get the size perfect in the DBCS case.
  175. *
  176. * Fortunately, the slop is on the high end, where hopefully
  177. * nobody lives or will notice.
  178. *
  179. * Is it worth fixing?
  180. */
  181. cb = cwchCb(*pcbBuf);
  182. lRc = RegQueryValueEx(hk, ptszValue, 0, 0, (PV)tszBuf, &cb);
  183. if(lRc == ERROR_SUCCESS)
  184. {
  185. DWORD cwch;
  186. /*
  187. * Convert the string up to UNICODE.
  188. */
  189. cwch = AToU(pwszBuf, cwchCb(*pcbBuf), tszBuf);
  190. *pcbBuf = cbCwch(cwch);
  191. /*
  192. * If the buffer was not big enough, the return value
  193. * will be zero.
  194. */
  195. if(cwch == 0 && tszBuf[0])
  196. {
  197. lRc = ERROR_MORE_DATA;
  198. } else
  199. {
  200. lRc = ERROR_SUCCESS;
  201. }
  202. }
  203. #endif
  204. /*
  205. * If the buffer was too small, then null-terminate it just
  206. * to make sure.
  207. */
  208. if(lRc == ERROR_MORE_DATA)
  209. {
  210. if(*pcbBuf)
  211. {
  212. pwszBuf[cwchCb(*pcbBuf)-1] = TEXT('\0');
  213. }
  214. } else
  215. /*
  216. * If it was some other error, then wipe out the buffer
  217. * so the caller won't get confused.
  218. */
  219. if(lRc != ERROR_SUCCESS)
  220. {
  221. pwszBuf[0] = TEXT('\0');
  222. /*
  223. * If the error was that the key doesn't exist, then
  224. * treat it as if it existed with a null string.
  225. */
  226. if(lRc == ERROR_FILE_NOT_FOUND)
  227. {
  228. lRc = ERROR_SUCCESS;
  229. }
  230. }
  231. return lRc;
  232. }
  233. /*****************************************************************************
  234. *
  235. * @doc INTERNAL
  236. *
  237. * @func LONG | RegSetStringValueW |
  238. *
  239. * Wrapper for <f RegSetValueEx> that handles ANSI/UNICODE
  240. * issues, as well as converting null strings into nonexistent
  241. * values.
  242. *
  243. * Note that the value name is still a <t LPCTSTR>.
  244. *
  245. * It is assumed that the thing being written is a string.
  246. * Don't use this function to write binary data.
  247. *
  248. * @parm IN HKEY | hk |
  249. *
  250. * Parent registry key.
  251. *
  252. * @parm LPCTSTR | ptszValue |
  253. *
  254. * Value name.
  255. *
  256. * @parm LPCWSTR | pwsz |
  257. *
  258. * UNICODE value to write. A null pointer is valid, indicating
  259. * that the key should be deleted.
  260. *
  261. * @returns
  262. *
  263. * Registry error code.
  264. *
  265. *****************************************************************************/
  266. LONG EXTERNAL
  267. RegSetStringValueW(HKEY hk, LPCTSTR ptszValue, LPCWSTR pwszData)
  268. {
  269. DWORD cwch;
  270. LONG lRc;
  271. if(pwszData)
  272. {
  273. cwch = lstrlenW(pwszData);
  274. } else
  275. {
  276. cwch = 0;
  277. }
  278. if(cwch)
  279. {
  280. #ifdef UNICODE
  281. lRc = RegSetValueExW(hk, ptszValue, 0, REG_SZ,
  282. (PV)pwszData, cbCwch(cwch+1));
  283. #else
  284. DWORD ctch;
  285. TCHAR tszBuf[MAX_PATH];
  286. /*
  287. * Convert the string down to ANSI.
  288. */
  289. ctch = UToA(tszBuf, cA(tszBuf), pwszData);
  290. if(ctch)
  291. {
  292. lRc = RegSetValueEx(hk, ptszValue, 0, REG_SZ,
  293. (PV)tszBuf, cbCtch(ctch+1));
  294. } else
  295. {
  296. lRc = ERROR_CANTWRITE;
  297. }
  298. #endif
  299. } else
  300. {
  301. lRc = RegDeleteValue(hk, ptszValue);
  302. /*
  303. * It is not an error if the key does not already exist.
  304. */
  305. if(lRc == ERROR_FILE_NOT_FOUND)
  306. {
  307. lRc = ERROR_SUCCESS;
  308. }
  309. }
  310. return lRc;
  311. }
  312. #ifndef UNICODE
  313. /*****************************************************************************
  314. *
  315. * @doc INTERNAL
  316. *
  317. * @func LONG | RegDeleteKeyW |
  318. *
  319. * Wrapper for <f RegDeleteKeyA> on non-UNICODE platforms.
  320. *
  321. * @parm IN HKEY | hk |
  322. *
  323. * Parent registry key.
  324. *
  325. * @parm LPCWSTR | pwsz |
  326. *
  327. * Subkey name.
  328. *
  329. * @returns
  330. *
  331. * Registry error code.
  332. *
  333. *****************************************************************************/
  334. LONG EXTERNAL
  335. RegDeleteKeyW(HKEY hk, LPCWSTR pwsz)
  336. {
  337. LONG lRc;
  338. CHAR szBuf[MAX_PATH];
  339. /*
  340. * Convert the string down to ANSI.
  341. */
  342. UToA(szBuf, cA(szBuf), pwsz);
  343. lRc = RegDeleteKeyA(hk, szBuf);
  344. return lRc;
  345. }
  346. #endif
  347. /*****************************************************************************
  348. *
  349. * @doc INTERNAL
  350. *
  351. * @func HRESULT | hresMumbleKeyEx |
  352. *
  353. * Either open or create the key, depending on the degree
  354. * of access requested.
  355. *
  356. * @parm HKEY | hk |
  357. *
  358. * Base key.
  359. *
  360. * @parm LPCTSTR | ptszKey |
  361. *
  362. * Name of subkey, possibly NULL.
  363. *
  364. * @parm REGSAM | sam |
  365. *
  366. * Security access mask.
  367. *
  368. * @parm DWORD | dwOptions |
  369. * Options for RegCreateEx
  370. *
  371. * @parm PHKEY | phk |
  372. *
  373. * Receives output key.
  374. *
  375. * @returns
  376. *
  377. * Return value from <f RegOpenKeyEx> or <f RegCreateKeyEx>,
  378. * converted to an <t HRESULT>.
  379. *
  380. *****************************************************************************/
  381. STDMETHODIMP
  382. hresMumbleKeyEx(HKEY hk, LPCTSTR ptszKey, REGSAM sam, DWORD dwOptions, PHKEY phk)
  383. {
  384. HRESULT hres;
  385. LONG lRc;
  386. BOOL bWinXP = FALSE;
  387. /*
  388. * If caller is requesting write access, then create the key.
  389. * Else just open it.
  390. */
  391. if(IsWriteSam(sam))
  392. {
  393. // on WinXP, we strip out WRITE_DAC and WRITE_OWNER bits
  394. if (DIGetOSVersion() == WINWH_OS)
  395. {
  396. sam &= ~DI_DAC_OWNER;
  397. bWinXP = TRUE;
  398. }
  399. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  400. if( lRc == ERROR_SUCCESS )
  401. {
  402. // Don't need to create it already exists
  403. } else
  404. {
  405. #ifdef WINNT
  406. EXPLICIT_ACCESS ExplicitAccess;
  407. PACL pACL;
  408. DWORD dwErr;
  409. SECURITY_DESCRIPTOR SecurityDesc;
  410. DWORD dwDisposition;
  411. SECURITY_ATTRIBUTES sa;
  412. PSID pSid = NULL;
  413. SID_IDENTIFIER_AUTHORITY authority = SECURITY_WORLD_SID_AUTHORITY;
  414. // Describe the access we want to create the key with
  415. ZeroMemory (&ExplicitAccess, sizeof(ExplicitAccess) );
  416. //set the access depending on the OS (see Whistler bug 318865)
  417. if (bWinXP == TRUE)
  418. {
  419. ExplicitAccess.grfAccessPermissions = DI_KEY_ALL_ACCESS;
  420. }
  421. else
  422. {
  423. ExplicitAccess.grfAccessPermissions = KEY_ALL_ACCESS;
  424. }
  425. ExplicitAccess.grfAccessMode = GRANT_ACCESS;
  426. ExplicitAccess.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  427. if (AllocateAndInitializeSid(
  428. &authority,
  429. 1,
  430. SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0,
  431. &pSid
  432. ))
  433. {
  434. BuildTrusteeWithSid(&(ExplicitAccess.Trustee), pSid );
  435. dwErr = SetEntriesInAcl( 1, &ExplicitAccess, NULL, &pACL );
  436. if( dwErr == ERROR_SUCCESS )
  437. {
  438. AssertF( pACL );
  439. if( InitializeSecurityDescriptor( &SecurityDesc, SECURITY_DESCRIPTOR_REVISION ) )
  440. {
  441. if( SetSecurityDescriptorDacl( &SecurityDesc, TRUE, pACL, FALSE ) )
  442. {
  443. // Initialize a security attributes structure.
  444. sa.nLength = sizeof (SECURITY_ATTRIBUTES);
  445. sa.lpSecurityDescriptor = &SecurityDesc;
  446. sa.bInheritHandle = TRUE;// Use the security attributes to create a key.
  447. lRc = RegCreateKeyEx
  448. (
  449. hk, // handle of an open key
  450. ptszKey, // address of subkey name
  451. 0, // reserved
  452. NULL, // address of class string
  453. dwOptions, // special options flag
  454. ExplicitAccess.grfAccessPermissions, // desired security access
  455. &sa, // address of key security structure
  456. phk, // address of buffer for opened handle
  457. &dwDisposition // address of disposition value buffer);
  458. );
  459. }
  460. else
  461. {
  462. SquirtSqflPtszV( sqflError | sqflRegUtils,
  463. TEXT("SetSecurityDescriptorDacl failed lastError=0x%x "),
  464. GetLastError());
  465. }
  466. }
  467. else
  468. {
  469. SquirtSqflPtszV( sqflError | sqflRegUtils,
  470. TEXT("InitializeSecurityDescriptor failed lastError=0x%x "),
  471. GetLastError());
  472. }
  473. LocalFree( pACL );
  474. }
  475. else
  476. {
  477. SquirtSqflPtszV( sqflError | sqflRegUtils,
  478. TEXT("SetEntriesInACL failed, dwErr=0x%x"), dwErr );
  479. }
  480. }
  481. else
  482. {
  483. SquirtSqflPtszV( sqflError | sqflRegUtils,
  484. TEXT("AllocateAndInitializeSid failed lastError=0x%x "), GetLastError());
  485. }
  486. //Cleanup pSid
  487. if (pSid != NULL)
  488. {
  489. FreeSid(pSid);
  490. }
  491. if( lRc != ERROR_SUCCESS )
  492. {
  493. SquirtSqflPtszV( sqflError,
  494. TEXT("Failed to create regkey %s with security descriptor, lRc=0x%x "),
  495. ptszKey, lRc);
  496. }
  497. #else
  498. lRc = RegCreateKeyEx(hk, ptszKey, 0, 0,
  499. dwOptions,
  500. sam, 0, phk, 0);
  501. #endif
  502. }
  503. } else
  504. {
  505. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  506. }
  507. if(lRc == ERROR_SUCCESS)
  508. {
  509. hres = S_OK;
  510. } else
  511. {
  512. if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY)
  513. {
  514. lRc = ERROR_FILE_NOT_FOUND;
  515. }
  516. hres = hresLe(lRc);
  517. }
  518. return hres;
  519. }
  520. /*****************************************************************************
  521. *
  522. * @doc INTERNAL
  523. *
  524. * @func LONG | RegQueryDIDword |
  525. *
  526. * Read a dword value from a sub key of the DirectInput part of the
  527. * registry.
  528. *
  529. * @parm LPCTSTR | ptszSubKey |
  530. *
  531. * Optional path from root of DirectInput registry.
  532. *
  533. * @parm LPCTSTR | ptszValue |
  534. *
  535. * Value name.
  536. *
  537. * @parm DWORD | dwDefault |
  538. *
  539. * Default value to use if there was an error.
  540. *
  541. * @returns
  542. *
  543. * The value read, or the default.
  544. *
  545. *****************************************************************************/
  546. DWORD EXTERNAL
  547. RegQueryDIDword(LPCTSTR ptszPath, LPCTSTR ptszValue, DWORD dwDefault)
  548. {
  549. HKEY hk;
  550. DWORD dw;
  551. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DINPUT, 0,
  552. KEY_QUERY_VALUE, &hk) == 0)
  553. {
  554. DWORD cb = cbX(dw);
  555. if( ptszPath )
  556. {
  557. HKEY hkSub;
  558. if(RegOpenKeyEx(hk, ptszPath, 0,
  559. KEY_QUERY_VALUE, &hkSub) == 0)
  560. {
  561. RegCloseKey( hk );
  562. hk = hkSub;
  563. }
  564. }
  565. if(RegQueryValueEx(hk, ptszValue, 0, 0, (LPBYTE)&dw, &cb) == 0 &&
  566. cb == cbX(dw))
  567. {
  568. } else
  569. {
  570. dw = dwDefault;
  571. }
  572. RegCloseKey(hk);
  573. } else
  574. {
  575. dw = dwDefault;
  576. }
  577. return dw;
  578. }
  579. //
  580. // A registry key that is opened by an application can be deleted
  581. // without error by another application in both Windows 95 and
  582. // Windows NT. This is by design.
  583. DWORD EXTERNAL
  584. DIWinnt_RegDeleteKey
  585. (
  586. HKEY hStartKey ,
  587. LPCTSTR pKeyName
  588. )
  589. {
  590. #define MAX_KEY_LENGTH ( 256 )
  591. DWORD dwRtn, dwSubKeyLength;
  592. TCHAR szSubKey[MAX_KEY_LENGTH]; // (256) this should be dynamic.
  593. HKEY hKey;
  594. // do not allow NULL or empty key name
  595. if( pKeyName && lstrlen(pKeyName))
  596. {
  597. if( (dwRtn=RegOpenKeyEx(hStartKey,pKeyName,
  598. 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKey )) == ERROR_SUCCESS)
  599. {
  600. while(dwRtn == ERROR_SUCCESS )
  601. {
  602. dwSubKeyLength = MAX_KEY_LENGTH;
  603. dwRtn=RegEnumKeyEx(
  604. hKey,
  605. 0, // always index zero
  606. szSubKey,
  607. &dwSubKeyLength,
  608. NULL,
  609. NULL,
  610. NULL,
  611. NULL
  612. );
  613. if(dwRtn == ERROR_SUCCESS)
  614. {
  615. dwRtn = DIWinnt_RegDeleteKey(hKey, szSubKey);
  616. } else if(dwRtn == ERROR_NO_MORE_ITEMS)
  617. {
  618. dwRtn = RegDeleteKey(hStartKey, pKeyName);
  619. break;
  620. }
  621. }
  622. RegCloseKey(hKey);
  623. // Do not save return code because error
  624. // has already occurred
  625. }
  626. } else
  627. dwRtn = ERROR_BADKEY;
  628. return dwRtn;
  629. }
  630. /*****************************************************************************
  631. *
  632. * @doc INTERNAL
  633. *
  634. * @func HRESULT | hresRegCopyValues |
  635. *
  636. * Copy all the values from one key to another.
  637. *
  638. * @parm HKEY | hkSrc |
  639. *
  640. * Key with values to be copied
  641. * (must be opened with at least KEY_READ access).
  642. *
  643. * @parm HKEY | hkDest |
  644. *
  645. * Key to receive copies (must be opened with at least KEY_WRITE).
  646. *
  647. * @returns
  648. *
  649. * S_OK if all values were successfully copied
  650. * S_FALSE if there were no values to copy.
  651. * Or a memory allocation error code or the failing registry function
  652. * return code converted to a <t HRESULT>.
  653. *
  654. *****************************************************************************/
  655. STDMETHODIMP
  656. hresRegCopyValues( HKEY hkSrc, HKEY hkDest )
  657. {
  658. HRESULT hres;
  659. LONG lRc;
  660. DWORD cItems;
  661. DWORD MaxNameLen;
  662. DWORD MaxDataLen;
  663. DWORD NameLen;
  664. DWORD DataLen;
  665. PTCHAR tszName;
  666. PBYTE pData;
  667. DWORD Type;
  668. EnterProcI(hresRegCopyValues, (_ "xx", hkSrc, hkDest));
  669. lRc = RegQueryInfoKey( hkSrc, // Key,
  670. NULL, NULL, NULL,// Class, cbClass, Reserved,
  671. NULL, NULL, NULL,// NumSubKeys, MaxSubKeyLen, MaxClassLen,
  672. &cItems, // NumValues,
  673. &MaxNameLen, // MaxValueNameLen,
  674. &MaxDataLen, // MaxValueLen,
  675. NULL, NULL ); // Security descriptor, last write
  676. if( lRc == ERROR_SUCCESS )
  677. {
  678. if( cItems )
  679. {
  680. MaxNameLen++; // Take account of NULL terminator
  681. hres = AllocCbPpv( MaxDataLen + MaxNameLen * sizeof(tszName[0]), &pData );
  682. if( FAILED(hres) )
  683. {
  684. SquirtSqflPtszV(sqfl | sqflError,
  685. TEXT("Out of memory copying registry values") );
  686. }
  687. else
  688. {
  689. tszName = (PTCHAR)(pData + MaxDataLen);
  690. do
  691. {
  692. DataLen = MaxDataLen;
  693. NameLen = MaxNameLen;
  694. lRc = RegEnumValue( hkSrc, --cItems, tszName, &NameLen,
  695. NULL, &Type, pData, &DataLen );
  696. if( lRc != ERROR_SUCCESS )
  697. {
  698. SquirtSqflPtszV(sqfl | sqflError,
  699. TEXT("RegEnumValues failed during copy values, code 0x%08x"), lRc );
  700. break;
  701. }
  702. else
  703. {
  704. lRc = RegSetValueEx( hkDest, tszName, 0, Type, pData, DataLen );
  705. if( lRc != ERROR_SUCCESS )
  706. {
  707. SquirtSqflPtszV(sqfl | sqflError,
  708. TEXT("Failed to copy value %s code %x"), tszName, lRc );
  709. break;
  710. }
  711. }
  712. } while( cItems );
  713. FreePpv( &pData );
  714. if( lRc != ERROR_SUCCESS )
  715. {
  716. hres = hresReg( lRc );
  717. }
  718. else
  719. {
  720. hres = S_OK;
  721. }
  722. }
  723. }
  724. else
  725. {
  726. SquirtSqflPtszV(sqfl, TEXT("No values to copy") );
  727. hres = S_FALSE;
  728. }
  729. }
  730. else
  731. {
  732. SquirtSqflPtszV(sqfl | sqflBenign,
  733. TEXT("RegQueryInfoKey failed during value copy, code 0x%08x"), lRc );
  734. hres = hresReg(lRc);
  735. }
  736. ExitOleProc();
  737. return( hres );
  738. } /* hresRegCopyValues */
  739. /*****************************************************************************
  740. *
  741. * @doc INTERNAL
  742. *
  743. * @func HRESULT | hresRegCopyKey |
  744. *
  745. * Make an empty copy of a key.
  746. *
  747. * @parm HKEY | hkSrcRoot |
  748. *
  749. * The Key under the key name to be copied exists.
  750. * (must be opened with at least KEY_READ).
  751. *
  752. * @parm PTCHAR | szSrcName |
  753. * Name of key to copy
  754. *
  755. * @parm PTCHAR | szClass |
  756. * Class of key to copy
  757. *
  758. * @parm HKEY | hkDestRoot |
  759. *
  760. * The Key under which the copy will be created
  761. * (must be opened with at least KEY_WRITE).
  762. *
  763. * @parm PTCHAR | szSrcName |
  764. * Name of new key
  765. *
  766. * @parm PHKEY | phkSub |
  767. *
  768. * The optional pointer to an HKEY to recieve the opened key if it is
  769. * successfully created. If this is NULL, the key is closed.
  770. *
  771. * @returns
  772. *
  773. * S_OK if the new key was created.
  774. * S_FALSE if the new key already existed
  775. * Or the return value of a failing registry function or
  776. * GetSecurityInfo converted to a <t HRESULT>.
  777. *
  778. *****************************************************************************/
  779. STDMETHODIMP
  780. hresRegCopyKey( HKEY hkSrcRoot, PTCHAR szSrcName, PTCHAR szClass,
  781. HKEY hkDestRoot, PTCHAR szDestName, HKEY *phkSub )
  782. {
  783. LONG lRc;
  784. HKEY hkSub;
  785. DWORD dwDisposition;
  786. HRESULT hres;
  787. #ifdef WINNT
  788. HKEY hkSrc;
  789. #endif
  790. EnterProcI(hresRegCopyKey, (_ "xssxs", hkSrcRoot, szSrcName, szClass, hkDestRoot, szDestName));
  791. #ifdef WINNT
  792. lRc = RegOpenKeyEx( hkSrcRoot, szSrcName, 0, KEY_READ, &hkSrc );
  793. if( lRc == ERROR_SUCCESS )
  794. {
  795. SECURITY_ATTRIBUTES sa;
  796. SECURITY_INFORMATION si;
  797. sa.nLength = sizeof( sa );
  798. sa.bInheritHandle = TRUE;
  799. si = OWNER_SECURITY_INFORMATION;
  800. lRc = GetSecurityInfo( hkSrc, SE_REGISTRY_KEY,
  801. si,
  802. NULL, NULL, // Don't care about SID or SID group
  803. NULL, NULL, // Don't care about DACL or SACL
  804. &sa.lpSecurityDescriptor );
  805. RegCloseKey( hkSrc );
  806. if( lRc == ERROR_SUCCESS )
  807. {
  808. lRc = RegCreateKeyEx( hkDestRoot,
  809. szDestName,
  810. 0,
  811. szClass,
  812. REG_OPTION_NON_VOLATILE,
  813. KEY_WRITE,
  814. &sa,
  815. &hkSub,
  816. &dwDisposition );
  817. LocalFree( sa.lpSecurityDescriptor );
  818. if( lRc != ERROR_SUCCESS )
  819. {
  820. SquirtSqflPtszV(sqfl | sqflBenign,
  821. TEXT("Failed to RegCreateKeyEx for key name %s, code 0x%08x"), szDestName, lRc );
  822. }
  823. }
  824. else
  825. {
  826. SquirtSqflPtszV(sqfl | sqflBenign,
  827. TEXT("Failed to GetSecurityInfo for key name %s, code 0x%08x"), szSrcName, lRc );
  828. }
  829. }
  830. else
  831. {
  832. SquirtSqflPtszV(sqfl | sqflBenign,
  833. TEXT("Failed to RegOpenKeyEx for key name %s, code 0x%08x"), szSrcName, lRc );
  834. }
  835. #else
  836. /* On Win9x the source is not used as the name and class is all we need */
  837. hkSrcRoot;
  838. szSrcName;
  839. lRc = RegCreateKeyEx( hkDestRoot,
  840. szDestName,
  841. 0,
  842. szClass,
  843. REG_OPTION_NON_VOLATILE,
  844. KEY_WRITE,
  845. NULL,
  846. &hkSub,
  847. &dwDisposition );
  848. if( lRc != ERROR_SUCCESS )
  849. {
  850. SquirtSqflPtszV(sqfl | sqflBenign,
  851. TEXT("Failed to RegCreateKeyEx for key name %s, code 0x%08x"), szDestName, lRc );
  852. }
  853. #endif /* WINNT */
  854. if( lRc == ERROR_SUCCESS )
  855. {
  856. if( phkSub )
  857. {
  858. *phkSub = hkSub;
  859. }
  860. else
  861. {
  862. RegCloseKey( hkSub );
  863. }
  864. hres =( dwDisposition == REG_CREATED_NEW_KEY ) ? S_OK : S_FALSE;
  865. }
  866. else
  867. {
  868. hres = hresReg( lRc );
  869. }
  870. ExitOleProc();
  871. return( hres );
  872. } /* hresRegCopyKey */
  873. /*****************************************************************************
  874. *
  875. * @doc INTERNAL
  876. *
  877. * @func HRESULT | hresRegCopyKeys |
  878. *
  879. * Copy all the keys under the source key to the root.
  880. *
  881. * @parm HKEY | hkSrc |
  882. *
  883. * Key be copied (must be opened with at least KEY_READ access).
  884. *
  885. * @parm HKEY | hkRoot |
  886. *
  887. * The Key under which the copy will be created
  888. * (must be opened with at least KEY_WRITE).
  889. *
  890. * @parm PDWORD | pMaxNameLen |
  891. *
  892. * An optional pointer to a value which will be filled with the number
  893. * of characters, incl. the NULL terminator, in the longest key name.
  894. *
  895. * @returns
  896. *
  897. * S_OK if all keys were successfully copied
  898. * S_FALSE if there were no keys to copy.
  899. * Or the memory allocation error code or the failing registry
  900. * function return code converted to a <t HRESULT>.
  901. *
  902. *****************************************************************************/
  903. STDMETHODIMP
  904. hresRegCopyKeys( HKEY hkSrc, HKEY hkRoot, PDWORD OPTIONAL pMaxNameLen )
  905. {
  906. HRESULT hres;
  907. LONG lRc;
  908. DWORD cSubKeys;
  909. DWORD MaxNameLen;
  910. DWORD cbName;
  911. PTCHAR szKeyName;
  912. DWORD MaxClassLen;
  913. DWORD cbClass;
  914. PTCHAR szClassName;
  915. EnterProcI(hresRegCopyKeys, (_ "xx", hkSrc, hkRoot ));
  916. lRc = RegQueryInfoKey( hkSrc, // handle to key to query
  917. NULL, NULL, NULL, // Class, cbClass, Reserved
  918. &cSubKeys, // NumSubKeys
  919. &MaxNameLen, // MaxSubKeyLen
  920. &MaxClassLen, // MaxClassLen
  921. NULL, NULL, NULL, // NumValues, MaxValueNameLen, MaxValueLen
  922. NULL, NULL ); // Security descriptor, last write
  923. if( lRc == ERROR_SUCCESS )
  924. {
  925. if( cSubKeys )
  926. {
  927. // Make space for NULL terminators
  928. MaxNameLen++;
  929. MaxClassLen++;
  930. if( pMaxNameLen )
  931. {
  932. *pMaxNameLen = MaxNameLen;
  933. }
  934. /*
  935. * There are keys to copy so allocate buffer sapce for the key and
  936. * key class names.
  937. */
  938. /*
  939. * Prefix warns (mb:34678) that things would go horribly wrong if
  940. * (MaxNameLen + MaxClassLen) * sizeof(szClassName[0]) == 0
  941. * however this cannot happen unless RegQueryInfoKey has some
  942. * catestrophic failure _and_ returned OK.
  943. */
  944. AssertF( (MaxNameLen + MaxClassLen) * sizeof(szClassName[0]) != 0 );
  945. hres = AllocCbPpv( (MaxNameLen + MaxClassLen) * sizeof(szClassName[0]), &szKeyName );
  946. if( FAILED( hres ) )
  947. {
  948. SquirtSqflPtszV(sqfl | sqflError,
  949. TEXT("Out of memory copying subkeys") );
  950. }
  951. else
  952. {
  953. szClassName = &szKeyName[MaxNameLen];
  954. // redefine Max*Len to cbMax* for the loop
  955. MaxNameLen *= sizeof( szKeyName[0] );
  956. MaxNameLen *= sizeof( szClassName[0] );
  957. cSubKeys--;
  958. do
  959. {
  960. cbName = MaxNameLen;
  961. cbClass = MaxClassLen;
  962. lRc = RegEnumKeyEx( hkSrc, // Key containing subkeys to enumerate
  963. cSubKeys, // index of subkey to enumerate
  964. szKeyName, // address of buffer for subkey name
  965. &cbName, // address for size of subkey buffer
  966. NULL, // reserved
  967. szClassName,// address of buffer for class string
  968. &cbClass, // address for size of class buffer
  969. NULL ); // address for time key last written to
  970. if( lRc == ERROR_SUCCESS )
  971. {
  972. hres = hresRegCopyKey( hkSrc, szKeyName, szClassName, hkRoot, szKeyName, NULL );
  973. }
  974. else
  975. {
  976. SquirtSqflPtszV(sqfl | sqflError,
  977. TEXT("RegEnumKeyEx failed during copy keys, code 0x%08x"), lRc );
  978. hres = hresReg( hres );
  979. }
  980. if( FAILED( hres ) )
  981. {
  982. break;
  983. }
  984. } while( cSubKeys-- );
  985. FreePpv(&szKeyName);
  986. }
  987. }
  988. else
  989. {
  990. SquirtSqflPtszV(sqfl, TEXT("No keys to copy") );
  991. hres = S_FALSE;
  992. }
  993. }
  994. else
  995. {
  996. SquirtSqflPtszV(sqfl | sqflBenign,
  997. TEXT("RegQueryInfoKey failed during value key, code 0x%08x"), lRc );
  998. hres = hresReg(lRc);
  999. }
  1000. ExitOleProc();
  1001. return( hres );
  1002. } /* hresRegCopyKeys */
  1003. /*****************************************************************************
  1004. *
  1005. * @doc INTERNAL
  1006. *
  1007. * @func HRESULT | hresRegCopyBranch |
  1008. *
  1009. * Copy the contents of one key including sub-keys to another.
  1010. * Since this function calls itself to copy the contents of subkeys,
  1011. * the local variables should be kept to a minimum.
  1012. *
  1013. * @parm HKEY | hkSrc |
  1014. *
  1015. * Key to be copied (must be opened with at least KEY_READ access).
  1016. *
  1017. * @parm HKEY | hkDest |
  1018. *
  1019. * Key to receive copy (must be opened with at least KEY_WRITE).
  1020. *
  1021. * @returns
  1022. *
  1023. * S_OK if the copy completed succesfully
  1024. * or the return value from <f hresRegCopyValues>,
  1025. * <f hresRegCopyKeys>, memory allocation error or a registry
  1026. * function failure code converted to a <t HRESULT>.
  1027. *
  1028. *****************************************************************************/
  1029. STDMETHODIMP
  1030. hresRegCopyBranch( HKEY hkSrc, HKEY hkDest )
  1031. {
  1032. HKEY hkSrcSub;
  1033. HKEY hkDestSub;
  1034. HRESULT hres;
  1035. DWORD dwIdx;
  1036. DWORD cbMaxName;
  1037. DWORD cbKeyName;
  1038. PTCHAR szKeyName;
  1039. EnterProcI(hresRegCopyBranch, (_ "xx", hkSrc, hkDest));
  1040. hres = hresRegCopyValues( hkSrc, hkDest );
  1041. if( SUCCEEDED( hres ) )
  1042. {
  1043. hres = hresRegCopyKeys( hkSrc, hkDest, &cbMaxName );
  1044. if( hres == S_FALSE )
  1045. {
  1046. /* No keys to recurse into */
  1047. hres = S_OK;
  1048. }
  1049. else if( hres == S_OK )
  1050. {
  1051. /*
  1052. * Assert that a non-zero size buffer is requested
  1053. */
  1054. AssertF( cbMaxName * sizeof(szKeyName[0]) );
  1055. hres = AllocCbPpv( cbMaxName * sizeof(szKeyName[0]), &szKeyName );
  1056. if( SUCCEEDED( hres ) )
  1057. {
  1058. for( dwIdx=0; SUCCEEDED( hres ); dwIdx++ )
  1059. {
  1060. cbKeyName = cbMaxName;
  1061. /*
  1062. * Prefix warns (mb:34669 & win:170672) that szKeyName
  1063. * could be NULL if the above alloc was for zero bytes.
  1064. * This cannot happen as cbMaxName is the length of the
  1065. * longest key name, incremented to leave space for null
  1066. * termination on a successful call to RegQueryInfoKey
  1067. * when at least one key was found.
  1068. */
  1069. hres = hresReg( RegEnumKeyEx( hkSrc, dwIdx,
  1070. szKeyName, &cbKeyName,
  1071. NULL, NULL, NULL, NULL ) ); // Reserved, szClass, cbClass, Last Write
  1072. if( SUCCEEDED( hres ) )
  1073. {
  1074. hres = hresReg( RegOpenKeyEx( hkSrc, szKeyName, 0, KEY_READ, &hkSrcSub ) );
  1075. if( SUCCEEDED( hres ) )
  1076. {
  1077. hres = hresReg( RegOpenKeyEx( hkDest, szKeyName, 0, KEY_WRITE, &hkDestSub ) );
  1078. if( SUCCEEDED( hres ) )
  1079. {
  1080. hres = hresRegCopyBranch( hkSrcSub, hkDestSub );
  1081. }
  1082. else
  1083. {
  1084. SquirtSqflPtszV(sqfl | sqflError,
  1085. TEXT("Failed to open destination subkey %s for recursion, code 0x%04x"),
  1086. szKeyName, LOWORD(hres) );
  1087. }
  1088. }
  1089. else
  1090. {
  1091. SquirtSqflPtszV(sqfl | sqflError,
  1092. TEXT("Failed to open source subkey %s for recursion, code 0x%04x"),
  1093. szKeyName, LOWORD(hres) );
  1094. }
  1095. }
  1096. else
  1097. {
  1098. if( hres == hresReg( ERROR_NO_MORE_ITEMS ) )
  1099. {
  1100. /* Recursed all keys */
  1101. hres = S_OK;
  1102. break;
  1103. }
  1104. else
  1105. {
  1106. SquirtSqflPtszV(sqfl | sqflError,
  1107. TEXT("Failed RegEnumKeyEx during subkey recursion, code 0x%04x"),
  1108. LOWORD(hres) );
  1109. }
  1110. }
  1111. }
  1112. FreePpv( &szKeyName );
  1113. }
  1114. else
  1115. {
  1116. SquirtSqflPtszV(sqfl | sqflError,
  1117. TEXT("Out of memory recursing subkeys") );
  1118. }
  1119. }
  1120. else
  1121. {
  1122. if( SUCCEEDED( hres ) )
  1123. {
  1124. RPF( "Unexpected success code 0x%08x from hresRegCopyKeys", hres );
  1125. }
  1126. }
  1127. }
  1128. ExitOleProc();
  1129. return( hres );
  1130. } /* hresRegCopyBranch */