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.

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