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.

1180 lines
33 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. /*
  387. * If caller is requesting write access, then try opening it for writing;
  388. * if that fails with access denied error, then try opening it for reading;
  389. * if key doesn't exist, create the key.
  390. * Else just open it.
  391. */
  392. if(IsWriteSam(sam))
  393. {
  394. // on WinXP, we strip out WRITE_DAC and WRITE_OWNER bits
  395. if (DIGetOSVersion() == WINWH_OS)
  396. {
  397. sam &= ~DI_DAC_OWNER;
  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. // Change for server per Whistler bug 575181
  406. // If error is access denied, try opening the key for reading
  407. if (lRc == ERROR_ACCESS_DENIED)
  408. {
  409. lRc = RegOpenKeyEx(hk, ptszKey, 0, KEY_READ, phk);
  410. }
  411. else
  412. {
  413. // Try to create it
  414. lRc = RegCreateKeyEx
  415. (
  416. hk, // handle of an open key
  417. ptszKey, // address of subkey name
  418. 0, // reserved
  419. NULL, // address of class string
  420. dwOptions, // special options flag
  421. sam, // desired security access
  422. NULL, // inherit the parent's secuirty descriptor
  423. phk, // address of buffer for opened handle
  424. 0 // address of disposition value buffer);
  425. );
  426. }
  427. }
  428. } else
  429. {
  430. lRc = RegOpenKeyEx(hk, ptszKey, 0, sam, phk);
  431. }
  432. if(lRc == ERROR_SUCCESS)
  433. {
  434. hres = S_OK;
  435. } else
  436. {
  437. if(lRc == ERROR_KEY_DELETED || lRc == ERROR_BADKEY)
  438. {
  439. lRc = ERROR_FILE_NOT_FOUND;
  440. }
  441. hres = hresLe(lRc);
  442. }
  443. return hres;
  444. }
  445. /*****************************************************************************
  446. *
  447. * @doc INTERNAL
  448. *
  449. * @func LONG | RegQueryDIDword |
  450. *
  451. * Read a dword value from a sub key of the DirectInput part of the
  452. * registry.
  453. *
  454. * @parm LPCTSTR | ptszSubKey |
  455. *
  456. * Optional path from root of DirectInput registry.
  457. *
  458. * @parm LPCTSTR | ptszValue |
  459. *
  460. * Value name.
  461. *
  462. * @parm DWORD | dwDefault |
  463. *
  464. * Default value to use if there was an error.
  465. *
  466. * @returns
  467. *
  468. * The value read, or the default.
  469. *
  470. *****************************************************************************/
  471. DWORD EXTERNAL
  472. RegQueryDIDword(LPCTSTR ptszPath, LPCTSTR ptszValue, DWORD dwDefault)
  473. {
  474. HKEY hk;
  475. DWORD dw;
  476. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_DINPUT, 0,
  477. KEY_QUERY_VALUE, &hk) == 0)
  478. {
  479. DWORD cb = cbX(dw);
  480. if( ptszPath )
  481. {
  482. HKEY hkSub;
  483. if(RegOpenKeyEx(hk, ptszPath, 0,
  484. KEY_QUERY_VALUE, &hkSub) == 0)
  485. {
  486. RegCloseKey( hk );
  487. hk = hkSub;
  488. }
  489. }
  490. if(RegQueryValueEx(hk, ptszValue, 0, 0, (LPBYTE)&dw, &cb) == 0 &&
  491. cb == cbX(dw))
  492. {
  493. } else
  494. {
  495. dw = dwDefault;
  496. }
  497. RegCloseKey(hk);
  498. } else
  499. {
  500. dw = dwDefault;
  501. }
  502. return dw;
  503. }
  504. //
  505. // A registry key that is opened by an application can be deleted
  506. // without error by another application in both Windows 95 and
  507. // Windows NT. This is by design.
  508. DWORD EXTERNAL
  509. DIWinnt_RegDeleteKey
  510. (
  511. HKEY hStartKey ,
  512. LPCTSTR pKeyName
  513. )
  514. {
  515. #define MAX_KEY_LENGTH ( 256 )
  516. DWORD dwRtn, dwSubKeyLength;
  517. TCHAR szSubKey[MAX_KEY_LENGTH]; // (256) this should be dynamic.
  518. HKEY hKey;
  519. // do not allow NULL or empty key name
  520. if( pKeyName && lstrlen(pKeyName))
  521. {
  522. if( (dwRtn=RegOpenKeyEx(hStartKey,pKeyName,
  523. 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKey )) == ERROR_SUCCESS)
  524. {
  525. while(dwRtn == ERROR_SUCCESS )
  526. {
  527. dwSubKeyLength = MAX_KEY_LENGTH;
  528. dwRtn=RegEnumKeyEx(
  529. hKey,
  530. 0, // always index zero
  531. szSubKey,
  532. &dwSubKeyLength,
  533. NULL,
  534. NULL,
  535. NULL,
  536. NULL
  537. );
  538. if(dwRtn == ERROR_SUCCESS)
  539. {
  540. dwRtn = DIWinnt_RegDeleteKey(hKey, szSubKey);
  541. } else if(dwRtn == ERROR_NO_MORE_ITEMS)
  542. {
  543. dwRtn = RegDeleteKey(hStartKey, pKeyName);
  544. break;
  545. }
  546. }
  547. RegCloseKey(hKey);
  548. // Do not save return code because error
  549. // has already occurred
  550. }
  551. } else
  552. dwRtn = ERROR_BADKEY;
  553. return dwRtn;
  554. }
  555. /*****************************************************************************
  556. *
  557. * @doc INTERNAL
  558. *
  559. * @func HRESULT | hresRegCopyValues |
  560. *
  561. * Copy all the values from one key to another.
  562. *
  563. * @parm HKEY | hkSrc |
  564. *
  565. * Key with values to be copied
  566. * (must be opened with at least KEY_READ access).
  567. *
  568. * @parm HKEY | hkDest |
  569. *
  570. * Key to receive copies (must be opened with at least KEY_WRITE).
  571. *
  572. * @returns
  573. *
  574. * S_OK if all values were successfully copied
  575. * S_FALSE if there were no values to copy.
  576. * Or a memory allocation error code or the failing registry function
  577. * return code converted to a <t HRESULT>.
  578. *
  579. *****************************************************************************/
  580. STDMETHODIMP
  581. hresRegCopyValues( HKEY hkSrc, HKEY hkDest )
  582. {
  583. HRESULT hres;
  584. LONG lRc;
  585. DWORD cItems;
  586. DWORD MaxNameLen;
  587. DWORD MaxDataLen;
  588. DWORD NameLen;
  589. DWORD DataLen;
  590. PTCHAR tszName;
  591. PBYTE pData;
  592. DWORD Type;
  593. EnterProcI(hresRegCopyValues, (_ "xx", hkSrc, hkDest));
  594. lRc = RegQueryInfoKey( hkSrc, // Key,
  595. NULL, NULL, NULL,// Class, cbClass, Reserved,
  596. NULL, NULL, NULL,// NumSubKeys, MaxSubKeyLen, MaxClassLen,
  597. &cItems, // NumValues,
  598. &MaxNameLen, // MaxValueNameLen,
  599. &MaxDataLen, // MaxValueLen,
  600. NULL, NULL ); // Security descriptor, last write
  601. if( lRc == ERROR_SUCCESS )
  602. {
  603. if( cItems )
  604. {
  605. MaxNameLen++; // Take account of NULL terminator
  606. hres = AllocCbPpv( MaxDataLen + MaxNameLen * sizeof(tszName[0]), &pData );
  607. if( FAILED(hres) )
  608. {
  609. SquirtSqflPtszV(sqfl | sqflError,
  610. TEXT("Out of memory copying registry values") );
  611. }
  612. else
  613. {
  614. tszName = (PTCHAR)(pData + MaxDataLen);
  615. do
  616. {
  617. DataLen = MaxDataLen;
  618. NameLen = MaxNameLen;
  619. lRc = RegEnumValue( hkSrc, --cItems, tszName, &NameLen,
  620. NULL, &Type, pData, &DataLen );
  621. if( lRc != ERROR_SUCCESS )
  622. {
  623. SquirtSqflPtszV(sqfl | sqflError,
  624. TEXT("RegEnumValues failed during copy values, code 0x%08x"), lRc );
  625. break;
  626. }
  627. else
  628. {
  629. lRc = RegSetValueEx( hkDest, tszName, 0, Type, pData, DataLen );
  630. if( lRc != ERROR_SUCCESS )
  631. {
  632. SquirtSqflPtszV(sqfl | sqflError,
  633. TEXT("Failed to copy value %s code %x"), tszName, lRc );
  634. break;
  635. }
  636. }
  637. } while( cItems );
  638. FreePpv( &pData );
  639. if( lRc != ERROR_SUCCESS )
  640. {
  641. hres = hresReg( lRc );
  642. }
  643. else
  644. {
  645. hres = S_OK;
  646. }
  647. }
  648. }
  649. else
  650. {
  651. SquirtSqflPtszV(sqfl, TEXT("No values to copy") );
  652. hres = S_FALSE;
  653. }
  654. }
  655. else
  656. {
  657. SquirtSqflPtszV(sqfl | sqflBenign,
  658. TEXT("RegQueryInfoKey failed during value copy, code 0x%08x"), lRc );
  659. hres = hresReg(lRc);
  660. }
  661. ExitOleProc();
  662. return( hres );
  663. } /* hresRegCopyValues */
  664. /*****************************************************************************
  665. *
  666. * @doc INTERNAL
  667. *
  668. * @func HRESULT | hresRegCopyKey |
  669. *
  670. * Make an empty copy of a key.
  671. *
  672. * @parm HKEY | hkSrcRoot |
  673. *
  674. * The Key under the key name to be copied exists.
  675. * (must be opened with at least KEY_READ).
  676. *
  677. * @parm PTCHAR | szSrcName |
  678. * Name of key to copy
  679. *
  680. * @parm PTCHAR | szClass |
  681. * Class of key to copy
  682. *
  683. * @parm HKEY | hkDestRoot |
  684. *
  685. * The Key under which the copy will be created
  686. * (must be opened with at least KEY_WRITE).
  687. *
  688. * @parm PTCHAR | szSrcName |
  689. * Name of new key
  690. *
  691. * @parm PHKEY | phkSub |
  692. *
  693. * The optional pointer to an HKEY to recieve the opened key if it is
  694. * successfully created. If this is NULL, the key is closed.
  695. *
  696. * @returns
  697. *
  698. * S_OK if the new key was created.
  699. * S_FALSE if the new key already existed
  700. * Or the return value of a failing registry function or
  701. * GetSecurityInfo converted to a <t HRESULT>.
  702. *
  703. *****************************************************************************/
  704. STDMETHODIMP
  705. hresRegCopyKey( HKEY hkSrcRoot, PTCHAR szSrcName, PTCHAR szClass,
  706. HKEY hkDestRoot, PTCHAR szDestName, HKEY *phkSub )
  707. {
  708. LONG lRc;
  709. HKEY hkSub;
  710. DWORD dwDisposition;
  711. HRESULT hres;
  712. #ifdef WINNT
  713. HKEY hkSrc;
  714. #endif
  715. EnterProcI(hresRegCopyKey, (_ "xssxs", hkSrcRoot, szSrcName, szClass, hkDestRoot, szDestName));
  716. #ifdef WINNT
  717. lRc = RegOpenKeyEx( hkSrcRoot, szSrcName, 0, KEY_READ, &hkSrc );
  718. if( lRc == ERROR_SUCCESS )
  719. {
  720. SECURITY_ATTRIBUTES sa;
  721. SECURITY_INFORMATION si;
  722. sa.nLength = sizeof( sa );
  723. sa.bInheritHandle = TRUE;
  724. si = OWNER_SECURITY_INFORMATION;
  725. lRc = GetSecurityInfo( hkSrc, SE_REGISTRY_KEY,
  726. si,
  727. NULL, NULL, // Don't care about SID or SID group
  728. NULL, NULL, // Don't care about DACL or SACL
  729. &sa.lpSecurityDescriptor );
  730. RegCloseKey( hkSrc );
  731. if( lRc == ERROR_SUCCESS )
  732. {
  733. lRc = RegCreateKeyEx( hkDestRoot,
  734. szDestName,
  735. 0,
  736. szClass,
  737. REG_OPTION_NON_VOLATILE,
  738. KEY_WRITE,
  739. &sa,
  740. &hkSub,
  741. &dwDisposition );
  742. LocalFree( sa.lpSecurityDescriptor );
  743. if( lRc != ERROR_SUCCESS )
  744. {
  745. SquirtSqflPtszV(sqfl | sqflBenign,
  746. TEXT("Failed to RegCreateKeyEx for key name %s, code 0x%08x"), szDestName, lRc );
  747. }
  748. }
  749. else
  750. {
  751. SquirtSqflPtszV(sqfl | sqflBenign,
  752. TEXT("Failed to GetSecurityInfo for key name %s, code 0x%08x"), szSrcName, lRc );
  753. }
  754. }
  755. else
  756. {
  757. SquirtSqflPtszV(sqfl | sqflBenign,
  758. TEXT("Failed to RegOpenKeyEx for key name %s, code 0x%08x"), szSrcName, lRc );
  759. }
  760. #else
  761. /* On Win9x the source is not used as the name and class is all we need */
  762. hkSrcRoot;
  763. szSrcName;
  764. lRc = RegCreateKeyEx( hkDestRoot,
  765. szDestName,
  766. 0,
  767. szClass,
  768. REG_OPTION_NON_VOLATILE,
  769. KEY_WRITE,
  770. NULL,
  771. &hkSub,
  772. &dwDisposition );
  773. if( lRc != ERROR_SUCCESS )
  774. {
  775. SquirtSqflPtszV(sqfl | sqflBenign,
  776. TEXT("Failed to RegCreateKeyEx for key name %s, code 0x%08x"), szDestName, lRc );
  777. }
  778. #endif /* WINNT */
  779. if( lRc == ERROR_SUCCESS )
  780. {
  781. if( phkSub )
  782. {
  783. *phkSub = hkSub;
  784. }
  785. else
  786. {
  787. RegCloseKey( hkSub );
  788. }
  789. hres =( dwDisposition == REG_CREATED_NEW_KEY ) ? S_OK : S_FALSE;
  790. }
  791. else
  792. {
  793. hres = hresReg( lRc );
  794. }
  795. ExitOleProc();
  796. return( hres );
  797. } /* hresRegCopyKey */
  798. /*****************************************************************************
  799. *
  800. * @doc INTERNAL
  801. *
  802. * @func HRESULT | hresRegCopyKeys |
  803. *
  804. * Copy all the keys under the source key to the root.
  805. *
  806. * @parm HKEY | hkSrc |
  807. *
  808. * Key be copied (must be opened with at least KEY_READ access).
  809. *
  810. * @parm HKEY | hkRoot |
  811. *
  812. * The Key under which the copy will be created
  813. * (must be opened with at least KEY_WRITE).
  814. *
  815. * @parm PDWORD | pMaxNameLen |
  816. *
  817. * An optional pointer to a value which will be filled with the number
  818. * of characters, incl. the NULL terminator, in the longest key name.
  819. *
  820. * @returns
  821. *
  822. * S_OK if all keys were successfully copied
  823. * S_FALSE if there were no keys to copy.
  824. * Or the memory allocation error code or the failing registry
  825. * function return code converted to a <t HRESULT>.
  826. *
  827. *****************************************************************************/
  828. STDMETHODIMP
  829. hresRegCopyKeys( HKEY hkSrc, HKEY hkRoot, PDWORD OPTIONAL pMaxNameLen )
  830. {
  831. HRESULT hres;
  832. LONG lRc;
  833. DWORD cSubKeys;
  834. DWORD MaxNameLen;
  835. DWORD cbName;
  836. PTCHAR szKeyName;
  837. DWORD MaxClassLen;
  838. DWORD cbClass;
  839. PTCHAR szClassName;
  840. EnterProcI(hresRegCopyKeys, (_ "xx", hkSrc, hkRoot ));
  841. lRc = RegQueryInfoKey( hkSrc, // handle to key to query
  842. NULL, NULL, NULL, // Class, cbClass, Reserved
  843. &cSubKeys, // NumSubKeys
  844. &MaxNameLen, // MaxSubKeyLen
  845. &MaxClassLen, // MaxClassLen
  846. NULL, NULL, NULL, // NumValues, MaxValueNameLen, MaxValueLen
  847. NULL, NULL ); // Security descriptor, last write
  848. if( lRc == ERROR_SUCCESS )
  849. {
  850. if( cSubKeys )
  851. {
  852. // Make space for NULL terminators
  853. MaxNameLen++;
  854. MaxClassLen++;
  855. if( pMaxNameLen )
  856. {
  857. *pMaxNameLen = MaxNameLen;
  858. }
  859. /*
  860. * There are keys to copy so allocate buffer sapce for the key and
  861. * key class names.
  862. */
  863. /*
  864. * Prefix warns (mb:34678) that things would go horribly wrong if
  865. * (MaxNameLen + MaxClassLen) * sizeof(szClassName[0]) == 0
  866. * however this cannot happen unless RegQueryInfoKey has some
  867. * catestrophic failure _and_ returned OK.
  868. */
  869. AssertF( (MaxNameLen + MaxClassLen) * sizeof(szClassName[0]) != 0 );
  870. hres = AllocCbPpv( (MaxNameLen + MaxClassLen) * sizeof(szClassName[0]), &szKeyName );
  871. if( FAILED( hres ) )
  872. {
  873. SquirtSqflPtszV(sqfl | sqflError,
  874. TEXT("Out of memory copying subkeys") );
  875. }
  876. else
  877. {
  878. szClassName = &szKeyName[MaxNameLen];
  879. cSubKeys--;
  880. do
  881. {
  882. cbName = MaxNameLen;
  883. cbClass = MaxClassLen;
  884. lRc = RegEnumKeyEx( hkSrc, // Key containing subkeys to enumerate
  885. cSubKeys, // index of subkey to enumerate
  886. szKeyName, // address of buffer for subkey name
  887. &cbName, // address for size of subkey buffer
  888. NULL, // reserved
  889. szClassName,// address of buffer for class string
  890. &cbClass, // address for size of class buffer
  891. NULL ); // address for time key last written to
  892. if( lRc == ERROR_SUCCESS )
  893. {
  894. hres = hresRegCopyKey( hkSrc, szKeyName, szClassName, hkRoot, szKeyName, NULL );
  895. }
  896. else
  897. {
  898. SquirtSqflPtszV(sqfl | sqflError,
  899. TEXT("RegEnumKeyEx failed during copy keys, code 0x%08x"), lRc );
  900. hres = hresReg( hres );
  901. }
  902. if( FAILED( hres ) )
  903. {
  904. break;
  905. }
  906. } while( cSubKeys-- );
  907. FreePpv(&szKeyName);
  908. }
  909. }
  910. else
  911. {
  912. SquirtSqflPtszV(sqfl, TEXT("No keys to copy") );
  913. hres = S_FALSE;
  914. }
  915. }
  916. else
  917. {
  918. SquirtSqflPtszV(sqfl | sqflBenign,
  919. TEXT("RegQueryInfoKey failed during value key, code 0x%08x"), lRc );
  920. hres = hresReg(lRc);
  921. }
  922. ExitOleProc();
  923. return( hres );
  924. } /* hresRegCopyKeys */
  925. /*****************************************************************************
  926. *
  927. * @doc INTERNAL
  928. *
  929. * @func HRESULT | hresRegCopyBranch |
  930. *
  931. * Copy the contents of one key including sub-keys to another.
  932. * Since this function calls itself to copy the contents of subkeys,
  933. * the local variables should be kept to a minimum.
  934. *
  935. * @parm HKEY | hkSrc |
  936. *
  937. * Key to be copied (must be opened with at least KEY_READ access).
  938. *
  939. * @parm HKEY | hkDest |
  940. *
  941. * Key to receive copy (must be opened with at least KEY_WRITE).
  942. *
  943. * @returns
  944. *
  945. * S_OK if the copy completed succesfully
  946. * or the return value from <f hresRegCopyValues>,
  947. * <f hresRegCopyKeys>, memory allocation error or a registry
  948. * function failure code converted to a <t HRESULT>.
  949. *
  950. *****************************************************************************/
  951. STDMETHODIMP
  952. hresRegCopyBranch( HKEY hkSrc, HKEY hkDest )
  953. {
  954. HKEY hkSrcSub;
  955. HKEY hkDestSub;
  956. HRESULT hres;
  957. DWORD dwIdx;
  958. DWORD cbMaxName;
  959. DWORD cbKeyName;
  960. PTCHAR szKeyName;
  961. EnterProcI(hresRegCopyBranch, (_ "xx", hkSrc, hkDest));
  962. hres = hresRegCopyValues( hkSrc, hkDest );
  963. if( SUCCEEDED( hres ) )
  964. {
  965. hres = hresRegCopyKeys( hkSrc, hkDest, &cbMaxName );
  966. if( hres == S_FALSE )
  967. {
  968. /* No keys to recurse into */
  969. hres = S_OK;
  970. }
  971. else if( hres == S_OK )
  972. {
  973. /*
  974. * Assert that a non-zero size buffer is requested
  975. */
  976. AssertF( cbMaxName * sizeof(szKeyName[0]) );
  977. hres = AllocCbPpv( cbMaxName * sizeof(szKeyName[0]), &szKeyName );
  978. if( SUCCEEDED( hres ) )
  979. {
  980. for( dwIdx=0; SUCCEEDED( hres ); dwIdx++ )
  981. {
  982. cbKeyName = cbMaxName;
  983. /*
  984. * Prefix warns (mb:34669 & win:170672) that szKeyName
  985. * could be NULL if the above alloc was for zero bytes.
  986. * This cannot happen as cbMaxName is the length of the
  987. * longest key name, incremented to leave space for null
  988. * termination on a successful call to RegQueryInfoKey
  989. * when at least one key was found.
  990. */
  991. hres = hresReg( RegEnumKeyEx( hkSrc, dwIdx,
  992. szKeyName, &cbKeyName,
  993. NULL, NULL, NULL, NULL ) ); // Reserved, szClass, cbClass, Last Write
  994. if( SUCCEEDED( hres ) )
  995. {
  996. hres = hresReg( RegOpenKeyEx( hkSrc, szKeyName, 0, KEY_READ, &hkSrcSub ) );
  997. if( SUCCEEDED( hres ) )
  998. {
  999. hres = hresReg( RegOpenKeyEx( hkDest, szKeyName, 0, KEY_WRITE, &hkDestSub ) );
  1000. if( SUCCEEDED( hres ) )
  1001. {
  1002. hres = hresRegCopyBranch( hkSrcSub, hkDestSub );
  1003. }
  1004. else
  1005. {
  1006. SquirtSqflPtszV(sqfl | sqflError,
  1007. TEXT("Failed to open destination subkey %s for recursion, code 0x%04x"),
  1008. szKeyName, LOWORD(hres) );
  1009. }
  1010. }
  1011. else
  1012. {
  1013. SquirtSqflPtszV(sqfl | sqflError,
  1014. TEXT("Failed to open source subkey %s for recursion, code 0x%04x"),
  1015. szKeyName, LOWORD(hres) );
  1016. }
  1017. }
  1018. else
  1019. {
  1020. if( hres == hresReg( ERROR_NO_MORE_ITEMS ) )
  1021. {
  1022. /* Recursed all keys */
  1023. hres = S_OK;
  1024. break;
  1025. }
  1026. else
  1027. {
  1028. SquirtSqflPtszV(sqfl | sqflError,
  1029. TEXT("Failed RegEnumKeyEx during subkey recursion, code 0x%04x"),
  1030. LOWORD(hres) );
  1031. }
  1032. }
  1033. }
  1034. FreePpv( &szKeyName );
  1035. }
  1036. else
  1037. {
  1038. SquirtSqflPtszV(sqfl | sqflError,
  1039. TEXT("Out of memory recursing subkeys") );
  1040. }
  1041. }
  1042. else
  1043. {
  1044. if( SUCCEEDED( hres ) )
  1045. {
  1046. RPF( "Unexpected success code 0x%08x from hresRegCopyKeys", hres );
  1047. }
  1048. }
  1049. }
  1050. ExitOleProc();
  1051. return( hres );
  1052. } /* hresRegCopyBranch */