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.

4978 lines
108 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. VRegistry.cpp
  5. Abstract:
  6. A virtual registry for misbehaving registry readers.
  7. This engine has 5 main features:
  8. 1. Key redirection
  9. Eg: HKLM\Software -> HKLM\Hardware
  10. 2. Key and Value spoofing
  11. Eg: HKLM\Software\VersionNumber can be made to appear as a valid
  12. value
  13. HKEY_DYN_DATA can appear valid
  14. 3. Expansion of REG_EXPAND_SZ value type to REG_SZ
  15. Eg: %SystemRoot%\Media will result in C:\WINNT\Media
  16. 4. Support for EnumKey, EnumValue and QueryInfoKey on virtual keys
  17. 5. Support for CreateKey
  18. Other features:
  19. 1. Strip leading '\' characters from keys
  20. 2. Add MAXIMUM_ALLOWED security attributes to all keys
  21. 3. Adjust parameters of QueryInfoKey to match Win95
  22. 4. Enable key deletion for key which still has subkeys
  23. in order to match Win95 behavior for RegDeleteKey
  24. 5. Values and keys can be protected from modification and deletion
  25. 6. Custom triggers on opening a key.
  26. 7. Values that have extra data beyond end of string can be queried
  27. even though the provided buffer is too small for extra data.
  28. Known limitations:
  29. No support for RegSetValue and RegSetValueEx other than known parameter
  30. error and value protection.
  31. Notes:
  32. This is for apps with registry problems
  33. History:
  34. 01/06/2000 linstev Created
  35. 01/10/2000 linstev Added support for RegEnumKey, RegEnumValue
  36. 01/10/2000 linstev Added support for RegCreateKey
  37. 05/05/2000 linstev Parameterized
  38. 10/03/2000 maonis Bug fixes and got rid of the cleanup code in process detach.
  39. 10/30/2000 andyseti Added support for RegDeleteKey
  40. 02/27/2001 robkenny Converted to use CString
  41. 08/07/2001 mikrause Added protectors, enumeration of virtual & non-virtual keys & values,
  42. triggers on opening a key, and querying values with extra data
  43. and a too small buffer.
  44. 10/12/2001 mikrause Added support for custom callbacks on SetValue.
  45. Reimplemented value protectors as do-nothing callbacks.
  46. --*/
  47. #include "precomp.h"
  48. IMPLEMENT_SHIM_BEGIN(VirtualRegistry)
  49. #include "ShimHookMacro.h"
  50. #include "VRegistry.h"
  51. #include "VRegistry_Worker.h"
  52. // Allows us to have only one code path for dumping all APIs or just the APIs
  53. // that had errors
  54. #define ELEVEL(lRet) SUCCESS(lRet) ? eDbgLevelInfo : eDbgLevelError
  55. CRITICAL_SECTION csRegCriticalSection;
  56. // Global instance of Virtual Registry class
  57. CVirtualRegistry VRegistry;
  58. // Used to enable win9x only features
  59. BOOL g_bWin9x = TRUE;
  60. /*++
  61. Class Description:
  62. This class is designed to simplify locking logic. If an object of this
  63. class is instantiated, then internal lock will be taken. As soon as object
  64. is destroyed lock will be released. We also check if the registry has been
  65. initialized. This has to happen late because we don't get notified after
  66. we've been loaded.
  67. History:
  68. 01/10/2000 linstev Created
  69. --*/
  70. static BOOL g_bInitialized = FALSE;
  71. BOOL ParseCommandLineA(LPCSTR lpCommandLine);
  72. class CRegLock
  73. {
  74. public:
  75. CRegLock()
  76. {
  77. EnterCriticalSection(&csRegCriticalSection);
  78. if (!g_bInitialized)
  79. {
  80. VENTRY* ventry = g_pVList;
  81. while (ventry->pfnBuilder)
  82. {
  83. if (ventry->bShouldCall)
  84. {
  85. DPFN( eDbgLevelInfo, " %S", ventry->cName);
  86. ventry->pfnBuilder(ventry->szParam);
  87. if (ventry->szParam)
  88. {
  89. free(ventry->szParam);
  90. }
  91. ventry->bShouldCall = FALSE;
  92. }
  93. ventry++;
  94. }
  95. g_bInitialized = TRUE;
  96. }
  97. }
  98. ~CRegLock()
  99. {
  100. LeaveCriticalSection(&csRegCriticalSection);
  101. }
  102. };
  103. /*++
  104. Function Description:
  105. Remove leading slash from an Unicode string
  106. Arguments:
  107. IN lpSubKey - path to string
  108. Return Value:
  109. Subkey without leading \
  110. History:
  111. 01/06/2000 linstev Created
  112. --*/
  113. LPCWSTR
  114. TrimSlashW(
  115. IN OUT LPCWSTR lpSubKey
  116. )
  117. {
  118. if (!lpSubKey)
  119. {
  120. return lpSubKey;
  121. }
  122. LPWSTR lpNew = (LPWSTR) lpSubKey;
  123. #define REG_MACHINE L"\\Registry\\Machine"
  124. #define REG_USER L"\\Registry\\User"
  125. //
  126. // Pull off the old NT4 legacy stuff. This only works on NT4, but we're
  127. // making it for everyone since it's low risk.
  128. //
  129. if (wcsistr(lpNew, REG_MACHINE) == lpNew)
  130. {
  131. LOGN( eDbgLevelError, "[TrimSlashW] Bypass \\Registry\\Machine");
  132. lpNew += wcslen(REG_MACHINE);
  133. }
  134. else if (wcsistr(lpNew, REG_USER) == lpNew)
  135. {
  136. LOGN( eDbgLevelError, "[TrimSlashW] Bypass \\Registry\\User");
  137. lpNew += wcslen(REG_USER);
  138. }
  139. if (*lpNew == L'\\')
  140. {
  141. LOGN( eDbgLevelError, "[TrimSlashW] Removed slash from key beginning");
  142. lpNew++;
  143. }
  144. return lpNew;
  145. }
  146. /*++
  147. Function Description:
  148. Convert a key from registry format to virtual registry format. i.e.:
  149. HKEY, Path -> VPath. The VPath format has the base included as "HKLM"
  150. instead of HKEY_LOCAL_MACHINE etc.
  151. Algorithm:
  152. 1. Case the different keys and output a 4 letter string
  153. 2. Append subkey if available
  154. Arguments:
  155. IN hkBase - Base key, eg: HKEY_LOCAL_MACHINE
  156. IN lpSubKey - Subkey, eg: SOFTWARE
  157. OUT lpPath - Output, eg: HKLM\SOFTWARE
  158. Return Value:
  159. A string path of the form HKLM\SOFTWARE
  160. History:
  161. 01/06/2000 linstev Created
  162. --*/
  163. LPWSTR
  164. MakePath(
  165. IN HKEY hkBase,
  166. IN LPCWSTR lpKey,
  167. IN LPCWSTR lpSubKey
  168. )
  169. {
  170. DWORD dwSize = 0;
  171. if (hkBase)
  172. {
  173. // Length of HKCU + NULL
  174. dwSize = 5;
  175. }
  176. if (lpKey)
  177. {
  178. dwSize += wcslen(lpKey) + 1;
  179. }
  180. if (lpSubKey)
  181. {
  182. dwSize += wcslen(lpSubKey) + 1;
  183. }
  184. LPWSTR lpPath = (LPWSTR) malloc((dwSize + 1) * sizeof(WCHAR));
  185. if (!lpPath)
  186. {
  187. if (dwSize)
  188. {
  189. DPFN( eDbgLevelError, szOutOfMemory);
  190. }
  191. return NULL;
  192. }
  193. *lpPath = L'\0';
  194. HRESULT hr;
  195. if (hkBase)
  196. {
  197. if (hkBase == HKEY_CLASSES_ROOT)
  198. {
  199. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKCR");
  200. if (FAILED(hr))
  201. {
  202. goto ErrorCleanup;
  203. }
  204. }
  205. else if (hkBase == HKEY_CURRENT_CONFIG)
  206. {
  207. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKCC");
  208. if (FAILED(hr))
  209. {
  210. goto ErrorCleanup;
  211. }
  212. }
  213. else if (hkBase == HKEY_CURRENT_USER)
  214. {
  215. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKCU");
  216. if (FAILED(hr))
  217. {
  218. goto ErrorCleanup;
  219. }
  220. }
  221. else if (hkBase == HKEY_LOCAL_MACHINE)
  222. {
  223. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKLM");
  224. if (FAILED(hr))
  225. {
  226. goto ErrorCleanup;
  227. }
  228. }
  229. else if (hkBase == HKEY_USERS)
  230. {
  231. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKUS");
  232. if (FAILED(hr))
  233. {
  234. goto ErrorCleanup;
  235. }
  236. }
  237. else if (hkBase == HKEY_PERFORMANCE_DATA)
  238. {
  239. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKPD");
  240. if (FAILED(hr))
  241. {
  242. goto ErrorCleanup;
  243. }
  244. }
  245. else if (hkBase == HKEY_DYN_DATA)
  246. {
  247. hr = StringCchCopyW(lpPath, dwSize + 1, L"HKDD");
  248. if (FAILED(hr))
  249. {
  250. goto ErrorCleanup;
  251. }
  252. }
  253. else
  254. {
  255. DPFN( eDbgLevelWarning,
  256. "Key not found: %08lx - did not get an openkey or createkey",
  257. hkBase);
  258. }
  259. }
  260. // Add the key
  261. if (lpKey)
  262. {
  263. if (wcslen(lpPath) != 0)
  264. {
  265. hr = StringCchCatW(lpPath, dwSize + 1, L"\\");
  266. if (FAILED(hr))
  267. {
  268. goto ErrorCleanup;
  269. }
  270. }
  271. hr = StringCchCatW(lpPath, dwSize + 1, lpKey);
  272. if (FAILED(hr))
  273. {
  274. goto ErrorCleanup;
  275. }
  276. }
  277. // Add the subkey
  278. if (lpSubKey)
  279. {
  280. if (wcslen(lpPath) != 0)
  281. {
  282. hr = StringCchCatW(lpPath, dwSize + 1, L"\\");
  283. if (FAILED(hr))
  284. {
  285. goto ErrorCleanup;
  286. }
  287. }
  288. hr = StringCchCatW(lpPath, dwSize + 1, lpSubKey);
  289. if (FAILED(hr))
  290. {
  291. goto ErrorCleanup;
  292. }
  293. }
  294. // The key name can have a trailing slash, so we clean this up
  295. DWORD dwLen = wcslen(lpPath);
  296. if (dwLen && (lpPath[dwLen - 1] == L'\\'))
  297. {
  298. lpPath[dwLen - 1] = L'\0';
  299. }
  300. return lpPath;
  301. ErrorCleanup:
  302. free(lpPath);
  303. return NULL;
  304. }
  305. /*++
  306. Function Description:
  307. Convert a key from Path format into key and subkey format.
  308. Algorithm:
  309. 1. Case the different keys and output a 4 letter string
  310. 2. Append subkey if available
  311. Arguments:
  312. IN lpPath - Path, eg: HKLM\Software
  313. OUT hkBase - Key, eg: HKEY_LOCAL_MACHINE
  314. OUT lpSubKey - Subkey, eg: Software
  315. Return Value:
  316. None
  317. History:
  318. 01/06/2000 linstev Created
  319. --*/
  320. LPWSTR
  321. SplitPath(
  322. IN LPCWSTR lpPath,
  323. OUT HKEY *hkBase
  324. )
  325. {
  326. LPWSTR p = (LPWSTR) lpPath;
  327. // Find first \ or NULL
  328. while (*p && (*p != L'\\')) p++;
  329. if (wcsncmp(lpPath, L"HKCR", 4) == 0)
  330. *hkBase = HKEY_CLASSES_ROOT;
  331. else if (wcsncmp(lpPath, L"HKCC", 4) == 0)
  332. *hkBase = HKEY_CURRENT_CONFIG;
  333. else if (wcsncmp(lpPath, L"HKCU", 4) == 0)
  334. *hkBase = HKEY_CURRENT_USER;
  335. else if (wcsncmp(lpPath, L"HKLM", 4) == 0)
  336. *hkBase = HKEY_LOCAL_MACHINE;
  337. else if (wcsncmp(lpPath, L"HKUS", 4) == 0)
  338. *hkBase = HKEY_USERS;
  339. else if (wcsncmp(lpPath, L"HKPD", 4) == 0)
  340. *hkBase = HKEY_PERFORMANCE_DATA;
  341. else if (wcsncmp(lpPath, L"HKDD", 4) == 0)
  342. *hkBase = HKEY_DYN_DATA;
  343. else
  344. *hkBase = 0;
  345. // Don't allow an invalid base key to get through.
  346. if (*hkBase && lpPath[4] != '\\')
  347. {
  348. *hkBase = 0;
  349. }
  350. if (*p)
  351. {
  352. p++;
  353. }
  354. return p;
  355. }
  356. /*++
  357. Function Description:
  358. Add a virtual key: a key contains other keys and values and will behave
  359. like a normal registry key, but of course has no persistent storage.
  360. Algorithm:
  361. 1. The input string is split apart and a tree is created recursively
  362. 2. The key is created only if it doesn't already exist
  363. Arguments:
  364. IN lpPath - Path to key, eg: "HKLM\\Software"
  365. Return Value:
  366. Pointer to key or NULL
  367. History:
  368. 01/06/2000 linstev Created
  369. --*/
  370. VIRTUALKEY *
  371. VIRTUALKEY::AddKey(
  372. IN LPCWSTR lpPath
  373. )
  374. {
  375. VIRTUALKEY *key;
  376. LPWSTR p = (LPWSTR)lpPath;
  377. // Find first \ or NULL
  378. while (*p && (*p != L'\\')) p++;
  379. // Check if this part already exists
  380. key = keys;
  381. while (key != NULL)
  382. {
  383. if (_wcsnicmp(lpPath, key->wName, p - lpPath) == 0)
  384. {
  385. if (*p == L'\\')
  386. {
  387. // Continue the search
  388. return key->AddKey(p + 1);
  389. }
  390. else
  391. {
  392. // We already added this key
  393. return key;
  394. }
  395. }
  396. key = key->next;
  397. }
  398. // Create a new key
  399. key = (VIRTUALKEY *) malloc(sizeof(VIRTUALKEY));
  400. if (!key)
  401. {
  402. DPFN( eDbgLevelError, szOutOfMemory);
  403. return NULL;
  404. }
  405. ZeroMemory(key, sizeof(VIRTUALKEY));
  406. //
  407. // Still use wcsncpy, because here it specifies number of characters
  408. // to copy, not size of the destination buffer. Add in check
  409. // for destination buffer size.
  410. //
  411. if ( (p - lpPath) > sizeof(key->wName)/sizeof(WCHAR))
  412. {
  413. free (key);
  414. return NULL;
  415. }
  416. wcsncpy((LPWSTR)key->wName, lpPath, p - lpPath);
  417. key->next = keys;
  418. keys = key;
  419. DPFN( eDbgLevelSpew, "Adding Key %S", key->wName);
  420. if (*p == L'\0')
  421. {
  422. // We are at the end of the chain, so just return this one
  423. return key;
  424. }
  425. else
  426. {
  427. // More subkeys to go
  428. return key->AddKey(p + 1);
  429. }
  430. }
  431. /*++
  432. Function Description:
  433. Add a value to a virtual key. The actual registry key may exist and the
  434. value may even exist, but this value will override.
  435. Algorithm:
  436. 1. If lpData is a string and cbData is 0, calculate the size
  437. 2. Add this value (no duplicate checking)
  438. Arguments:
  439. IN lpValueName - Value name
  440. IN dwType - Type of key; eg: REG_SZ, REG_DWORD etc
  441. IN lpData - Data, use unicode if string
  442. IN cbData - Size of lpData
  443. Return Value:
  444. Pointer to value or NULL
  445. History:
  446. 01/06/2000 linstev Created
  447. --*/
  448. VIRTUALVAL *
  449. VIRTUALKEY::AddValue(
  450. IN LPCWSTR lpValueName,
  451. IN DWORD dwType,
  452. IN BYTE *lpData,
  453. IN DWORD cbData
  454. )
  455. {
  456. // Parameter validation
  457. if (lpData == NULL && cbData != 0)
  458. {
  459. return NULL;
  460. }
  461. VIRTUALVAL *value = (VIRTUALVAL *) malloc(sizeof(VIRTUALVAL));
  462. if (!value)
  463. {
  464. DPFN( eDbgLevelError, szOutOfMemory);
  465. return NULL;
  466. }
  467. ZeroMemory(value, sizeof(VIRTUALVAL));
  468. // Auto calculate size if cbData is 0
  469. if (lpData && (cbData == 0))
  470. {
  471. switch (dwType)
  472. {
  473. case REG_SZ:
  474. case REG_EXPAND_SZ:
  475. cbData = wcslen((LPWSTR)lpData)*2 + sizeof(WCHAR);
  476. break;
  477. case REG_DWORD:
  478. cbData = sizeof(DWORD);
  479. break;
  480. }
  481. }
  482. // lpValueName can == NULL, which means default value
  483. if (lpValueName)
  484. {
  485. HRESULT hr = StringCchCopy(value->wName, sizeof(value->wName)/sizeof(WCHAR), lpValueName);
  486. if (FAILED(hr))
  487. {
  488. free(value);
  489. return NULL;
  490. }
  491. }
  492. if (cbData)
  493. {
  494. // Make a copy of the data if needed
  495. value->lpData = (BYTE *) malloc(cbData);
  496. if (!value->lpData)
  497. {
  498. DPFN( eDbgLevelError, szOutOfMemory);
  499. free(value);
  500. return NULL;
  501. }
  502. MoveMemory(value->lpData, lpData, cbData);
  503. value->cbData = cbData;
  504. }
  505. value->pfnQueryValue = NULL;
  506. value->pfnSetValue = NULL;
  507. value->dwType = dwType;
  508. value->next = values;
  509. values = value;
  510. if (lpData && ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)))
  511. {
  512. DPFN( eDbgLevelSpew, "Adding Value %S\\%S = %S", wName, lpValueName, lpData);
  513. }
  514. else
  515. {
  516. DPFN( eDbgLevelSpew, "Adding Value %S\\%S", wName, lpValueName);
  517. }
  518. return value;
  519. }
  520. /*++
  521. Function Description:
  522. Add a dword value to a key. Calls off to AddValue.
  523. Arguments:
  524. IN lpValueName - Value name
  525. IN Value - DWord value
  526. Return Value:
  527. Pointer to a virtual dword value
  528. History:
  529. 05/25/2000 linstev Created
  530. --*/
  531. VIRTUALVAL *
  532. VIRTUALKEY::AddValueDWORD(
  533. IN LPCWSTR lpValueName,
  534. IN DWORD dwValue
  535. )
  536. {
  537. return AddValue(lpValueName, REG_DWORD, (LPBYTE)&dwValue);
  538. }
  539. /*++
  540. Function Description:
  541. Add an expander to a key. An expander causes QueryValue to expand the
  542. REG_EXPAND_SZ type to a REG_SZ type. The expander itself is just
  543. a virtual value which allows us to intercept queries to it.
  544. Arguments:
  545. IN lpValueName - Value name
  546. Return Value:
  547. Pointer to a virtual value
  548. History:
  549. 01/06/2000 linstev Created
  550. --*/
  551. VIRTUALVAL *
  552. VIRTUALKEY::AddExpander(
  553. IN LPCWSTR lpValueName
  554. )
  555. {
  556. VIRTUALVAL *value = AddValue(lpValueName, REG_SZ, 0, 0);
  557. if (value)
  558. {
  559. value->pfnQueryValue = VR_Expand;
  560. }
  561. return value;
  562. }
  563. /*++
  564. Function Description:
  565. Add a protector on a value. A protector causes SetValue to
  566. be ignored. This is implemented through a custom setvalue
  567. callback that does nothing.
  568. Arguments:
  569. IN lpValueName - Value name
  570. Return Value:
  571. Pointer to a virtual value
  572. History:
  573. 10/12/2001 mikrause Created
  574. --*/
  575. VIRTUALVAL *
  576. VIRTUALKEY::AddProtector(
  577. IN LPCWSTR lpValueName
  578. )
  579. {
  580. VIRTUALVAL *value = AddValue(lpValueName, REG_SZ, 0, 0);
  581. if (value)
  582. {
  583. value->pfnSetValue = VR_Protect;
  584. }
  585. return value;
  586. }
  587. /*++
  588. Function Description:
  589. Add a custom queryvalue routine
  590. Arguments:
  591. IN lpValueName - Value name
  592. IN pfnQueryValue - routine to call when this value is queried
  593. Return Value:
  594. Pointer to a virtual value
  595. History:
  596. 07/18/2000 linstev Created
  597. --*/
  598. VIRTUALVAL *
  599. VIRTUALKEY::AddCustom(
  600. IN LPCWSTR lpValueName,
  601. _pfn_QueryValue pfnQueryValue
  602. )
  603. {
  604. VIRTUALVAL *value = AddValue(lpValueName, REG_SZ, 0, 0);
  605. if (value)
  606. {
  607. value->pfnQueryValue = pfnQueryValue;
  608. }
  609. return value;
  610. }
  611. /*++
  612. Function Description:
  613. Add a custom setvalue routine
  614. Arguments:
  615. IN lpValueName - Value name
  616. IN pfnSetValue - routine to call when this value is set
  617. Return Value:
  618. Pointer to a virtual value
  619. History:
  620. 11/06/2001 mikrause Created
  621. --*/
  622. VIRTUALVAL *
  623. VIRTUALKEY::AddCustomSet(
  624. IN LPCWSTR lpValueName,
  625. _pfn_SetValue pfnSetValue
  626. )
  627. {
  628. VIRTUALVAL *value = AddValue(lpValueName, REG_SZ, 0, 0);
  629. if (value)
  630. {
  631. value->pfnSetValue = pfnSetValue;
  632. }
  633. return value;
  634. }
  635. /*++
  636. Function Description:
  637. Find a subkey of a key.
  638. Algorithm:
  639. 1. Recursively search the tree for the matching subkey
  640. Arguments:
  641. IN lpKeyName - Name of key to find
  642. Return Value:
  643. Pointer to value or NULL
  644. History:
  645. 01/06/2000 linstev Created
  646. --*/
  647. VIRTUALKEY *
  648. VIRTUALKEY::FindKey(
  649. IN LPCWSTR lpPath
  650. )
  651. {
  652. VIRTUALKEY *key = keys;
  653. LPWSTR p = (LPWSTR)lpPath;
  654. if (!lpPath)
  655. {
  656. return NULL;
  657. }
  658. // Find first \ or NULL
  659. while (*p && (*p != L'\\')) p++;
  660. // recursively look for the key
  661. while (key)
  662. {
  663. if (_wcsnicmp(
  664. lpPath,
  665. key->wName,
  666. max((DWORD_PTR)(p - lpPath), wcslen(key->wName))) == 0)
  667. {
  668. if (*p == L'\\')
  669. {
  670. key = key->FindKey(p + 1);
  671. }
  672. break;
  673. }
  674. key = key->next;
  675. }
  676. // We're at the end of the chain
  677. return key;
  678. }
  679. /*++
  680. Function Description:
  681. Find a value in a key.
  682. Arguments:
  683. IN key - Key used for expanders; unused at this time
  684. IN lpValueName - Value name
  685. Return Value:
  686. Pointer to value or NULL
  687. History:
  688. 01/06/2000 linstev Created
  689. --*/
  690. VIRTUALVAL *
  691. VIRTUALKEY::FindValue(
  692. IN LPCWSTR lpValueName
  693. )
  694. {
  695. VIRTUALVAL *value = values;
  696. WCHAR wDef[1] = L"";
  697. LPWSTR lpName;
  698. if (!lpValueName)
  699. {
  700. lpName = (LPWSTR)wDef;
  701. }
  702. else
  703. {
  704. lpName = (LPWSTR)lpValueName;
  705. }
  706. // Find the value
  707. while (value)
  708. {
  709. if (_wcsicmp(lpName, value->wName) == 0)
  710. {
  711. LOGN( eDbgLevelWarning, "[FindValue] Using virtual value: %S", value->wName);
  712. break;
  713. }
  714. value = value->next;
  715. }
  716. return value;
  717. }
  718. /*++
  719. Function Description:
  720. Free the subkeys and values belonging to a key
  721. Algorithm:
  722. 1. Free all values belonging to a key, including any data
  723. 2. Free all subkeys recursively
  724. Arguments:
  725. None
  726. Return Value:
  727. None
  728. History:
  729. 01/06/2000 linstev Created
  730. --*/
  731. VOID
  732. VIRTUALKEY::Free()
  733. {
  734. VIRTUALVAL *value = values;
  735. VIRTUALKEY *key = keys;
  736. while (value)
  737. {
  738. values = value->next;
  739. if (value->lpData)
  740. {
  741. free((PVOID) value->lpData);
  742. }
  743. free((PVOID) value);
  744. value = values;
  745. }
  746. while (key)
  747. {
  748. keys = key->next;
  749. key->Free();
  750. free((PVOID) key);
  751. key = keys;
  752. }
  753. DPFN( eDbgLevelSpew, "Free keys and values from %S", wName);
  754. }
  755. /*++
  756. Function Description:
  757. Allocate a new enum entry
  758. Arguments:
  759. IN wzPath - Key path or value name of entry.
  760. IN next - Next entry in the list.
  761. Return Value:
  762. Pointer to new entry or NULL
  763. History:
  764. 08/21/2001 mikrause Created
  765. --*/
  766. ENUMENTRY*
  767. CreateNewEnumEntry(
  768. IN LPWSTR wzPath,
  769. IN ENUMENTRY* next)
  770. {
  771. ENUMENTRY* enumEntry;
  772. enumEntry = (ENUMENTRY*)malloc(sizeof(ENUMENTRY));
  773. if (enumEntry == NULL)
  774. {
  775. DPFN( eDbgLevelError, szOutOfMemory);
  776. return NULL;
  777. }
  778. ZeroMemory(enumEntry, sizeof(ENUMENTRY));
  779. enumEntry->wzName = (LPWSTR)malloc((wcslen(wzPath) + 1)*sizeof(WCHAR));
  780. if (enumEntry->wzName == NULL)
  781. {
  782. free(enumEntry);
  783. DPFN( eDbgLevelError, szOutOfMemory);
  784. return NULL;
  785. }
  786. HRESULT hr = StringCchCopyW(enumEntry->wzName, wcslen(wzPath)+1, wzPath);
  787. if (FAILED(hr))
  788. {
  789. free(enumEntry->wzName);
  790. free(enumEntry);
  791. return NULL;
  792. }
  793. enumEntry->next = next;
  794. return enumEntry;
  795. }
  796. /*++
  797. Function Description:
  798. Add enumeration entries to a list. Templatized,
  799. so the same code works for keys or values.
  800. Arguments:
  801. IN entryHead - Head of the list containing virtual keys or values.
  802. IN enumFunc - Enumeration function to use. Either RegEnumKey or RegEnumValue
  803. Return Value:
  804. Pointer to the head of the entry list, or NULL.
  805. History:
  806. 08/21/2001 mikrause Created
  807. --*/
  808. template<class T>
  809. ENUMENTRY*
  810. OPENKEY::AddEnumEntries(T* entryHead, _pfn_EnumFunction enumFunc)
  811. {
  812. LONG lRet;
  813. DWORD dwIndex;
  814. DWORD dwSize;
  815. WCHAR wzName[MAX_PATH + 1];
  816. ENUMENTRY* enumEntryList = NULL;
  817. ENUMENTRY* newEnumEntry = NULL;
  818. // Add virtual entries to the list.
  819. T* entry = entryHead;
  820. while (entry)
  821. {
  822. // Create a new entry.
  823. newEnumEntry = CreateNewEnumEntry(entry->wName, enumEntryList);
  824. if (newEnumEntry != NULL)
  825. {
  826. enumEntryList = newEnumEntry;
  827. }
  828. entry = entry->next;
  829. }
  830. // Now non-virtuals.
  831. if (bVirtual == FALSE)
  832. {
  833. dwIndex = 0;
  834. for (;;)
  835. {
  836. dwSize = MAX_PATH * sizeof(WCHAR);
  837. lRet = enumFunc(hkOpen, dwIndex, wzName, &dwSize, NULL, NULL, NULL, NULL);
  838. // No more items, we're done.
  839. if (lRet == ERROR_NO_MORE_ITEMS)
  840. {
  841. break;
  842. }
  843. //
  844. // Check for error.
  845. // On Win2K, this can return more data if there are additional keys.
  846. //
  847. if (lRet != ERROR_SUCCESS && lRet != ERROR_MORE_DATA)
  848. {
  849. break;
  850. }
  851. // Check if this key is a duplicate.
  852. entry = entryHead;
  853. while (entry)
  854. {
  855. if (_wcsicmp(entry->wName, wzName) == 0)
  856. {
  857. break;
  858. }
  859. entry = entry->next;
  860. }
  861. // Add this key to the list, if it's not a duplicate.
  862. if (entry == NULL)
  863. {
  864. // Create a new entry.
  865. newEnumEntry = CreateNewEnumEntry(wzName, enumEntryList);
  866. if (newEnumEntry != NULL)
  867. {
  868. enumEntryList = newEnumEntry;
  869. }
  870. }
  871. dwIndex++;
  872. }
  873. }
  874. return enumEntryList;
  875. }
  876. /*++
  877. Function Description:
  878. Builds the list of enumerated keys and values.
  879. Arguments:
  880. None
  881. Return Value:
  882. None
  883. History:
  884. 08/10/2001 mikrause Created
  885. --*/
  886. VOID
  887. OPENKEY::BuildEnumList()
  888. {
  889. VIRTUALKEY* keyHead = NULL;
  890. VIRTUALVAL* valHead = NULL;
  891. if (vkey)
  892. {
  893. keyHead = vkey->keys;
  894. valHead = vkey->values;
  895. }
  896. enumKeys = AddEnumEntries(keyHead, (_pfn_EnumFunction)ORIGINAL_API(RegEnumKeyExW));
  897. enumValues = AddEnumEntries(valHead, (_pfn_EnumFunction)ORIGINAL_API(RegEnumValueW));
  898. }
  899. /*++
  900. Function Description:
  901. Flushes all enumerated data..
  902. Arguments:
  903. None
  904. Return Value:
  905. None
  906. History:
  907. 08/10/2001 mikrause Created
  908. --*/
  909. VOID
  910. OPENKEY::FlushEnumList()
  911. {
  912. ENUMENTRY *enumentry;
  913. DPFN(eDbgLevelInfo, "Flushing enumeration data for %S", wzPath);
  914. while (enumKeys)
  915. {
  916. enumentry = enumKeys;
  917. enumKeys = enumKeys->next;
  918. if (enumentry->wzName)
  919. {
  920. free(enumentry->wzName);
  921. }
  922. free(enumentry);
  923. }
  924. while (enumValues)
  925. {
  926. enumentry = enumValues;
  927. enumValues = enumValues->next;
  928. if (enumentry->wzName)
  929. {
  930. free(enumentry->wzName);
  931. }
  932. free(enumentry);
  933. }
  934. enumKeys = enumValues = NULL;
  935. }
  936. /*++
  937. Function Description:
  938. Initialize the virtual registry. This would ordinarily go into the
  939. constructor, but because of the shim architecture, we need to explicity
  940. initialize and free the virtual registry.
  941. Arguments:
  942. None
  943. Return Value:
  944. None
  945. History:
  946. 01/06/2000 linstev Created
  947. --*/
  948. BOOL
  949. CVirtualRegistry::Init()
  950. {
  951. OpenKeys = NULL;
  952. Redirectors = NULL;
  953. KeyProtectors = NULL;
  954. OpenKeyTriggers = NULL;
  955. Root = (VIRTUALKEY *) malloc(sizeof(VIRTUALKEY));
  956. if (!Root)
  957. {
  958. DPFN(eDbgLevelError, szOutOfMemory);
  959. return FALSE;
  960. }
  961. ZeroMemory(Root, sizeof(VIRTUALKEY));
  962. HRESULT hr = StringCchCopyW(Root->wName, sizeof(Root->wName)/sizeof(WCHAR), L"ROOT");
  963. if (FAILED(hr))
  964. {
  965. return FALSE;
  966. }
  967. DPFN( eDbgLevelSpew, "Initializing Virtual Registry");
  968. return TRUE;
  969. }
  970. /*++
  971. Function Description:
  972. Free the lists contained by the virtual registry. This includes keys,
  973. their values and redirectors.
  974. Algorithm:
  975. 1. Free virtual root key which recursively frees subkeys and values
  976. 2. Free open keys
  977. 3. Free redirectors
  978. Arguments:
  979. None
  980. Return Value:
  981. None
  982. History:
  983. 01/06/2000 linstev Created
  984. --*/
  985. VOID
  986. CVirtualRegistry::Free()
  987. {
  988. OPENKEY *key;
  989. REDIRECTOR *redirect;
  990. OPENKEYTRIGGER *trigger;
  991. PROTECTOR *protector;
  992. DPFN( eDbgLevelSpew, "Freeing Virtual Registry");
  993. // Free Root and all subkeys/values
  994. if (Root)
  995. {
  996. Root->Free();
  997. free(Root);
  998. Root = NULL;
  999. }
  1000. // Delete all enumeration data.
  1001. FlushEnumLists();
  1002. // Free list of open registry keys
  1003. key = OpenKeys;
  1004. while (key)
  1005. {
  1006. OpenKeys = key->next;
  1007. free(key->wzPath);
  1008. free(key);
  1009. key = OpenKeys;
  1010. }
  1011. // Free redirectors
  1012. redirect = Redirectors;
  1013. while (redirect)
  1014. {
  1015. Redirectors = redirect->next;
  1016. free(redirect->wzPath);
  1017. free(redirect->wzPathNew);
  1018. free(redirect);
  1019. redirect = Redirectors;
  1020. }
  1021. // Free open key triggers
  1022. trigger = OpenKeyTriggers;
  1023. while(trigger)
  1024. {
  1025. OpenKeyTriggers = trigger->next;
  1026. free(trigger->wzPath);
  1027. free(trigger);
  1028. trigger = OpenKeyTriggers;
  1029. }
  1030. // Free Protectors
  1031. protector = KeyProtectors;
  1032. while(protector)
  1033. {
  1034. KeyProtectors = protector->next;
  1035. free(protector->wzPath);
  1036. free(protector);
  1037. protector = KeyProtectors;
  1038. }
  1039. }
  1040. /*++
  1041. Function Description:
  1042. Create a dummy key for use as a virtual key. We need to have unique handles
  1043. in order to look up the keys, so by creating a key off HKLM, we can be
  1044. sure it won't fail.
  1045. We can't damage the registry like this because writes to this key will fail.
  1046. Calls to QueryValue, QueryInfo and EnumKey will work correctly because the
  1047. virtual registry is used in preference to the real one.
  1048. Arguments:
  1049. None
  1050. Return Value:
  1051. Dummy key
  1052. History:
  1053. 01/06/2000 linstev Created
  1054. --*/
  1055. HKEY
  1056. CVirtualRegistry::CreateDummyKey()
  1057. {
  1058. HKEY key = NULL;
  1059. LONG lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software", 0, KEY_READ, &key);
  1060. if (lRet != ERROR_SUCCESS)
  1061. {
  1062. return NULL;
  1063. }
  1064. return key;
  1065. }
  1066. /*++
  1067. Function Description:
  1068. Find an open key in the list of open keys.
  1069. Algorithm:
  1070. 1. Search the list of open keys for a match
  1071. Arguments:
  1072. IN hKey - Open HKEY
  1073. Return Value:
  1074. Pointer to a key or NULL
  1075. History:
  1076. 01/06/2000 linstev Created
  1077. --*/
  1078. OPENKEY *
  1079. CVirtualRegistry::FindOpenKey(
  1080. IN HKEY hKey
  1081. )
  1082. {
  1083. OPENKEY *key = OpenKeys;
  1084. while (key)
  1085. {
  1086. if (key->hkOpen == hKey)
  1087. {
  1088. return key;
  1089. }
  1090. key = key->next;
  1091. }
  1092. return NULL;
  1093. }
  1094. /*++
  1095. Function Description:
  1096. If this key is to be redirected, we adjust the path to the redirected
  1097. version. This works even if the requested path is a 'subpath' of a
  1098. redirector, eg:
  1099. Input = HKLM\Software\Test
  1100. Redirector = HKLM\Software -> HKLM\Hardware
  1101. Output = HKLM\Hardware\Test
  1102. If no redirector is present for this key/path, then lpPath is unchanged
  1103. Algorithm:
  1104. 1. Find a key whose base is a redirector
  1105. 2. Substitute the new base for the key
  1106. Arguments:
  1107. IN OUT lpPath - Path to redirect
  1108. Return Value:
  1109. TRUE if redirected
  1110. History:
  1111. 01/06/2000 linstev Created
  1112. --*/
  1113. BOOL
  1114. CVirtualRegistry::CheckRedirect(
  1115. IN OUT LPWSTR *lpPath
  1116. )
  1117. {
  1118. REDIRECTOR *redirect = Redirectors;
  1119. DWORD sza = wcslen(*lpPath);
  1120. // Go through the list of redirectors
  1121. while (redirect)
  1122. {
  1123. DWORD szb = wcslen(redirect->wzPath);
  1124. if ((szb <= sza) &&
  1125. (_wcsnicmp(*lpPath, redirect->wzPath, szb) == 0) &&
  1126. ((*lpPath)[szb] == L'\\' || (*lpPath)[szb] == L'\0'))
  1127. {
  1128. WCHAR *p = *lpPath + szb;
  1129. DWORD cchPathSize = wcslen(redirect->wzPathNew) + wcslen(p) + 1;
  1130. LPWSTR wzPathNew = (LPWSTR) malloc(cchPathSize * sizeof(WCHAR));
  1131. if (wzPathNew)
  1132. {
  1133. HRESULT hr;
  1134. hr = StringCchCopyW(wzPathNew, cchPathSize, redirect->wzPathNew);
  1135. if (FAILED(hr))
  1136. {
  1137. free (wzPathNew);
  1138. return FALSE;
  1139. }
  1140. hr = StringCchCatW(wzPathNew, cchPathSize, p);
  1141. if (FAILED(hr))
  1142. {
  1143. free(wzPathNew);
  1144. return FALSE;
  1145. }
  1146. // return the new path
  1147. LOGN( eDbgLevelWarning, "Redirecting: %S -> %S", *lpPath, wzPathNew);
  1148. free(*lpPath);
  1149. *lpPath = wzPathNew;
  1150. return TRUE;
  1151. }
  1152. else
  1153. {
  1154. DPFN( eDbgLevelError, szOutOfMemory);
  1155. return FALSE;
  1156. }
  1157. }
  1158. redirect = redirect->next;
  1159. }
  1160. return FALSE;
  1161. }
  1162. /*++
  1163. Function Description:
  1164. Returns true if a protector guards this key.
  1165. This will even work on a subkey of a protector.
  1166. Arguments:
  1167. IN lpPath - Path to protect
  1168. Return Value:
  1169. TRUE if protected
  1170. History:
  1171. 08/07/2001 mikrause Created
  1172. --*/
  1173. BOOL
  1174. CVirtualRegistry::CheckProtected(
  1175. IN LPWSTR lpPath
  1176. )
  1177. {
  1178. PROTECTOR *protect;
  1179. DWORD sza = wcslen(lpPath);
  1180. DWORD szb;
  1181. protect = KeyProtectors;
  1182. while (protect)
  1183. {
  1184. szb = wcslen(protect->wzPath);
  1185. // Check if we have a key or subkey match.
  1186. if ((szb <= sza) &&
  1187. (_wcsnicmp(protect->wzPath, lpPath, szb) == 0) &&
  1188. (lpPath[szb] == L'\\' || lpPath[szb] == L'\0'))
  1189. {
  1190. // Protector found.
  1191. LOGN( eDbgLevelWarning, "\tProtecting: %S", lpPath);
  1192. return TRUE;
  1193. }
  1194. protect = protect->next;
  1195. }
  1196. // Fell through, no protector found.
  1197. return FALSE;
  1198. }
  1199. /*++
  1200. Function Description:
  1201. Checks if any triggers should be called on this path,
  1202. and calls them.
  1203. Arguments:
  1204. IN lpPath - Path to check triggers for.
  1205. Return Value:
  1206. None
  1207. History:
  1208. 08/09/2001 mikrause Created
  1209. --*/
  1210. VOID
  1211. CVirtualRegistry::CheckTriggers(
  1212. IN LPWSTR lpPath)
  1213. {
  1214. OPENKEYTRIGGER *trigger;
  1215. DWORD sza, szb;
  1216. sza = wcslen(lpPath);
  1217. trigger = OpenKeyTriggers;
  1218. //
  1219. // Loop through all triggers and check. Even after finding a match,
  1220. // keep repeating, because a single OpenKey can cause multiple triggers.
  1221. //
  1222. while (trigger)
  1223. {
  1224. szb = wcslen(trigger->wzPath);
  1225. if ((szb <= sza) &&
  1226. (_wcsnicmp(lpPath, trigger->wzPath, szb)==0) &&
  1227. (lpPath[szb] == L'\\' || lpPath[szb] == L'\0'))
  1228. {
  1229. DPFN(eDbgLevelInfo, "Triggering %S on opening of %S", trigger->wzPath, lpPath);
  1230. trigger->pfnTrigger(lpPath);
  1231. }
  1232. trigger = trigger->next;
  1233. }
  1234. }
  1235. /*++
  1236. Function Description:
  1237. Flushes all enumerated lists.
  1238. Arguments:
  1239. IN lpPath - Path to redirect, eg: HKLM\Software\Microsoft
  1240. IN lpPathNew - Redirect to this path
  1241. Return Value:
  1242. None
  1243. History:
  1244. 01/06/2000 linstev Created
  1245. --*/
  1246. VOID
  1247. CVirtualRegistry::FlushEnumLists()
  1248. {
  1249. OPENKEY *key;
  1250. key = OpenKeys;
  1251. while (key)
  1252. {
  1253. key->FlushEnumList();
  1254. key = key->next;
  1255. }
  1256. }
  1257. /*++
  1258. Function Description:
  1259. Add a redirector to the virtual registry. See CheckRedirect().
  1260. Arguments:
  1261. IN lpPath - Path to redirect, eg: HKLM\Software\Microsoft
  1262. IN lpPathNew - Redirect to this path
  1263. Return Value:
  1264. None
  1265. History:
  1266. 01/06/2000 linstev Created
  1267. --*/
  1268. REDIRECTOR *
  1269. CVirtualRegistry::AddRedirect(
  1270. IN LPCWSTR lpPath,
  1271. IN LPCWSTR lpPathNew)
  1272. {
  1273. REDIRECTOR *redirect = (REDIRECTOR *) malloc(sizeof(REDIRECTOR));
  1274. if (!redirect)
  1275. {
  1276. DPFN( eDbgLevelError, szOutOfMemory);
  1277. return NULL;
  1278. }
  1279. ZeroMemory(redirect, sizeof(REDIRECTOR));
  1280. DWORD cchPath = wcslen(lpPath) + 1;
  1281. DWORD cchNewPath = wcslen(lpPathNew) + 1;
  1282. redirect->wzPath = (LPWSTR) malloc(cchPath * sizeof(WCHAR));
  1283. redirect->wzPathNew = (LPWSTR) malloc(cchNewPath * sizeof(WCHAR));
  1284. if (redirect->wzPath && redirect->wzPathNew)
  1285. {
  1286. HRESULT hr;
  1287. hr = StringCchCopyW(redirect->wzPath, cchPath, lpPath);
  1288. if (FAILED(hr))
  1289. {
  1290. goto ErrorCleanup;
  1291. }
  1292. hr = StringCchCopyW(redirect->wzPathNew, cchNewPath, lpPathNew);
  1293. if (FAILED(hr))
  1294. {
  1295. goto ErrorCleanup;
  1296. }
  1297. }
  1298. else
  1299. {
  1300. DPFN( eDbgLevelError, szOutOfMemory);
  1301. goto ErrorCleanup;
  1302. }
  1303. redirect->next = Redirectors;
  1304. Redirectors = redirect;
  1305. DPFN( eDbgLevelSpew, "Adding Redirector: %S ->\n %S", lpPath, lpPathNew);
  1306. return redirect;
  1307. ErrorCleanup:
  1308. free(redirect->wzPath);
  1309. free(redirect->wzPathNew);
  1310. free(redirect);
  1311. return NULL;
  1312. }
  1313. /*++
  1314. Function Description:
  1315. Add a key protector to the virtual registry. See CheckProtected().
  1316. Arguments:
  1317. IN lpPath - Path to protector, eg: HKLM\Software\Microsoft
  1318. Return Value:
  1319. None
  1320. History:
  1321. 08/21/2001 mikrause Created
  1322. --*/
  1323. PROTECTOR *
  1324. CVirtualRegistry::AddKeyProtector(
  1325. IN LPCWSTR lpPath)
  1326. {
  1327. PROTECTOR *protect = (PROTECTOR *) malloc(sizeof(PROTECTOR));
  1328. if (!protect)
  1329. {
  1330. DPFN( eDbgLevelError, szOutOfMemory);
  1331. return NULL;
  1332. }
  1333. ZeroMemory(protect, sizeof(PROTECTOR));
  1334. DWORD cchPath = wcslen(lpPath) + 1;
  1335. protect->wzPath = (LPWSTR) malloc(cchPath * sizeof(WCHAR));
  1336. if (protect->wzPath)
  1337. {
  1338. HRESULT hr;
  1339. hr = StringCchCopyW(protect->wzPath, cchPath, lpPath);
  1340. if (FAILED(hr))
  1341. {
  1342. goto ErrorCleanup;
  1343. }
  1344. }
  1345. else
  1346. {
  1347. DPFN( eDbgLevelError, szOutOfMemory);
  1348. goto ErrorCleanup;
  1349. }
  1350. DPFN( eDbgLevelSpew, "Adding Key Protector: %S", lpPath);
  1351. protect->next = KeyProtectors;
  1352. KeyProtectors = protect;
  1353. return protect;
  1354. ErrorCleanup:
  1355. free(protect->wzPath);
  1356. free(protect);
  1357. return NULL;
  1358. }
  1359. /*++
  1360. Function Description:
  1361. Add an open key trigger to the virtual registry.
  1362. Arguments:
  1363. IN lpPath - Path to trigger on, eg: HKLM\Software\Microsoft
  1364. IN pfnOpenKey - Function to be called when key is opened.
  1365. Return Value:
  1366. New open key trigger, or NULL on failure.
  1367. History:
  1368. 08/07/2001 mikrause Created
  1369. --*/
  1370. OPENKEYTRIGGER*
  1371. CVirtualRegistry::AddOpenKeyTrigger(
  1372. IN LPCWSTR lpPath,
  1373. IN _pfn_OpenKeyTrigger pfnOpenKey)
  1374. {
  1375. OPENKEYTRIGGER *openkeytrigger = (OPENKEYTRIGGER *) malloc(sizeof(OPENKEYTRIGGER));
  1376. if (!openkeytrigger)
  1377. {
  1378. DPFN( eDbgLevelError, szOutOfMemory);
  1379. return NULL;
  1380. }
  1381. ZeroMemory(openkeytrigger, sizeof(OPENKEYTRIGGER));
  1382. DWORD cchPath = wcslen(lpPath) + 1;
  1383. openkeytrigger->wzPath = (LPWSTR) malloc(cchPath * sizeof(WCHAR));
  1384. if (openkeytrigger->wzPath)
  1385. {
  1386. HRESULT hr = StringCchCopyW(openkeytrigger->wzPath, cchPath, lpPath);
  1387. if (FAILED(hr))
  1388. {
  1389. goto ErrorCleanup;
  1390. }
  1391. }
  1392. else
  1393. {
  1394. DPFN( eDbgLevelError, szOutOfMemory);
  1395. goto ErrorCleanup;
  1396. }
  1397. openkeytrigger->pfnTrigger = pfnOpenKey;
  1398. openkeytrigger->next = OpenKeyTriggers;
  1399. OpenKeyTriggers = openkeytrigger;
  1400. DPFN( eDbgLevelSpew, "Adding Open Key Trigger: %S, func@0x%x", lpPath, pfnOpenKey);
  1401. return openkeytrigger;
  1402. ErrorCleanup:
  1403. free(openkeytrigger->wzPath);
  1404. free(openkeytrigger);
  1405. return NULL;
  1406. }
  1407. /*++
  1408. Function Description:
  1409. Allow user to specify VRegistry.AddKey instead of VRegistry.Root->AddKey.
  1410. Arguments:
  1411. IN lpPath - Path of key
  1412. Return Value:
  1413. Virtual key
  1414. History:
  1415. 01/06/2000 linstev Created
  1416. --*/
  1417. VIRTUALKEY *
  1418. CVirtualRegistry::AddKey(
  1419. IN LPCWSTR lpPath
  1420. )
  1421. {
  1422. return Root->AddKey(lpPath);
  1423. }
  1424. /*++
  1425. Function Description:
  1426. Virtualized version of RegCreateKeyA, RegCreateKeyExA, RegOpenKeyA and RegOpenKeyExA
  1427. See RegOpenKey* and RegCreateKey* for details
  1428. Algorithm:
  1429. 1. Convert lpSubKey and lpClass to WCHAR
  1430. 2. Pass through to OpenKeyW
  1431. Arguments:
  1432. IN hKey - Handle to open key or HKLM etc
  1433. IN lpSubKey - Subkey to open
  1434. IN lpClass - Address of a class string
  1435. IN DWORD dwOptions - special options flag
  1436. OUT phkResult - Handle to open key if successful
  1437. OUT lpdwDisposition - Address of disposition value buffer
  1438. IN bCreate - Create the key if it doesn't exist
  1439. Return Value:
  1440. Error code or ERROR_SUCCESS
  1441. History:
  1442. 01/06/2000 linstev Created
  1443. --*/
  1444. LONG CVirtualRegistry::OpenKeyA(
  1445. IN HKEY hKey,
  1446. IN LPCSTR lpSubKey,
  1447. IN LPSTR lpClass,
  1448. IN DWORD dwOptions,
  1449. IN REGSAM samDesired,
  1450. IN LPSECURITY_ATTRIBUTES pSecurityAttributes,
  1451. OUT HKEY *phkResult,
  1452. OUT LPDWORD lpdwDisposition,
  1453. IN BOOL bCreate
  1454. )
  1455. {
  1456. LONG lRet;
  1457. LPWSTR wzSubKey = NULL;
  1458. LPWSTR wzClass = NULL;
  1459. if (lpSubKey)
  1460. {
  1461. wzSubKey = ToUnicode(lpSubKey);
  1462. if (!wzSubKey)
  1463. {
  1464. DPFN( eDbgLevelError, szOutOfMemory);
  1465. return ERROR_NOT_ENOUGH_MEMORY;
  1466. }
  1467. }
  1468. if (lpClass)
  1469. {
  1470. wzClass = ToUnicode(lpClass);
  1471. if (!wzClass)
  1472. {
  1473. free(wzSubKey);
  1474. DPFN( eDbgLevelError, szOutOfMemory);
  1475. return ERROR_NOT_ENOUGH_MEMORY;
  1476. }
  1477. }
  1478. lRet = OpenKeyW(
  1479. hKey,
  1480. wzSubKey,
  1481. wzClass,
  1482. dwOptions,
  1483. samDesired,
  1484. pSecurityAttributes,
  1485. phkResult,
  1486. lpdwDisposition,
  1487. bCreate,
  1488. FALSE,
  1489. NULL);
  1490. free(wzSubKey);
  1491. free(wzClass);
  1492. return lRet;
  1493. }
  1494. /*++
  1495. Function Description:
  1496. Wrapper for RegOpenKeyExW, RegOpenKeyW, RegCreateKeyW and RegCreateKeyExW
  1497. Algorithm:
  1498. 1. Strip leading '\' characters
  1499. 2. Inherit already open key data to get full key path
  1500. 3. Redirect if necessary
  1501. 4. RegOpenKeyEx with maximum possible security attributes
  1502. 5. If the open failed, check for virtual key
  1503. 6. If virtual, return a dummy key and succeed
  1504. 7. Find the virtual key if it exists and attach it to the open key
  1505. Arguments:
  1506. IN hKey - Handle to open key or HKLM etc
  1507. IN lpSubKey - Subkey to open
  1508. IN lpClass - Address of a class string
  1509. IN DWORD dwOptions - special options flag
  1510. OUT phkResult - Handle to open key if successful
  1511. OUT lpdwDisposition - Address of disposition value buffer
  1512. IN bCreate - Create the key if it doesn't exist
  1513. IN bRemote - Opening the remote registry.
  1514. IN lpMachineName - Machine name.
  1515. Return Value:
  1516. Error code or ERROR_SUCCESS
  1517. History:
  1518. 01/06/2000 linstev Created
  1519. --*/
  1520. LONG
  1521. CVirtualRegistry::OpenKeyW(
  1522. IN HKEY hKey,
  1523. IN LPCWSTR lpSubKey,
  1524. IN LPWSTR lpClass,
  1525. IN DWORD dwOptions,
  1526. IN REGSAM samDesired,
  1527. IN LPSECURITY_ATTRIBUTES pSecurityAttributes,
  1528. OUT HKEY *phkResult,
  1529. OUT LPDWORD lpdwDisposition,
  1530. IN BOOL bCreate,
  1531. IN BOOL bRemote,
  1532. IN LPCWSTR lpMachineName
  1533. )
  1534. {
  1535. // Just a paranoid sanity check
  1536. if (!hKey)
  1537. {
  1538. DPFN( eDbgLevelError, "NULL handle passed to OpenKeyW");
  1539. return ERROR_INVALID_HANDLE;
  1540. }
  1541. // Hack for Mavis Beacon which uses really old stack for this parameter
  1542. if (lpdwDisposition && IsBadWritePtr(lpdwDisposition, sizeof(DWORD_PTR)))
  1543. {
  1544. DPFN( eDbgLevelError, "HACK: Ignoring bad lpdwDispostion pointer");
  1545. lpdwDisposition = NULL;
  1546. }
  1547. LONG lRet;
  1548. OPENKEY *key;
  1549. BOOL bVirtual, bRedirected;
  1550. VIRTUALKEY *vkey;
  1551. LPWSTR wzPath = NULL;
  1552. __try
  1553. {
  1554. // Base error condition
  1555. lRet = ERROR_INVALID_HANDLE;
  1556. // Everybody AVs if this ones bad
  1557. *phkResult = 0;
  1558. samDesired &= (KEY_WOW64_64KEY | KEY_WOW64_32KEY);
  1559. samDesired |= MAXIMUM_ALLOWED;
  1560. // Win9x ignores the options parameter
  1561. if (g_bWin9x)
  1562. {
  1563. if (dwOptions & REG_OPTION_VOLATILE)
  1564. {
  1565. LOGN( eDbgLevelWarning, "[OpenKeyW] Removing volatile flag");
  1566. }
  1567. dwOptions = REG_OPTION_NON_VOLATILE;
  1568. }
  1569. // Trim leading stuff, e.g. '\' character
  1570. lpSubKey = TrimSlashW(lpSubKey);
  1571. // Inherit from previously opened key
  1572. key = FindOpenKey(hKey);
  1573. if (key)
  1574. {
  1575. bVirtual = key->bVirtual;
  1576. bRedirected = key->bRedirected;
  1577. wzPath = MakePath(0, key->wzPath, lpSubKey);
  1578. }
  1579. else
  1580. {
  1581. bVirtual = FALSE;
  1582. bRedirected = FALSE;
  1583. wzPath = MakePath(hKey, NULL, lpSubKey);
  1584. }
  1585. if (!wzPath)
  1586. {
  1587. // Set the error code appropriately
  1588. lRet = ERROR_NOT_ENOUGH_MEMORY;
  1589. }
  1590. // Check if we need to trigger on this key
  1591. else
  1592. {
  1593. CheckTriggers(wzPath);
  1594. }
  1595. // Now that we have the full path, see if we want to redirect it
  1596. if (!bRedirected && wzPath && CheckRedirect(&wzPath))
  1597. {
  1598. //
  1599. // Turn off virtual mode - since we don't know anything about the
  1600. // key we're redirecting to...
  1601. //
  1602. bVirtual = FALSE;
  1603. //
  1604. // Make sure we know we've been redirected so we don't get into recursive
  1605. // problems if the destination is a subkey of the source.
  1606. //
  1607. bRedirected = TRUE;
  1608. //
  1609. // We've been redirected, so we can no longer open the key directly:
  1610. // we have to get the full path in order to open the right key.
  1611. //
  1612. lpSubKey = SplitPath(wzPath, &hKey);
  1613. }
  1614. // Try and open the key if it's not already virtual
  1615. if (!bVirtual)
  1616. {
  1617. //
  1618. // Since we aren't virtual yet, we need to try for the original
  1619. // key. If one of these fail, then we'll go ahead and try for a
  1620. // virtual key.
  1621. //
  1622. if (bCreate)
  1623. {
  1624. lRet = ORIGINAL_API(RegCreateKeyExW)(
  1625. hKey,
  1626. lpSubKey,
  1627. 0,
  1628. lpClass,
  1629. dwOptions,
  1630. samDesired,
  1631. pSecurityAttributes,
  1632. phkResult,
  1633. lpdwDisposition);
  1634. if (lRet == ERROR_SUCCESS)
  1635. {
  1636. // Possible change in enumeration data, flush lists.
  1637. FlushEnumLists();
  1638. }
  1639. }
  1640. else
  1641. {
  1642. //
  1643. // bRemote is only true when this is called by the
  1644. // RegConnectRegistry hook so bCreate can't be true.
  1645. //
  1646. if (bRemote)
  1647. {
  1648. lRet = ORIGINAL_API(RegConnectRegistryW)(
  1649. lpMachineName,
  1650. hKey,
  1651. phkResult);
  1652. }
  1653. else
  1654. {
  1655. lRet = ORIGINAL_API(RegOpenKeyExW)(
  1656. hKey,
  1657. lpSubKey,
  1658. 0,
  1659. samDesired,
  1660. phkResult);
  1661. }
  1662. }
  1663. }
  1664. //
  1665. // We have to look up the virtual key even if we managed to open an
  1666. // actual key, because when we query, we look for virtual values
  1667. // first. i.e. the virtual values override existing values.
  1668. //
  1669. vkey = Root->FindKey(wzPath);
  1670. // Check if our key is virtual, or may need to become virtual
  1671. if (bVirtual || FAILURE(lRet))
  1672. {
  1673. if (vkey)
  1674. {
  1675. //
  1676. // We have a virtual key, so create a dummy handle to hand back
  1677. // to the app.
  1678. //
  1679. *phkResult = CreateDummyKey();
  1680. if (*phkResult)
  1681. {
  1682. bVirtual = TRUE;
  1683. lRet = ERROR_SUCCESS;
  1684. }
  1685. else
  1686. {
  1687. // Couldn't create the dummy key, something seriously wrong.
  1688. DPFN(eDbgLevelError, "Couldn't create dummy key in OpenKeyW");
  1689. lRet = ERROR_FILE_NOT_FOUND;
  1690. }
  1691. }
  1692. }
  1693. if (SUCCESS(lRet) && wzPath)
  1694. {
  1695. // Made it this far, so make a new key entry
  1696. key = (OPENKEY *) malloc(sizeof(OPENKEY));
  1697. if (key)
  1698. {
  1699. key->vkey = vkey;
  1700. key->bVirtual = bVirtual;
  1701. key->bRedirected = bRedirected;
  1702. key->hkOpen = *phkResult;
  1703. key->wzPath = wzPath;
  1704. key->enumKeys = NULL;
  1705. key->enumValues = NULL;
  1706. key->next = OpenKeys;
  1707. OpenKeys = key;
  1708. }
  1709. else
  1710. {
  1711. DPFN( eDbgLevelError, szOutOfMemory);
  1712. // Clean up the dummy key
  1713. RegCloseKey(*phkResult);
  1714. lRet = ERROR_NOT_ENOUGH_MEMORY;
  1715. }
  1716. }
  1717. DPFN( ELEVEL(lRet), "%08lx=OpenKeyW(Key=%04lx)", lRet, hKey);
  1718. if (wzPath)
  1719. {
  1720. DPFN( ELEVEL(lRet), " Path=%S", wzPath);
  1721. }
  1722. DPFN( ELEVEL(lRet), " Result=%04lx", *phkResult);
  1723. }
  1724. __except(EXCEPTION_EXECUTE_HANDLER)
  1725. {
  1726. DPFN( eDbgLevelError, "Exception occurred in OpenKeyW");
  1727. lRet = ERROR_BAD_ARGUMENTS;
  1728. }
  1729. if (FAILURE(lRet))
  1730. {
  1731. //
  1732. // If we failed for any reason, we didn't create an OPENKEY and so we
  1733. // can kill wzPath which was allocated by MakePath.
  1734. //
  1735. free(wzPath);
  1736. }
  1737. return lRet;
  1738. }
  1739. /*++
  1740. Function Description:
  1741. Wrapper for RegQueryValueExA and RegQueryValue.
  1742. See QueryValueW for more details.
  1743. Algorithm:
  1744. 1. Call QueryValueW
  1745. 2. If it's a string, convert back to ANSI
  1746. Note: this whole function is slightly more complex than it needs to be
  1747. because we don't want to query the value twice: once to get it's type
  1748. and the second time to get the value.
  1749. Most of the complications are due to the strings: we have to make sure we
  1750. have a buffer large enough so we can figure out how large the (possibly
  1751. DBCS) string is.
  1752. Arguments:
  1753. IN hKey - Handle to open key
  1754. IN lpValueName - Value to query
  1755. IN lpType - Type of data, eg: REG_SZ
  1756. IN OUT lpData - Buffer for queries data
  1757. IN OUT lpcbData - Size of input buffer/size of returned data
  1758. Return Value:
  1759. Error code or ERROR_SUCCESS
  1760. History:
  1761. 01/06/2000 linstev Created
  1762. --*/
  1763. LONG
  1764. CVirtualRegistry::QueryValueA(
  1765. IN HKEY hKey,
  1766. IN LPSTR lpValueName,
  1767. IN LPDWORD lpType,
  1768. IN OUT LPBYTE lpData,
  1769. IN OUT LPDWORD lpcbData
  1770. )
  1771. {
  1772. LONG lRet;
  1773. WCHAR wValueName[MAX_PATH];
  1774. DWORD dwType;
  1775. DWORD dwSize, dwOutSize;
  1776. LPBYTE lpBigData = NULL;
  1777. BOOL bText;
  1778. __try
  1779. {
  1780. // Can't have this
  1781. if (lpData && !lpcbData)
  1782. {
  1783. return ERROR_INVALID_PARAMETER;
  1784. }
  1785. // Convert the Value Name to WCHAR
  1786. if (lpValueName)
  1787. {
  1788. if (MultiByteToWideChar(
  1789. CP_ACP,
  1790. 0,
  1791. lpValueName,
  1792. -1,
  1793. (LPWSTR)wValueName,
  1794. MAX_PATH) == 0)
  1795. {
  1796. return ERROR_INVALID_PARAMETER;
  1797. }
  1798. }
  1799. else
  1800. {
  1801. wValueName[0] = L'\0';
  1802. }
  1803. //
  1804. // Get an initial size to use: if they sent us a buffer, we start with
  1805. // that size, otherwise, we try a reasonable string length
  1806. //
  1807. if (lpData && *lpcbData)
  1808. {
  1809. dwSize = *lpcbData;
  1810. }
  1811. else
  1812. {
  1813. dwSize = MAX_PATH;
  1814. }
  1815. Retry:
  1816. //
  1817. // We can't touch their buffer unless we're going to succeed, so we
  1818. // have to double buffer the call.
  1819. //
  1820. lpBigData = (LPBYTE) malloc(dwSize);
  1821. if (!lpBigData)
  1822. {
  1823. DPFN( eDbgLevelError, szOutOfMemory);
  1824. return ERROR_NOT_ENOUGH_MEMORY;
  1825. }
  1826. lRet = QueryValueW(hKey, wValueName, &dwType, lpBigData, &dwSize);
  1827. //
  1828. // We need to know if it's a string, since then we have to do extra
  1829. // work to calculate the real size of the buffer etc.
  1830. //
  1831. bText = (SUCCESS(lRet) || (lRet == ERROR_MORE_DATA)) &&
  1832. ((dwType == REG_SZ) ||
  1833. (dwType == REG_EXPAND_SZ) ||
  1834. (dwType == REG_MULTI_SZ));
  1835. if (bText && (lRet == ERROR_MORE_DATA))
  1836. {
  1837. //
  1838. // The buffer wasn't big enough: we have to actually query the value
  1839. // so we can get the real length in case it's DBCS, so we retry.
  1840. // Note: dwSize now contains the required size, so it will succeed
  1841. // this time around.
  1842. //
  1843. free(lpBigData);
  1844. goto Retry;
  1845. }
  1846. //
  1847. // Calculate the size of the output buffer: if it's text, it may be
  1848. // a DBCS string, so we need to get the right size
  1849. //
  1850. if (bText)
  1851. {
  1852. dwOutSize = WideCharToMultiByte(
  1853. CP_ACP,
  1854. 0,
  1855. (LPWSTR) lpBigData,
  1856. dwSize / sizeof(WCHAR),
  1857. NULL,
  1858. NULL,
  1859. 0,
  1860. 0);
  1861. }
  1862. else
  1863. {
  1864. // It's not text, so we just use the actual size
  1865. dwOutSize = dwSize;
  1866. }
  1867. //
  1868. // If they gave us a buffer, we fill it in with what we got back
  1869. //
  1870. if (SUCCESS(lRet) && lpData)
  1871. {
  1872. //
  1873. // Make sure we have enough space: lpcbData is guaranteed to be
  1874. // valid since lpData is ok.
  1875. //
  1876. if (*lpcbData >= dwOutSize)
  1877. {
  1878. if (bText)
  1879. {
  1880. //
  1881. // Convert the string back to ANSI. The buffer must have been big
  1882. // enough since QueryValue succeeded.
  1883. // Note: we have to give the exact size to convert otherwise we
  1884. // use more of the buffer than absolutely necessary. Some apps,
  1885. // like NHL 98 say they have a 256 byte buffer, but only give us
  1886. // a 42 byte buffer. On NT, everything is done in place on that
  1887. // buffer: so we always use more than the exact string length.
  1888. // This shim gets around that because we use separate buffers.
  1889. //
  1890. if (WideCharToMultiByte(
  1891. CP_ACP,
  1892. 0,
  1893. (LPWSTR)lpBigData,
  1894. dwSize / 2,
  1895. (LPSTR)lpData,
  1896. dwOutSize, // *lpcbData,
  1897. 0,
  1898. 0) == 0)
  1899. {
  1900. free(lpBigData);
  1901. return ERROR_INVALID_PARAMETER;
  1902. }
  1903. }
  1904. else
  1905. {
  1906. MoveMemory(lpData, lpBigData, dwSize);
  1907. }
  1908. }
  1909. else
  1910. {
  1911. lRet = ERROR_MORE_DATA;
  1912. }
  1913. }
  1914. free(lpBigData);
  1915. // Fill the output structures in if possible
  1916. if (lpType)
  1917. {
  1918. *lpType = dwType;
  1919. }
  1920. if (lpcbData)
  1921. {
  1922. *lpcbData = dwOutSize;
  1923. }
  1924. }
  1925. __except(EXCEPTION_EXECUTE_HANDLER)
  1926. {
  1927. DPFN( eDbgLevelError, "Exception occurred in QueryValueA");
  1928. lRet = ERROR_BAD_ARGUMENTS;
  1929. }
  1930. return lRet;
  1931. }
  1932. /*++
  1933. Function Description:
  1934. Wrapper for RegQueryValueExW and RegQueryValue. We first see if the value
  1935. is virtual because virtual values override actual values
  1936. Algorithm:
  1937. 1. Check if it's a virtual value and if so, spoof it
  1938. 2. If it's not virtual, query registry normally
  1939. Arguments:
  1940. IN hKey - Handle to open key
  1941. IN lpValueName - Value to query
  1942. IN lpType - Type of data, eg: REG_SZ
  1943. IN OUT lpData - Buffer for queries data
  1944. IN OUT lpcbData - Size of input buffer/size of returned data
  1945. Return Value:
  1946. Error code or ERROR_SUCCESS
  1947. History:
  1948. 01/06/2000 linstev Created
  1949. --*/
  1950. LONG
  1951. CVirtualRegistry::QueryValueW(
  1952. IN HKEY hKey,
  1953. IN LPWSTR lpValueName,
  1954. IN LPDWORD lpType,
  1955. IN OUT LPBYTE lpData,
  1956. IN OUT LPDWORD lpcbData
  1957. )
  1958. {
  1959. // Just a paranoid sanity check
  1960. if (!hKey)
  1961. {
  1962. DPFN( eDbgLevelError, "NULL handle passed to OpenKeyW");
  1963. return ERROR_INVALID_HANDLE;
  1964. }
  1965. LONG lRet;
  1966. OPENKEY *key;
  1967. VIRTUALKEY *vkey;
  1968. VIRTUALVAL *vvalue;
  1969. DWORD dwType;
  1970. WCHAR* lpBuffer;
  1971. DWORD dwStringSize;
  1972. DWORD cbData = 0;
  1973. BOOL bDataPresent = TRUE;
  1974. __try
  1975. {
  1976. lRet = ERROR_FILE_NOT_FOUND;
  1977. // Can't have this
  1978. if (lpData && !lpcbData)
  1979. {
  1980. return ERROR_INVALID_PARAMETER;
  1981. }
  1982. // We always need the type
  1983. if (!lpType)
  1984. {
  1985. lpType = &dwType;
  1986. }
  1987. // Do we want to spoof this
  1988. key = FindOpenKey(hKey);
  1989. vkey = key ? key->vkey : NULL;
  1990. vvalue = vkey ? vkey->FindValue(lpValueName) : NULL;
  1991. if (key && vkey && vvalue &&
  1992. (vvalue->cbData != 0 || vvalue->pfnQueryValue))
  1993. {
  1994. // Use the callback if available
  1995. if (vvalue->pfnQueryValue)
  1996. {
  1997. //
  1998. // Note, the callback puts it's values into the vvalue field,
  1999. // just as if we knew it all along. In addition, we can fail
  2000. // the call... but that doesn't allow us defer to the original
  2001. // value.
  2002. //
  2003. lRet = (*vvalue->pfnQueryValue)(
  2004. key,
  2005. vkey,
  2006. vvalue);
  2007. }
  2008. else
  2009. {
  2010. lRet = ERROR_SUCCESS;
  2011. }
  2012. // Copy the virtual value into the buffer
  2013. if (SUCCESS(lRet))
  2014. {
  2015. *lpType = vvalue->dwType;
  2016. if (lpData)
  2017. {
  2018. if (vvalue->cbData <= *lpcbData)
  2019. {
  2020. MoveMemory(lpData, vvalue->lpData, vvalue->cbData);
  2021. }
  2022. else
  2023. {
  2024. lRet = ERROR_MORE_DATA;
  2025. }
  2026. }
  2027. if (lpcbData)
  2028. {
  2029. *lpcbData = vvalue->cbData;
  2030. }
  2031. }
  2032. }
  2033. else if (key && vkey && vvalue &&
  2034. (vvalue->cbData == 0))
  2035. {
  2036. bDataPresent = FALSE;
  2037. lRet = ERROR_SUCCESS;
  2038. }
  2039. else
  2040. {
  2041. // Save the size of the data buffer.
  2042. if (lpcbData)
  2043. {
  2044. cbData = *lpcbData;
  2045. }
  2046. //
  2047. // Get the key normally as if it weren't virtual at all
  2048. //
  2049. lRet = ORIGINAL_API(RegQueryValueExW)(
  2050. hKey,
  2051. lpValueName,
  2052. NULL,
  2053. lpType,
  2054. lpData,
  2055. lpcbData);
  2056. //
  2057. // Some apps store bogus data beyond the end of the string.
  2058. // Attempt to fix.
  2059. //
  2060. // Only try this if it's a string.
  2061. if (lRet == ERROR_MORE_DATA && (*lpType == REG_SZ || *lpType == REG_EXPAND_SZ))
  2062. {
  2063. //
  2064. // Create a buffer large enough to hold the data
  2065. // We read from lpcbData here, but this should be ok,
  2066. // since RegQueryValueEx shouldn't return ERROR_MORE_DATA
  2067. // if lpcbData is NULL.
  2068. //
  2069. lpBuffer = (WCHAR*)malloc(*lpcbData);
  2070. if (lpBuffer)
  2071. {
  2072. // Requery with new buffer.
  2073. lRet = ORIGINAL_API(RegQueryValueExW)(
  2074. hKey,
  2075. lpValueName,
  2076. NULL,
  2077. lpType,
  2078. (BYTE*)lpBuffer,
  2079. lpcbData);
  2080. if (lRet == ERROR_SUCCESS)
  2081. {
  2082. dwStringSize = wcslen(lpBuffer)*sizeof(WCHAR) + sizeof(WCHAR);
  2083. // If size of dest buffer can hold the string . . .
  2084. if (cbData >= dwStringSize)
  2085. {
  2086. DPFN(eDbgLevelInfo, "\tTrimming data beyond end of string in Query for %S", lpValueName);
  2087. // Copy the data to the caller's buffer,
  2088. CopyMemory(lpData, lpBuffer, dwStringSize);
  2089. *lpcbData = dwStringSize;
  2090. }
  2091. else
  2092. {
  2093. // Set *lpcbData to the correct size, and return more data error
  2094. *lpcbData = dwStringSize;
  2095. lRet = ERROR_MORE_DATA;
  2096. }
  2097. }
  2098. free(lpBuffer);
  2099. }
  2100. }
  2101. //
  2102. // Here's another hack for us: if the value is NULL or an empty string
  2103. // Win9x defers to QueryValue...
  2104. //
  2105. if (g_bWin9x && (lRet == ERROR_FILE_NOT_FOUND) &&
  2106. (!lpValueName || !lpValueName[0]))
  2107. {
  2108. lRet = ORIGINAL_API(RegQueryValueW)(
  2109. hKey,
  2110. NULL,
  2111. (LPWSTR)lpData,
  2112. (PLONG)lpcbData);
  2113. if (SUCCESS(lRet))
  2114. {
  2115. *lpType = REG_SZ;
  2116. }
  2117. }
  2118. }
  2119. DPFN( ELEVEL(lRet), "%08lx=QueryValueW(Key=%04lx)",
  2120. lRet,
  2121. hKey);
  2122. if (key)
  2123. {
  2124. DPFN( ELEVEL(lRet), " Path=%S\\%S", key->wzPath, lpValueName);
  2125. }
  2126. else
  2127. {
  2128. DPFN( ELEVEL(lRet), " Value=%S", lpValueName);
  2129. }
  2130. if (SUCCESS(lRet) &&
  2131. ((*lpType == REG_SZ) ||
  2132. (*lpType == REG_EXPAND_SZ))&&
  2133. (bDataPresent == TRUE))
  2134. {
  2135. DPFN( eDbgLevelInfo, " Result=%S", lpData);
  2136. }
  2137. }
  2138. __except(EXCEPTION_EXECUTE_HANDLER)
  2139. {
  2140. DPFN( eDbgLevelError, "Exception occurred in QueryValueW");
  2141. lRet = ERROR_BAD_ARGUMENTS;
  2142. }
  2143. return lRet;
  2144. }
  2145. /*++
  2146. Function Description:
  2147. Wrapper for RegEnumKeyA
  2148. Call out to EnumKeyW and convert the name back to ANSI. Note we pass the
  2149. size given to us (in lpcbName) down to EnumKeyW in case the lpName buffer
  2150. is too small.
  2151. Algoritm:
  2152. 1. EnumKeyW with a large buffer
  2153. 2. Convert the key back to ansi if it succeeds
  2154. Arguments:
  2155. IN hKey - Handle to open key
  2156. IN dwIndex - Index to enumerate
  2157. OUT lpName - Name of subkey
  2158. IN OUT lpcbName - Size of name buffer
  2159. Return Value:
  2160. Error code or ERROR_SUCCESS
  2161. History:
  2162. 01/06/2000 linstev Created
  2163. --*/
  2164. LONG
  2165. CVirtualRegistry::EnumKeyA(
  2166. IN HKEY hKey,
  2167. IN DWORD dwIndex,
  2168. OUT LPSTR lpName,
  2169. OUT LPDWORD lpcbName
  2170. )
  2171. {
  2172. LONG lRet = ERROR_NO_MORE_ITEMS;
  2173. WCHAR wKey[MAX_PATH + 1];
  2174. DWORD dwcbName = MAX_PATH + 1;
  2175. __try
  2176. {
  2177. lRet = EnumKeyW(hKey, dwIndex, (LPWSTR)wKey, &dwcbName);
  2178. if (SUCCESS(lRet))
  2179. {
  2180. DWORD dwByte = WideCharToMultiByte(
  2181. CP_ACP,
  2182. 0,
  2183. (LPWSTR)wKey,
  2184. dwcbName,
  2185. (LPSTR)lpName,
  2186. *lpcbName,
  2187. 0,
  2188. 0);
  2189. lpName[dwByte] = '\0';
  2190. *lpcbName = dwByte;
  2191. if (!dwByte)
  2192. {
  2193. lRet = GetLastError();
  2194. // Generate a registry error code
  2195. if (lRet == ERROR_INSUFFICIENT_BUFFER)
  2196. {
  2197. lRet = ERROR_MORE_DATA;
  2198. }
  2199. }
  2200. }
  2201. }
  2202. __except(EXCEPTION_EXECUTE_HANDLER)
  2203. {
  2204. lRet = ERROR_BAD_ARGUMENTS;
  2205. }
  2206. return lRet;
  2207. }
  2208. /*++
  2209. Function Description:
  2210. Wrapper for RegEnumKeyW.
  2211. Algorithm:
  2212. 1. Build enumeration list, if necessary.
  2213. 2. Iterate through enumeration list until index is found.
  2214. Arguments:
  2215. IN hKey - Handle to open key
  2216. IN dwIndex - Index to enumerate
  2217. OUT lpName - Name of subkey
  2218. OUT lpcbName - Size of name buffer
  2219. Return Value:
  2220. Error code or ERROR_SUCCESS
  2221. History:
  2222. 01/06/2000 linstev Created
  2223. --*/
  2224. LONG
  2225. CVirtualRegistry::EnumKeyW(
  2226. HKEY hKey,
  2227. DWORD dwIndex,
  2228. LPWSTR lpName,
  2229. LPDWORD lpcbName
  2230. )
  2231. {
  2232. LONG lRet = ERROR_BAD_ARGUMENTS;
  2233. OPENKEY *key;
  2234. ENUMENTRY *enumkey;
  2235. DWORD i;
  2236. __try
  2237. {
  2238. key = FindOpenKey(hKey);
  2239. if (key)
  2240. {
  2241. if (key->enumKeys == NULL)
  2242. {
  2243. key->BuildEnumList();
  2244. }
  2245. i = 0;
  2246. enumkey = key->enumKeys;
  2247. while (enumkey)
  2248. {
  2249. if (dwIndex == i)
  2250. {
  2251. DWORD len = wcslen(enumkey->wzName);
  2252. if (*lpcbName > len)
  2253. {
  2254. HRESULT hr;
  2255. hr = StringCchCopyW(lpName, *lpcbName, enumkey->wzName);
  2256. if (FAILED(hr))
  2257. {
  2258. lRet = ERROR_MORE_DATA;
  2259. }
  2260. else
  2261. {
  2262. *lpcbName = len;
  2263. lRet = ERROR_SUCCESS;
  2264. }
  2265. }
  2266. else
  2267. {
  2268. lRet = ERROR_MORE_DATA;
  2269. }
  2270. break;
  2271. }
  2272. i++;
  2273. enumkey = enumkey->next;
  2274. }
  2275. // No key found for index
  2276. if (enumkey == NULL)
  2277. {
  2278. lRet = ERROR_NO_MORE_ITEMS;
  2279. }
  2280. }
  2281. else
  2282. {
  2283. lRet = ORIGINAL_API(RegEnumKeyExW)(
  2284. hKey,
  2285. dwIndex,
  2286. lpName,
  2287. lpcbName,
  2288. 0,
  2289. 0,
  2290. 0,
  2291. 0);
  2292. }
  2293. }
  2294. __except(EXCEPTION_EXECUTE_HANDLER)
  2295. {
  2296. lRet = ERROR_BAD_ARGUMENTS;
  2297. }
  2298. DPFN( ELEVEL(lRet), "%08lx=EnumKeyW(hKey=%04lx,dwIndex=%d)",
  2299. lRet,
  2300. hKey,
  2301. dwIndex);
  2302. if (SUCCESS(lRet))
  2303. {
  2304. DPFN( eDbgLevelInfo, " Result=%S", lpName);
  2305. }
  2306. return lRet;
  2307. }
  2308. /*++
  2309. Function Description:
  2310. Wrapper for RegEnumValueA. Thunks to QueryValueW.
  2311. This function calls QueryValueA to get the data
  2312. out of the value, so most error handling is done by QueryValueA.
  2313. Arguments:
  2314. IN hKey - Handle to open key
  2315. IN dwIndex - Index of value to enumerate
  2316. IN OUT lpValueName - Value name buffer
  2317. IN OUT lpcbValueName - Sizeof value name buffer
  2318. IN OUT lpType - Type of data, eg: REG_SZ
  2319. IN OUT lpData - Buffer for queries data
  2320. IN OUT lpcbData - Size of input buffer/size of returned data
  2321. Return Value:
  2322. Error code or ERROR_SUCCESS
  2323. History:
  2324. 01/06/2000 linstev Created
  2325. --*/
  2326. LONG
  2327. CVirtualRegistry::EnumValueA(
  2328. IN HKEY hKey,
  2329. IN DWORD dwIndex,
  2330. IN OUT LPSTR lpValueName,
  2331. IN OUT LPDWORD lpcbValueName,
  2332. IN OUT LPDWORD lpType,
  2333. IN OUT LPBYTE lpData,
  2334. IN OUT LPDWORD lpcbData
  2335. )
  2336. {
  2337. LONG lRet;
  2338. WCHAR wzValueName[MAX_PATH];
  2339. DWORD dwValNameSize;
  2340. __try
  2341. {
  2342. dwValNameSize = MAX_PATH;
  2343. lRet = EnumValueW(hKey, dwIndex, wzValueName, &dwValNameSize, NULL, NULL, NULL);
  2344. if (lRet == ERROR_SUCCESS)
  2345. {
  2346. dwValNameSize = WideCharToMultiByte(
  2347. CP_ACP,
  2348. 0,
  2349. wzValueName,
  2350. -1,
  2351. lpValueName,
  2352. *lpcbValueName,
  2353. NULL,
  2354. NULL);
  2355. if (dwValNameSize != 0)
  2356. {
  2357. // Just do a normal query value for the remaining parameters.
  2358. lRet = QueryValueA(hKey, lpValueName, lpType, lpData, lpcbData);
  2359. }
  2360. else
  2361. {
  2362. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  2363. {
  2364. lRet = ERROR_MORE_DATA;
  2365. *lpcbValueName = WideCharToMultiByte(
  2366. CP_ACP,
  2367. 0,
  2368. wzValueName,
  2369. -1,
  2370. NULL,
  2371. 0,
  2372. NULL,
  2373. NULL);
  2374. }
  2375. else
  2376. {
  2377. lRet = GetLastError();
  2378. }
  2379. }
  2380. }
  2381. }
  2382. __except(EXCEPTION_EXECUTE_HANDLER)
  2383. {
  2384. lRet = ERROR_BAD_ARGUMENTS;
  2385. }
  2386. return lRet;
  2387. }
  2388. /*++
  2389. Function Description:
  2390. Wrapper for RegEnumValueW. This function calls QueryValueW to get the data
  2391. out of the value, so most error handling is done by QueryValueW.
  2392. Algorithm:
  2393. 1. Check if key has virtual values, if not default to RegEnumValueW.
  2394. 2. Build enumeration list, if necessary.
  2395. 3. Iterate through enumeration list until index is found.
  2396. Arguments:
  2397. IN hKey - Handle to open key
  2398. IN dwIndex - Index of value to enumerate
  2399. IN OUT lpValueName - Value name buffer
  2400. IN OUT lpcbValueName - Sizeof value name buffer
  2401. IN OUT lpType - Type of data, eg: REG_SZ
  2402. IN OUT lpData - Buffer for queries data
  2403. IN OUT lpcbData - Size of input buffer/size of returned data
  2404. Return Value:
  2405. Error code or ERROR_SUCCESS
  2406. History:
  2407. 01/06/2000 linstev Created
  2408. --*/
  2409. LONG
  2410. CVirtualRegistry::EnumValueW(
  2411. IN HKEY hKey,
  2412. IN DWORD dwIndex,
  2413. IN OUT LPWSTR lpValueName,
  2414. IN OUT LPDWORD lpcbValueName,
  2415. IN OUT LPDWORD lpType,
  2416. IN OUT LPBYTE lpData,
  2417. IN OUT LPDWORD lpcbData
  2418. )
  2419. {
  2420. LONG lRet;
  2421. OPENKEY *key;
  2422. ENUMENTRY *enumval;
  2423. // Check if it has virtual values . . .
  2424. key = FindOpenKey(hKey);
  2425. if (key && key->vkey && key->vkey->values)
  2426. {
  2427. DWORD i = 0;
  2428. if (key->enumValues == NULL)
  2429. {
  2430. key->BuildEnumList();
  2431. }
  2432. enumval = key->enumValues;
  2433. lRet = ERROR_NO_MORE_ITEMS;
  2434. while (enumval)
  2435. {
  2436. if (dwIndex == i)
  2437. {
  2438. DWORD len = wcslen(enumval->wzName);
  2439. if (*lpcbValueName > len)
  2440. {
  2441. // Copy the name and query the data
  2442. HRESULT hr = StringCchCopyW(lpValueName, *lpcbValueName, enumval->wzName);
  2443. if (FAILED(hr))
  2444. {
  2445. lRet = ERROR_MORE_DATA;
  2446. }
  2447. else
  2448. {
  2449. *lpcbValueName = len;
  2450. lRet = QueryValueW(
  2451. hKey,
  2452. enumval->wzName,
  2453. lpType,
  2454. lpData,
  2455. lpcbData);
  2456. }
  2457. }
  2458. else
  2459. {
  2460. // The buffer given for name wasn't big enough
  2461. lRet = ERROR_MORE_DATA;
  2462. }
  2463. break;
  2464. }
  2465. i++;
  2466. enumval = enumval->next;
  2467. }
  2468. }
  2469. // No virtual values, fall through to original API.
  2470. else
  2471. {
  2472. lRet = ORIGINAL_API(RegEnumValueW)(
  2473. hKey,
  2474. dwIndex,
  2475. lpValueName,
  2476. lpcbValueName,
  2477. 0,
  2478. lpType,
  2479. lpData,
  2480. lpcbData);
  2481. }
  2482. DPFN( ELEVEL(lRet), "%08lx=EnumValueW(hKey=%04lx,dwIndex=%d)",
  2483. lRet,
  2484. hKey,
  2485. dwIndex);
  2486. if (SUCCESS(lRet))
  2487. {
  2488. DPFN( eDbgLevelInfo, " Result=%S", lpValueName);
  2489. }
  2490. return lRet;
  2491. }
  2492. /*++
  2493. Function Description:
  2494. Wrapper for RegQueryInfoKeyA.
  2495. We don't need to worry about the conversion of ansi->unicode in the sizes
  2496. of values and keys because they are defined as string lengths.
  2497. Algorithm:
  2498. 1. Convert the class string to unicode
  2499. 2. Call QueryInfoW
  2500. Arguments:
  2501. IN hKey - handle to key to query
  2502. OUT lpClass - address of buffer for class string
  2503. OUT lpcbClass - address of size of class string buffer
  2504. OUT lpReserved - reserved
  2505. OUT lpcSubKeys - address of buffer for number of subkeys
  2506. OUT lpcbMaxSubKeyLen - address of buffer for longest subkey
  2507. OUT lpcbMaxClassLen - address of buffer for longest class string length
  2508. OUT lpcValues - address of buffer for number of value entries
  2509. OUT lpcbMaxValueNameLen - address of buffer for longest value name length
  2510. OUT lpcbMaxValueLen - address of buffer for longest value data length
  2511. OUT lpcbSecurityDescriptor - address of buffer for security descriptor length
  2512. OUT lpftLastWriteTime - address of buffer for last write time
  2513. Return Value:
  2514. Error code or ERROR_SUCCESS
  2515. History:
  2516. 01/06/2000 linstev Created
  2517. --*/
  2518. LONG
  2519. CVirtualRegistry::QueryInfoA(
  2520. IN HKEY hKey,
  2521. OUT LPSTR lpClass,
  2522. OUT LPDWORD lpcbClass,
  2523. OUT LPDWORD lpReserved,
  2524. OUT LPDWORD lpcSubKeys,
  2525. OUT LPDWORD lpcbMaxSubKeyLen,
  2526. OUT LPDWORD lpcbMaxClassLen,
  2527. OUT LPDWORD lpcValues,
  2528. OUT LPDWORD lpcbMaxValueNameLen,
  2529. OUT LPDWORD lpcbMaxValueLen,
  2530. OUT LPDWORD lpcbSecurityDescriptor,
  2531. OUT PFILETIME lpftLastWriteTime
  2532. )
  2533. {
  2534. LONG lRet;
  2535. if (lpClass && !lpcbClass)
  2536. {
  2537. LOGN( eDbgLevelError, "[QueryInfoA] NULL passed for lpClass but not lpcbClass. Fixing.");
  2538. lpcbClass = NULL;
  2539. }
  2540. if (lpClass && lpcbClass)
  2541. {
  2542. WCHAR wClass[MAX_PATH];
  2543. DWORD dwSize;
  2544. if (MultiByteToWideChar(
  2545. CP_ACP,
  2546. 0,
  2547. lpClass,
  2548. -1,
  2549. (LPWSTR)wClass,
  2550. MAX_PATH) == 0)
  2551. {
  2552. return ERROR_INVALID_PARAMETER;
  2553. }
  2554. dwSize = *lpcbClass * 2;
  2555. lRet = QueryInfoW(
  2556. hKey,
  2557. wClass,
  2558. &dwSize,
  2559. lpReserved,
  2560. lpcSubKeys,
  2561. lpcbMaxSubKeyLen,
  2562. lpcbMaxClassLen,
  2563. lpcValues,
  2564. lpcbMaxValueNameLen,
  2565. lpcbMaxValueLen,
  2566. lpcbSecurityDescriptor,
  2567. lpftLastWriteTime);
  2568. if (SUCCESS(lRet))
  2569. {
  2570. if (WideCharToMultiByte(
  2571. CP_ACP,
  2572. 0,
  2573. (LPWSTR)wClass,
  2574. dwSize,
  2575. (LPSTR)lpClass,
  2576. *lpcbClass,
  2577. 0,
  2578. 0) == 0)
  2579. {
  2580. return ERROR_INVALID_PARAMETER;
  2581. }
  2582. }
  2583. *lpcbClass = dwSize / 2;
  2584. }
  2585. else
  2586. {
  2587. lRet = QueryInfoW(
  2588. hKey,
  2589. NULL,
  2590. NULL,
  2591. lpReserved,
  2592. lpcSubKeys,
  2593. lpcbMaxSubKeyLen,
  2594. lpcbMaxClassLen,
  2595. lpcValues,
  2596. lpcbMaxValueNameLen,
  2597. lpcbMaxValueLen,
  2598. lpcbSecurityDescriptor,
  2599. lpftLastWriteTime);
  2600. }
  2601. return lRet;
  2602. }
  2603. /*++
  2604. Function Description:
  2605. Wrapper for RegQueryInfoKeyW.
  2606. Algorithm:
  2607. 1. Revert to the old API if the key isn't virtual
  2608. 2. Calculate all the virtual key and value name lengths by going through
  2609. them individually.
  2610. 3. Add all non-virtual key and value's that don't have overriding virtual's.
  2611. Arguments:
  2612. IN hKey - handle to key to query
  2613. OUT lpClass - address of buffer for class string
  2614. OUT lpcbClass - address of size of class string buffer
  2615. OUT lpReserved - reserved
  2616. OUT lpcSubKeys - address of buffer for number of subkeys
  2617. OUT lpcbMaxSubKeyLen - address of buffer for longest subkey
  2618. OUT lpcbMaxClassLen - address of buffer for longest class string length
  2619. OUT lpcValues - address of buffer for number of value entries
  2620. OUT lpcbMaxValueNameLen - address of buffer for longest value name length
  2621. OUT lpcbMaxValueLen - address of buffer for longest value data length
  2622. OUT lpcbSecurityDescriptor - address of buffer for security descriptor length
  2623. OUT lpftLastWriteTime - address of buffer for last write time
  2624. Return Value:
  2625. Error code or ERROR_SUCCESS
  2626. History:
  2627. 01/06/2000 linstev Created
  2628. 08/03/2001 mikrause Added support for counting both virtual & non-virtual keys & values.
  2629. --*/
  2630. LONG
  2631. CVirtualRegistry::QueryInfoW(
  2632. IN HKEY hKey,
  2633. OUT LPWSTR lpClass,
  2634. OUT LPDWORD lpcbClass,
  2635. OUT LPDWORD lpReserved,
  2636. OUT LPDWORD lpcSubKeys,
  2637. OUT LPDWORD lpcbMaxSubKeyLen,
  2638. OUT LPDWORD lpcbMaxClassLen,
  2639. OUT LPDWORD lpcValues,
  2640. OUT LPDWORD lpcbMaxValueNameLen,
  2641. OUT LPDWORD lpcbMaxValueLen,
  2642. OUT LPDWORD lpcbSecurityDescriptor,
  2643. OUT PFILETIME lpftLastWriteTime
  2644. )
  2645. {
  2646. LONG lRet;
  2647. OPENKEY *key;
  2648. DWORD cbData = 0;
  2649. ENUMENTRY *enumkey;
  2650. ENUMENTRY *enumval;
  2651. if (lpClass && !lpcbClass)
  2652. {
  2653. LOGN( eDbgLevelError, "[QueryInfoW] NULL passed for lpClass but not lpcbClass. Fixing.");
  2654. lpcbClass = NULL;
  2655. }
  2656. key = FindOpenKey(hKey);
  2657. if (key)
  2658. {
  2659. if (lpClass)
  2660. {
  2661. lpClass[0] = L'\0';
  2662. }
  2663. if (lpcbClass)
  2664. {
  2665. *lpcbClass = 0;
  2666. }
  2667. if (lpcbMaxClassLen)
  2668. {
  2669. *lpcbMaxClassLen = 0;
  2670. }
  2671. if (lpReserved)
  2672. {
  2673. *lpReserved = 0;
  2674. }
  2675. if (lpcSubKeys || lpcbMaxSubKeyLen)
  2676. {
  2677. DWORD i = 0;
  2678. DWORD len = 0;
  2679. // Count virtual keys.
  2680. if (!key->enumKeys)
  2681. {
  2682. key->BuildEnumList();
  2683. }
  2684. enumkey = key->enumKeys;
  2685. while (enumkey)
  2686. {
  2687. i++;
  2688. len = max(len, wcslen(enumkey->wzName));
  2689. enumkey = enumkey->next;
  2690. }
  2691. if (lpcSubKeys)
  2692. {
  2693. *lpcSubKeys = i;
  2694. }
  2695. if (lpcbMaxSubKeyLen)
  2696. {
  2697. *lpcbMaxSubKeyLen = len;
  2698. }
  2699. }
  2700. if (lpcValues || lpcbMaxValueNameLen || lpcbMaxValueLen)
  2701. {
  2702. // Check if this key has virtual values or is virtual.
  2703. if (key->bVirtual || (key->vkey && key->vkey->values))
  2704. {
  2705. DWORD i = 0;
  2706. DWORD lenA = 0, lenB = 0;
  2707. if (key->enumValues == NULL)
  2708. {
  2709. key->BuildEnumList();
  2710. }
  2711. enumval = key->enumValues;
  2712. while (enumval)
  2713. {
  2714. i++;
  2715. QueryValueW(key->hkOpen, enumval->wzName, NULL, NULL, &cbData);
  2716. lenA = max(lenA, cbData);
  2717. lenB = max(lenB, wcslen(enumval->wzName));
  2718. enumval = enumval->next;
  2719. }
  2720. if (lpcValues)
  2721. {
  2722. *lpcValues = i;
  2723. }
  2724. if (lpcbMaxValueLen)
  2725. {
  2726. *lpcbMaxValueLen = lenA;
  2727. }
  2728. if (lpcbMaxValueNameLen)
  2729. {
  2730. *lpcbMaxValueNameLen = lenB;
  2731. }
  2732. }
  2733. // No virtual values, do a normal query.
  2734. else
  2735. {
  2736. lRet = ORIGINAL_API(RegQueryInfoKeyW)(
  2737. key->hkOpen,
  2738. NULL,
  2739. NULL,
  2740. NULL,
  2741. NULL,
  2742. NULL,
  2743. NULL,
  2744. lpcValues,
  2745. lpcbMaxValueNameLen,
  2746. lpcbMaxValueLen,
  2747. NULL,
  2748. lpftLastWriteTime);
  2749. }
  2750. }
  2751. if (lpcbSecurityDescriptor)
  2752. {
  2753. *lpcbSecurityDescriptor = NULL;
  2754. }
  2755. lRet = ERROR_SUCCESS;
  2756. }
  2757. else
  2758. {
  2759. lRet = ORIGINAL_API(RegQueryInfoKeyW)(
  2760. hKey,
  2761. lpClass,
  2762. lpcbClass,
  2763. lpReserved,
  2764. lpcSubKeys,
  2765. lpcbMaxSubKeyLen,
  2766. lpcbMaxClassLen,
  2767. lpcValues,
  2768. lpcbMaxValueNameLen,
  2769. lpcbMaxValueLen,
  2770. lpcbSecurityDescriptor,
  2771. lpftLastWriteTime);
  2772. }
  2773. DPFN( ELEVEL(lRet), "%08lx=QueryInfoW(hKey=%04lx)",
  2774. lRet,
  2775. hKey);
  2776. if (key)
  2777. {
  2778. DPFN( ELEVEL(lRet), " Path=%S", key->wzPath);
  2779. }
  2780. return lRet;
  2781. }
  2782. /*++
  2783. Function Description:
  2784. Wrapper for RegSetValueA.
  2785. Algorithm:
  2786. 1. Convert value name and data (if string) to Unicode.
  2787. 2. Call SetValueW
  2788. Arguments:
  2789. hKey - Key to set value in.
  2790. lpValueName - Name of value to set.
  2791. dwType - Type of value (string, DWORD, etc.)
  2792. lpData - Buffer containing data to write.
  2793. cbData - Size of lpData in bytes.
  2794. Return Value:
  2795. ERROR_SUCCESS on success, failure code otherwise.
  2796. History:
  2797. 08/07/2001 mikrause Created
  2798. --*/
  2799. LONG
  2800. CVirtualRegistry::SetValueA(
  2801. HKEY hKey,
  2802. LPCSTR lpValueName,
  2803. DWORD dwType,
  2804. CONST BYTE* lpData,
  2805. DWORD cbData
  2806. )
  2807. {
  2808. LONG lRet;
  2809. DWORD dwSize;
  2810. WCHAR* wszValName = NULL;
  2811. BYTE* lpExpandedData = (BYTE*)lpData;
  2812. if (lpValueName != NULL)
  2813. {
  2814. dwSize = (DWORD)(lstrlenA(lpValueName) + 1);
  2815. dwSize *= sizeof(WCHAR);
  2816. wszValName = (WCHAR*)malloc(dwSize);
  2817. if (wszValName == NULL)
  2818. {
  2819. DPFN( eDbgLevelError, szOutOfMemory);
  2820. return ERROR_NOT_ENOUGH_MEMORY;
  2821. }
  2822. if (MultiByteToWideChar(
  2823. CP_ACP,
  2824. 0,
  2825. lpValueName,
  2826. -1,
  2827. (LPWSTR)wszValName,
  2828. dwSize/sizeof(WCHAR)) == 0)
  2829. {
  2830. return ERROR_INVALID_PARAMETER;
  2831. }
  2832. }
  2833. dwSize = cbData;
  2834. //
  2835. // Expand text buffers
  2836. //
  2837. if (lpData && (dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ))
  2838. {
  2839. if ((dwType != REG_MULTI_SZ) && g_bWin9x)
  2840. {
  2841. dwSize = (DWORD)(lstrlenA((char*)lpData) + 1);
  2842. }
  2843. lpExpandedData = (BYTE*) malloc(dwSize * sizeof(WCHAR));
  2844. if (lpExpandedData == NULL)
  2845. {
  2846. if (wszValName)
  2847. {
  2848. free(wszValName);
  2849. }
  2850. DPFN( eDbgLevelError, szOutOfMemory);
  2851. return ERROR_NOT_ENOUGH_MEMORY;
  2852. }
  2853. if (MultiByteToWideChar(
  2854. CP_ACP,
  2855. 0,
  2856. (LPCSTR)lpData,
  2857. dwSize,
  2858. (LPWSTR)lpExpandedData,
  2859. dwSize) == 0)
  2860. {
  2861. return ERROR_INVALID_PARAMETER;
  2862. }
  2863. dwSize = dwSize * sizeof(WCHAR);
  2864. }
  2865. lRet = SetValueW(hKey, wszValName, dwType, lpExpandedData, dwSize);
  2866. if (lpExpandedData != lpData)
  2867. {
  2868. free(lpExpandedData);
  2869. }
  2870. if (wszValName)
  2871. {
  2872. free(wszValName);
  2873. }
  2874. return lRet;
  2875. }
  2876. /*++
  2877. Function Description:
  2878. Wrapper for RegSetValueW.
  2879. Also protects for non-zero buffer length with zero buffer AV.
  2880. Algorithm:
  2881. 1. If non-protected key, write to registry using RegSetValueW
  2882. Arguments:
  2883. hKey - Key to set value in.
  2884. lpValueName - Name of value to set.
  2885. dwType - Type of value (string, DWORD, etc.)
  2886. lpData - Buffer containing data to write.
  2887. cbData - Size of lpData in bytes.
  2888. Return Value:
  2889. ERROR_SUCCESS on success, failure code otherwise.
  2890. History:
  2891. 08/07/2001 mikrause Created
  2892. --*/
  2893. LONG
  2894. CVirtualRegistry::SetValueW(
  2895. HKEY hKey,
  2896. LPCWSTR lpValueName,
  2897. DWORD dwType,
  2898. CONST BYTE* lpData,
  2899. DWORD cbData
  2900. )
  2901. {
  2902. LONG lRet;
  2903. // Just a paranoid sanity check
  2904. if (!hKey)
  2905. {
  2906. DPFN( eDbgLevelError, "NULL handle passed to SetValueW");
  2907. return ERROR_INVALID_HANDLE;
  2908. }
  2909. __try
  2910. {
  2911. lRet = ERROR_FILE_NOT_FOUND;
  2912. // To duplicate Win95/win98 behavior automatically override
  2913. // the cbData with the actual length of the lpData for REG_SZ.
  2914. if (g_bWin9x && lpData &&
  2915. ((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)))
  2916. {
  2917. cbData = (wcslen((WCHAR *)lpData)+1)*sizeof(WCHAR);
  2918. }
  2919. VIRTUALKEY *vkey;
  2920. VIRTUALVAL *vvalue;
  2921. OPENKEY* key = FindOpenKey(hKey);
  2922. if (key)
  2923. {
  2924. // Check if we should execute a custom action.
  2925. vkey = key->vkey;
  2926. vvalue = vkey ? vkey->FindValue(lpValueName) : NULL;
  2927. if (vkey && vvalue &&
  2928. vvalue->pfnSetValue)
  2929. {
  2930. lRet = vvalue->pfnSetValue(key, vkey, vvalue,
  2931. dwType, lpData,cbData);
  2932. }
  2933. else
  2934. {
  2935. // No custom action, just set value as normal.
  2936. lRet = ORIGINAL_API(RegSetValueExW)(
  2937. hKey,
  2938. lpValueName,
  2939. 0,
  2940. dwType,
  2941. lpData,
  2942. cbData);
  2943. }
  2944. // Possible change in enumeration data, flush lists.
  2945. if (lRet == ERROR_SUCCESS)
  2946. {
  2947. key->FlushEnumList();
  2948. }
  2949. }
  2950. // No key, fall through to original API
  2951. else
  2952. {
  2953. lRet = ORIGINAL_API(RegSetValueExW)(
  2954. hKey,
  2955. lpValueName,
  2956. 0,
  2957. dwType,
  2958. lpData,
  2959. cbData);
  2960. }
  2961. DPFN( ELEVEL(lRet), "%08lx=SetValueW(Key=%04lx)",
  2962. lRet,
  2963. hKey);
  2964. if (key)
  2965. {
  2966. DPFN( ELEVEL(lRet), " Path=%S\\%S", key->wzPath, lpValueName);
  2967. }
  2968. else
  2969. {
  2970. DPFN( ELEVEL(lRet), " Value=%S", lpValueName);
  2971. }
  2972. if (SUCCESS(lRet) &&
  2973. ((dwType == REG_SZ) ||
  2974. (dwType == REG_EXPAND_SZ)))
  2975. {
  2976. DPFN( eDbgLevelInfo, " Result=%S", lpData);
  2977. }
  2978. }
  2979. __except(EXCEPTION_EXECUTE_HANDLER)
  2980. {
  2981. DPFN( eDbgLevelError, "Exception occurred in SetValueW");
  2982. lRet = ERROR_BAD_ARGUMENTS;
  2983. }
  2984. return lRet;
  2985. }
  2986. /*++
  2987. Function Description:
  2988. Wrapper for RegDeleteKeyA.
  2989. Algorithm:
  2990. 1. Convert key name to Unicode.
  2991. 2. Call DeleteKeyW
  2992. Arguments:
  2993. hKey - Key that contains subkey to delete.
  2994. lpSubKey - Key name to delete.
  2995. Return Value:
  2996. ERROR_SUCCESS on success, failure code otherwise.
  2997. History:
  2998. 08/07/2001 mikrause Created
  2999. --*/
  3000. LONG
  3001. CVirtualRegistry::DeleteKeyA(
  3002. IN HKEY hKey,
  3003. IN LPCSTR lpSubKey
  3004. )
  3005. {
  3006. LONG lRet;
  3007. DWORD dwSize;
  3008. WCHAR* wszSubKey = NULL;
  3009. dwSize = (DWORD)(lstrlenA(lpSubKey) + 1);
  3010. dwSize *= sizeof(WCHAR);
  3011. wszSubKey = (WCHAR*)malloc(dwSize);
  3012. if (wszSubKey == NULL)
  3013. {
  3014. DPFN( eDbgLevelError, szOutOfMemory);
  3015. return ERROR_NOT_ENOUGH_MEMORY;
  3016. }
  3017. if (MultiByteToWideChar(
  3018. CP_ACP,
  3019. 0,
  3020. lpSubKey,
  3021. -1,
  3022. (LPWSTR)wszSubKey,
  3023. dwSize/sizeof(WCHAR)) == 0)
  3024. {
  3025. return ERROR_INVALID_PARAMETER;
  3026. }
  3027. lRet = DeleteKeyW(hKey, wszSubKey);
  3028. free(wszSubKey);
  3029. return lRet;
  3030. }
  3031. /*++
  3032. Function Description:
  3033. Wrapper for DeleteKeyW.
  3034. Algorithm:
  3035. 1. If key is not protected, delete key.
  3036. 2. If in 9x compat mode, recursively delete all subkeys.
  3037. Arguments:
  3038. hKey - Key to that contains subkey to delete.
  3039. lpSubKey - Name of key to delete
  3040. Return Value:
  3041. ERROR_SUCCESS on success, failure code otherwise.
  3042. History:
  3043. 08/07/2001 mikrause Created
  3044. --*/
  3045. LONG
  3046. CVirtualRegistry::DeleteKeyW(
  3047. IN HKEY hKey,
  3048. IN LPCWSTR lpSubKey
  3049. )
  3050. {
  3051. LONG hRet;
  3052. OPENKEY* key = FindOpenKey(hKey);
  3053. LPWSTR wzPath = NULL;
  3054. BOOL bProtected;
  3055. // Key not found, assume it's a root key.
  3056. if (!key)
  3057. {
  3058. DPFN( eDbgLevelInfo, "Key not found!");
  3059. wzPath = MakePath(hKey, 0, lpSubKey);
  3060. if (!wzPath)
  3061. {
  3062. DPFN(eDbgLevelError, szOutOfMemory);
  3063. return ERROR_NOT_ENOUGH_MEMORY;
  3064. }
  3065. DPFN( eDbgLevelInfo, "Using path %S", wzPath);
  3066. }
  3067. else if (lpSubKey)
  3068. {
  3069. DWORD dwSize = wcslen(key->wzPath) + wcslen(L"\\") + wcslen(lpSubKey) + 1;
  3070. wzPath = (LPWSTR) malloc(dwSize * sizeof(WCHAR));
  3071. if (!wzPath)
  3072. {
  3073. DPFN(eDbgLevelError, szOutOfMemory);
  3074. return ERROR_NOT_ENOUGH_MEMORY;
  3075. }
  3076. ZeroMemory(wzPath, dwSize);
  3077. StringCchCopyW(wzPath, dwSize, key->wzPath);
  3078. StringCchCatW(wzPath, dwSize, L"\\");
  3079. StringCchCatW(wzPath, dwSize, lpSubKey);
  3080. }
  3081. bProtected = (key && CheckProtected(key->wzPath))
  3082. || (wzPath && CheckProtected(wzPath));
  3083. if (!bProtected)
  3084. {
  3085. if (g_bWin9x)
  3086. {
  3087. //
  3088. // Find out whether hKey has any subkeys under it or not.
  3089. // If not, then proceed as normal.
  3090. // If yes, recursively delete the subkeys under it
  3091. // Then proceed as normal.
  3092. //
  3093. DWORD cSize = 0;
  3094. WCHAR lpSubKeyName[MAX_PATH];
  3095. HKEY hSubKey;
  3096. DPFN( eDbgLevelInfo, "RegDeleteKeyW called with hKey: %x, SubKey: %S", hKey, lpSubKey);
  3097. hRet = ORIGINAL_API(RegOpenKeyExW)(
  3098. hKey,
  3099. lpSubKey,
  3100. 0,
  3101. KEY_ENUMERATE_SUB_KEYS,
  3102. &hSubKey);
  3103. if (SUCCESS(hRet))
  3104. {
  3105. for (;;)
  3106. {
  3107. cSize = MAX_PATH;
  3108. hRet = ORIGINAL_API(RegEnumKeyExW)(
  3109. hSubKey,
  3110. 0,
  3111. lpSubKeyName,
  3112. &cSize,
  3113. NULL,
  3114. NULL,
  3115. NULL,
  3116. NULL
  3117. );
  3118. if (SUCCESS(hRet))
  3119. {
  3120. LOGN( eDbgLevelInfo,
  3121. "[DeleteKeyW] Deleting subkey %S for key %S.",
  3122. lpSubKeyName,
  3123. lpSubKey);
  3124. hRet = DeleteKeyW(
  3125. hSubKey,
  3126. lpSubKeyName);
  3127. if (SUCCESS(hRet))
  3128. {
  3129. LOGN( eDbgLevelInfo, "[DeleteKeyW] subkey %S was deleted.",lpSubKeyName);
  3130. }
  3131. else
  3132. {
  3133. LOGN( eDbgLevelInfo, "[DeleteKeyW] subkey %S was not deleted.",lpSubKeyName);
  3134. break;
  3135. }
  3136. }
  3137. else
  3138. {
  3139. DPFN( eDbgLevelInfo, "[DeleteKeyW] No more subkey under key %S.",lpSubKey);
  3140. break;
  3141. }
  3142. }
  3143. ORIGINAL_API(RegCloseKey)(hSubKey);
  3144. }
  3145. }
  3146. DPFN( eDbgLevelInfo, "[RegDeleteKeyW] Deleting subkey %S.",lpSubKey);
  3147. hRet = ORIGINAL_API(RegDeleteKeyW)(
  3148. hKey,
  3149. lpSubKey);
  3150. }
  3151. else
  3152. {
  3153. // Protected, just say it succeeded
  3154. hRet = ERROR_SUCCESS;
  3155. }
  3156. if (wzPath)
  3157. {
  3158. free(wzPath);
  3159. }
  3160. // Possible change in enumeration data, flush lists.
  3161. FlushEnumLists();
  3162. return hRet;
  3163. }
  3164. /*++
  3165. Function Description:
  3166. Wrapper for RegCloseKey. Note that we make sure we know about the key before closing it.
  3167. Algorithm:
  3168. 1. Run the list of open keys and free if found
  3169. 2. Close the key
  3170. Arguments:
  3171. IN hKey - Handle to open key to close
  3172. Return Value:
  3173. Error code or ERROR_SUCCESS
  3174. History:
  3175. 01/06/2000 linstev Created
  3176. --*/
  3177. LONG
  3178. CVirtualRegistry::CloseKey(
  3179. IN HKEY hKey
  3180. )
  3181. {
  3182. OPENKEY *key = OpenKeys, *last = NULL;
  3183. LONG lRet;
  3184. __try
  3185. {
  3186. lRet = ERROR_INVALID_HANDLE;
  3187. while (key)
  3188. {
  3189. if (key->hkOpen == hKey)
  3190. {
  3191. if (last)
  3192. {
  3193. last->next = key->next;
  3194. }
  3195. else
  3196. {
  3197. OpenKeys = key->next;
  3198. }
  3199. lRet = ORIGINAL_API(RegCloseKey)(hKey);
  3200. free(key->wzPath);
  3201. free(key);
  3202. break;
  3203. }
  3204. last = key;
  3205. key = key->next;
  3206. }
  3207. if (key == NULL)
  3208. {
  3209. RegCloseKey(hKey);
  3210. }
  3211. DPFN( ELEVEL(lRet), "%08lx=CloseKey(Key=%04lx)", lRet, hKey);
  3212. }
  3213. __except(EXCEPTION_EXECUTE_HANDLER)
  3214. {
  3215. lRet = ERROR_INVALID_HANDLE;
  3216. }
  3217. return lRet;
  3218. }
  3219. /*++
  3220. Pass through to virtual registry to handle call.
  3221. --*/
  3222. LONG
  3223. APIHOOK(RegCreateKeyA)(
  3224. HKEY hKey,
  3225. LPCSTR lpSubKey,
  3226. PHKEY phkResult
  3227. )
  3228. {
  3229. CRegLock Lock;
  3230. return VRegistry.OpenKeyA(
  3231. hKey,
  3232. lpSubKey,
  3233. 0,
  3234. REG_OPTION_NON_VOLATILE,
  3235. MAXIMUM_ALLOWED,
  3236. NULL,
  3237. phkResult,
  3238. 0,
  3239. TRUE);
  3240. }
  3241. /*++
  3242. Pass through to virtual registry to handle call.
  3243. --*/
  3244. LONG
  3245. APIHOOK(RegCreateKeyW)(
  3246. HKEY hKey,
  3247. LPCWSTR lpSubKey,
  3248. PHKEY phkResult
  3249. )
  3250. {
  3251. CRegLock Lock;
  3252. return VRegistry.OpenKeyW(
  3253. hKey,
  3254. lpSubKey,
  3255. 0,
  3256. REG_OPTION_NON_VOLATILE,
  3257. MAXIMUM_ALLOWED,
  3258. NULL,
  3259. phkResult,
  3260. 0,
  3261. TRUE);
  3262. }
  3263. /*++
  3264. Pass through to virtual registry to handle call.
  3265. --*/
  3266. LONG
  3267. APIHOOK(RegCreateKeyExA)(
  3268. HKEY hKey,
  3269. LPCSTR lpSubKey,
  3270. DWORD /* Reserved */,
  3271. LPSTR lpClass,
  3272. DWORD dwOptions,
  3273. REGSAM samDesired,
  3274. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  3275. PHKEY phkResult,
  3276. LPDWORD lpdwDisposition
  3277. )
  3278. {
  3279. CRegLock Lock;
  3280. return VRegistry.OpenKeyA(
  3281. hKey,
  3282. lpSubKey,
  3283. lpClass,
  3284. dwOptions,
  3285. samDesired,
  3286. lpSecurityAttributes,
  3287. phkResult,
  3288. lpdwDisposition,
  3289. TRUE);
  3290. }
  3291. /*++
  3292. Pass through to virtual registry to handle call.
  3293. --*/
  3294. LONG
  3295. APIHOOK(RegCreateKeyExW)(
  3296. HKEY hKey,
  3297. LPCWSTR lpSubKey,
  3298. DWORD /* Reserved */,
  3299. LPWSTR lpClass,
  3300. DWORD dwOptions,
  3301. REGSAM samDesired,
  3302. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  3303. PHKEY phkResult,
  3304. LPDWORD lpdwDisposition
  3305. )
  3306. {
  3307. CRegLock Lock;
  3308. return VRegistry.OpenKeyW(
  3309. hKey,
  3310. lpSubKey,
  3311. lpClass,
  3312. dwOptions,
  3313. samDesired,
  3314. lpSecurityAttributes,
  3315. phkResult,
  3316. lpdwDisposition,
  3317. TRUE);
  3318. }
  3319. /*++
  3320. Pass through to virtual registry to handle call.
  3321. --*/
  3322. LONG
  3323. APIHOOK(RegOpenKeyA)(
  3324. HKEY hKey,
  3325. LPCSTR lpSubKey,
  3326. PHKEY phkResult
  3327. )
  3328. {
  3329. CRegLock Lock;
  3330. return VRegistry.OpenKeyA(hKey, lpSubKey, 0, 0, MAXIMUM_ALLOWED, NULL, phkResult, 0, FALSE);
  3331. }
  3332. /*++
  3333. Pass through to virtual registry to handle call.
  3334. --*/
  3335. LONG
  3336. APIHOOK(RegOpenKeyW)(
  3337. HKEY hKey,
  3338. LPCWSTR lpSubKey,
  3339. PHKEY phkResult
  3340. )
  3341. {
  3342. CRegLock Lock;
  3343. return VRegistry.OpenKeyW(hKey, lpSubKey, 0, 0, MAXIMUM_ALLOWED, NULL, phkResult, 0, FALSE);
  3344. }
  3345. /*++
  3346. Pass through to virtual registry to handle call.
  3347. --*/
  3348. LONG
  3349. APIHOOK(RegOpenKeyExA)(
  3350. HKEY hKey,
  3351. LPCSTR lpSubKey,
  3352. DWORD /* ulOptions */,
  3353. REGSAM samDesired,
  3354. PHKEY phkResult
  3355. )
  3356. {
  3357. CRegLock Lock;
  3358. return VRegistry.OpenKeyA(hKey, lpSubKey, 0, 0, samDesired, NULL, phkResult, 0, FALSE);
  3359. }
  3360. /*++
  3361. Pass through to virtual registry to handle call.
  3362. --*/
  3363. LONG
  3364. APIHOOK(RegOpenKeyExW)(
  3365. HKEY hKey,
  3366. LPCWSTR lpSubKey,
  3367. DWORD /* ulOptions */,
  3368. REGSAM samDesired,
  3369. PHKEY phkResult
  3370. )
  3371. {
  3372. CRegLock Lock;
  3373. return VRegistry.OpenKeyW(hKey, lpSubKey, 0, 0, samDesired, NULL, phkResult, 0, FALSE);
  3374. }
  3375. /*++
  3376. Not yet implemented
  3377. --*/
  3378. LONG
  3379. APIHOOK(RegQueryValueA)(
  3380. HKEY hKey,
  3381. LPCSTR lpSubKey,
  3382. LPSTR lpData,
  3383. PLONG lpcbData
  3384. )
  3385. {
  3386. CRegLock Lock;
  3387. return ORIGINAL_API(RegQueryValueA)(
  3388. hKey,
  3389. lpSubKey,
  3390. lpData,
  3391. lpcbData);
  3392. }
  3393. /*++
  3394. Not yet implemented
  3395. --*/
  3396. LONG
  3397. APIHOOK(RegQueryValueW)(
  3398. HKEY hKey,
  3399. LPCWSTR lpSubKey,
  3400. LPWSTR lpData,
  3401. PLONG lpcbData
  3402. )
  3403. {
  3404. CRegLock Lock;
  3405. return ORIGINAL_API(RegQueryValueW)(
  3406. hKey,
  3407. lpSubKey,
  3408. lpData,
  3409. lpcbData);
  3410. }
  3411. /*++
  3412. Pass through to virtual registry to handle call.
  3413. --*/
  3414. LONG
  3415. APIHOOK(RegQueryValueExA)(
  3416. HKEY hKey,
  3417. LPSTR lpValueName,
  3418. LPDWORD /* lpReserved */,
  3419. LPDWORD lpType,
  3420. LPBYTE lpData,
  3421. LPDWORD lpcbData
  3422. )
  3423. {
  3424. CRegLock Lock;
  3425. return VRegistry.QueryValueA(hKey, lpValueName, lpType, lpData, lpcbData);
  3426. }
  3427. /*++
  3428. Pass through to virtual registry to handle call.
  3429. --*/
  3430. LONG
  3431. APIHOOK(RegQueryValueExW)(
  3432. HKEY hKey,
  3433. LPWSTR lpValueName,
  3434. LPDWORD /* lpReserved */,
  3435. LPDWORD lpType,
  3436. LPBYTE lpData,
  3437. LPDWORD lpcbData
  3438. )
  3439. {
  3440. CRegLock Lock;
  3441. return VRegistry.QueryValueW(hKey, lpValueName, lpType, lpData, lpcbData);
  3442. }
  3443. /*++
  3444. Pass through to virtual registry to handle call.
  3445. --*/
  3446. LONG
  3447. APIHOOK(RegCloseKey)(HKEY hKey)
  3448. {
  3449. CRegLock Lock;
  3450. return VRegistry.CloseKey(hKey);
  3451. }
  3452. /*++
  3453. Pass through to virtual registry to handle call.
  3454. --*/
  3455. LONG
  3456. APIHOOK(RegEnumValueA)(
  3457. HKEY hKey,
  3458. DWORD dwIndex,
  3459. LPSTR lpValueName,
  3460. LPDWORD lpcbValueName,
  3461. LPDWORD /* lpReserved */,
  3462. LPDWORD lpType,
  3463. LPBYTE lpData,
  3464. LPDWORD lpcbData
  3465. )
  3466. {
  3467. CRegLock Lock;
  3468. return VRegistry.EnumValueA(
  3469. hKey,
  3470. dwIndex,
  3471. lpValueName,
  3472. lpcbValueName,
  3473. lpType,
  3474. lpData,
  3475. lpcbData);
  3476. }
  3477. /*++
  3478. Pass through to virtual registry to handle call.
  3479. --*/
  3480. LONG
  3481. APIHOOK(RegEnumValueW)(
  3482. HKEY hKey,
  3483. DWORD dwIndex,
  3484. LPWSTR lpValueName,
  3485. LPDWORD lpcbValueName,
  3486. LPDWORD /* lpReserved */,
  3487. LPDWORD lpType,
  3488. LPBYTE lpData,
  3489. LPDWORD lpcbData
  3490. )
  3491. {
  3492. CRegLock Lock;
  3493. return VRegistry.EnumValueW(
  3494. hKey,
  3495. dwIndex,
  3496. lpValueName,
  3497. lpcbValueName,
  3498. lpType,
  3499. lpData,
  3500. lpcbData);
  3501. }
  3502. /*++
  3503. Pass through to virtual registry to handle call.
  3504. --*/
  3505. LONG
  3506. APIHOOK(RegEnumKeyExA)(
  3507. HKEY hKey,
  3508. DWORD dwIndex,
  3509. LPSTR lpName,
  3510. LPDWORD lpcbName,
  3511. LPDWORD /* lpReserved */,
  3512. LPSTR /* lpClass */,
  3513. LPDWORD /* lpcbClass */,
  3514. PFILETIME /* lpftLastWriteTime */
  3515. )
  3516. {
  3517. CRegLock Lock;
  3518. return VRegistry.EnumKeyA(hKey, dwIndex, lpName, lpcbName);
  3519. }
  3520. /*++
  3521. Pass through to virtual registry to handle call.
  3522. --*/
  3523. LONG
  3524. APIHOOK(RegEnumKeyExW)(
  3525. HKEY hKey,
  3526. DWORD dwIndex,
  3527. LPWSTR lpName,
  3528. LPDWORD lpcbName,
  3529. LPDWORD /* lpReserved */,
  3530. LPWSTR /* lpClass */,
  3531. LPDWORD /* lpcbClass */,
  3532. PFILETIME /* lpftLastWriteTime */
  3533. )
  3534. {
  3535. CRegLock Lock;
  3536. return VRegistry.EnumKeyW(hKey, dwIndex, lpName, lpcbName);
  3537. }
  3538. /*++
  3539. Pass through to virtual registry to handle call.
  3540. --*/
  3541. LONG
  3542. APIHOOK(RegEnumKeyA)(
  3543. HKEY hKey,
  3544. DWORD dwIndex,
  3545. LPSTR lpName,
  3546. DWORD cbName
  3547. )
  3548. {
  3549. CRegLock Lock;
  3550. return VRegistry.EnumKeyA(hKey, dwIndex, lpName, &cbName);
  3551. }
  3552. /*++
  3553. Calls down to RegEnumKeyExW
  3554. --*/
  3555. LONG
  3556. APIHOOK(RegEnumKeyW)(
  3557. HKEY hKey,
  3558. DWORD dwIndex,
  3559. LPWSTR lpName,
  3560. DWORD cbName
  3561. )
  3562. {
  3563. CRegLock Lock;
  3564. return VRegistry.EnumKeyW(hKey, dwIndex, lpName, &cbName);
  3565. }
  3566. /*++
  3567. Pass through to virtual registry to handle call.
  3568. --*/
  3569. LONG
  3570. APIHOOK(RegQueryInfoKeyW)(
  3571. HKEY hKey,
  3572. LPWSTR lpClass,
  3573. LPDWORD lpcbClass,
  3574. LPDWORD lpReserved,
  3575. LPDWORD lpcSubKeys,
  3576. LPDWORD lpcbMaxSubKeyLen,
  3577. LPDWORD lpcbMaxClassLen,
  3578. LPDWORD lpcValues,
  3579. LPDWORD lpcbMaxValueNameLen,
  3580. LPDWORD lpcbMaxValueLen,
  3581. LPDWORD lpcbSecurityDescriptor,
  3582. PFILETIME lpftLastWriteTime
  3583. )
  3584. {
  3585. CRegLock Lock;
  3586. return VRegistry.QueryInfoW(
  3587. hKey,
  3588. lpClass,
  3589. lpcbClass,
  3590. lpReserved,
  3591. lpcSubKeys,
  3592. lpcbMaxSubKeyLen,
  3593. lpcbMaxClassLen,
  3594. lpcValues,
  3595. lpcbMaxValueNameLen,
  3596. lpcbMaxValueLen,
  3597. lpcbSecurityDescriptor,
  3598. lpftLastWriteTime);
  3599. }
  3600. /*++
  3601. Pass through to virtual registry to handle call.
  3602. --*/
  3603. LONG
  3604. APIHOOK(RegQueryInfoKeyA)(
  3605. HKEY hKey,
  3606. LPSTR lpClass,
  3607. LPDWORD lpcbClass,
  3608. LPDWORD lpReserved,
  3609. LPDWORD lpcSubKeys,
  3610. LPDWORD lpcbMaxSubKeyLen,
  3611. LPDWORD lpcbMaxClassLen,
  3612. LPDWORD lpcValues,
  3613. LPDWORD lpcbMaxValueNameLen,
  3614. LPDWORD lpcbMaxValueLen,
  3615. LPDWORD lpcbSecurityDescriptor,
  3616. PFILETIME lpftLastWriteTime
  3617. )
  3618. {
  3619. CRegLock Lock;
  3620. return VRegistry.QueryInfoA(
  3621. hKey,
  3622. lpClass,
  3623. lpcbClass,
  3624. lpReserved,
  3625. lpcSubKeys,
  3626. lpcbMaxSubKeyLen,
  3627. lpcbMaxClassLen,
  3628. lpcValues,
  3629. lpcbMaxValueNameLen,
  3630. lpcbMaxValueLen,
  3631. lpcbSecurityDescriptor,
  3632. lpftLastWriteTime);
  3633. }
  3634. /*++
  3635. Pass through to virtual registry to handle call.
  3636. --*/
  3637. LONG
  3638. APIHOOK(RegSetValueExA)(
  3639. HKEY hKey,
  3640. LPCSTR lpSubKey,
  3641. DWORD /* Reserved */,
  3642. DWORD dwType,
  3643. CONST BYTE * lpData,
  3644. DWORD cbData
  3645. )
  3646. {
  3647. LONG lRet = 0;
  3648. if (!lpData && cbData)
  3649. {
  3650. lRet = ERROR_INVALID_PARAMETER;
  3651. }
  3652. else
  3653. {
  3654. CRegLock lock;
  3655. lRet = VRegistry.SetValueA(hKey, lpSubKey, dwType, lpData, cbData);
  3656. }
  3657. return lRet;
  3658. }
  3659. /*++
  3660. Pass through to virtual registry to handle call.
  3661. --*/
  3662. LONG
  3663. APIHOOK(RegSetValueExW)(
  3664. HKEY hKey,
  3665. LPCWSTR lpSubKey,
  3666. DWORD /* Reserved */,
  3667. DWORD dwType,
  3668. CONST BYTE * lpData,
  3669. DWORD cbData
  3670. )
  3671. {
  3672. LONG lRet = 0;
  3673. if (!lpData && cbData)
  3674. {
  3675. lRet = ERROR_INVALID_PARAMETER;
  3676. }
  3677. else
  3678. {
  3679. CRegLock lock;
  3680. lRet = VRegistry.SetValueW(hKey, lpSubKey, dwType, lpData, cbData);
  3681. }
  3682. return lRet;
  3683. }
  3684. /*++
  3685. Pass through to virtual registry to handle call.
  3686. --*/
  3687. LONG
  3688. APIHOOK(RegDeleteKeyA)(
  3689. HKEY hKey,
  3690. LPCSTR lpSubKey
  3691. )
  3692. {
  3693. CRegLock Lock;
  3694. return VRegistry.DeleteKeyA(hKey, lpSubKey);
  3695. }
  3696. /*++
  3697. Pass through to virtual registry to handle call.
  3698. --*/
  3699. LONG
  3700. APIHOOK(RegDeleteKeyW)(
  3701. HKEY hKey,
  3702. LPCWSTR lpSubKey
  3703. )
  3704. {
  3705. CRegLock Lock;
  3706. return VRegistry.DeleteKeyW(hKey, lpSubKey);
  3707. }
  3708. LONG
  3709. APIHOOK(RegConnectRegistryW)(
  3710. LPCWSTR lpMachineName,
  3711. HKEY hKey,
  3712. PHKEY phkResult
  3713. )
  3714. {
  3715. CRegLock Lock;
  3716. return VRegistry.OpenKeyW(
  3717. hKey,
  3718. NULL,
  3719. 0,
  3720. 0,
  3721. MAXIMUM_ALLOWED,
  3722. NULL,
  3723. phkResult,
  3724. 0,
  3725. FALSE,
  3726. TRUE,
  3727. lpMachineName);
  3728. }
  3729. LONG
  3730. APIHOOK(RegConnectRegistryA)(
  3731. LPCSTR lpMachineName,
  3732. HKEY hKey,
  3733. PHKEY phkResult
  3734. )
  3735. {
  3736. WCHAR wMachineName[MAX_COMPUTERNAME_LENGTH + 1] = L"";
  3737. if (lpMachineName)
  3738. {
  3739. if (MultiByteToWideChar(
  3740. CP_ACP,
  3741. 0,
  3742. lpMachineName,
  3743. -1,
  3744. wMachineName,
  3745. MAX_COMPUTERNAME_LENGTH + 1) == 0)
  3746. {
  3747. return ERROR_INVALID_PARAMETER;
  3748. }
  3749. }
  3750. return APIHOOK(RegConnectRegistryW)(wMachineName, hKey, phkResult);
  3751. }
  3752. /*++
  3753. Parse the command line for fixes:
  3754. FIXA(param); FIXB(param); FIXC(param) ...
  3755. param is optional, and can be omitted (along with parenthesis's)
  3756. --*/
  3757. BOOL
  3758. ParseCommandLineA(
  3759. LPCSTR lpCommandLine
  3760. )
  3761. {
  3762. const char szDefault[] = "Win9x";
  3763. // Add all the defaults if no command line is specified
  3764. if (!lpCommandLine || (lpCommandLine[0] == '\0'))
  3765. {
  3766. // Default to win9x API emulation
  3767. g_bWin9x = TRUE;
  3768. lpCommandLine = szDefault;
  3769. }
  3770. CSTRING_TRY
  3771. {
  3772. CStringToken csCommandLine(lpCommandLine, " ,\t;");
  3773. CString csTok;
  3774. int nLeftParam, nRightParam;
  3775. CString csParam;
  3776. VENTRY *ventry;
  3777. //
  3778. // Run the string, looking for fix names
  3779. //
  3780. DPFN( eDbgLevelInfo, "----------------------------------");
  3781. DPFN( eDbgLevelInfo, " Virtual registry ");
  3782. DPFN( eDbgLevelInfo, "----------------------------------");
  3783. DPFN( eDbgLevelInfo, "Adding command line:");
  3784. while (csCommandLine.GetToken(csTok))
  3785. {
  3786. PURPOSE ePurpose;
  3787. // Get the parameter
  3788. nLeftParam = csTok.Find(L'(');
  3789. nRightParam = csTok.Find(L')');
  3790. if (nLeftParam != -1 &&
  3791. nRightParam != -1)
  3792. {
  3793. if ( (nLeftParam + 1) < (nRightParam - 1))
  3794. {
  3795. csParam = csTok.Mid(nLeftParam+1, nRightParam-nLeftParam-1);
  3796. }
  3797. // Strip off the () from the token.
  3798. csTok.Truncate(nLeftParam);
  3799. }
  3800. else
  3801. {
  3802. csParam = L"";
  3803. }
  3804. if (csTok.CompareNoCase(L"Win9x") == 0)
  3805. {
  3806. // Turn on all win9x fixes
  3807. ePurpose = eWin9x;
  3808. g_bWin9x = TRUE;
  3809. }
  3810. else if (csTok.CompareNoCase(L"WinNT") == 0)
  3811. {
  3812. // Turn on all NT fixes
  3813. ePurpose = eWinNT;
  3814. g_bWin9x = FALSE;
  3815. }
  3816. else if (csTok.CompareNoCase(L"Win2K") == 0)
  3817. {
  3818. // Turn on all Win2K fixes
  3819. ePurpose = eWin2K;
  3820. g_bWin9x = FALSE;
  3821. }
  3822. else if (csTok.CompareNoCase(L"WinXP") == 0)
  3823. {
  3824. // Turn on all Win2K fixes
  3825. ePurpose = eWinXP;
  3826. g_bWin9x = FALSE;
  3827. }
  3828. else
  3829. {
  3830. // A custom fix
  3831. ePurpose = eCustom;
  3832. }
  3833. // Find the specified fix and run it's function
  3834. ventry = g_pVList;
  3835. while (ventry && (ventry->cName[0]))
  3836. {
  3837. if (((ePurpose != eCustom) && (ventry->ePurpose == ePurpose)) ||
  3838. ((ePurpose == eCustom) && (csTok.CompareNoCase(ventry->cName) == 0)))
  3839. {
  3840. if (ventry->bShouldCall == FALSE)
  3841. {
  3842. ventry->szParam = (char*) malloc(csParam.GetLength() + 1);
  3843. if (ventry->szParam)
  3844. {
  3845. if (SUCCEEDED(StringCchCopyA(ventry->szParam, csParam.GetLength() + 1, csParam.GetAnsi())))
  3846. {
  3847. ventry->bShouldCall = TRUE;
  3848. }
  3849. else
  3850. {
  3851. free(ventry->szParam);
  3852. ventry->szParam = NULL;
  3853. return FALSE;
  3854. }
  3855. }
  3856. else
  3857. {
  3858. return FALSE;
  3859. }
  3860. }
  3861. }
  3862. ventry++;
  3863. }
  3864. }
  3865. DPFN( eDbgLevelInfo, "----------------------------------");
  3866. }
  3867. CSTRING_CATCH
  3868. {
  3869. DPFN(eDbgLevelError, szOutOfMemory);
  3870. return FALSE;
  3871. }
  3872. return TRUE;
  3873. }
  3874. /*++
  3875. Initialize all the registry hooks
  3876. --*/
  3877. BOOL
  3878. NOTIFY_FUNCTION(
  3879. DWORD fdwReason
  3880. )
  3881. {
  3882. if (fdwReason == DLL_PROCESS_ATTACH)
  3883. {
  3884. if (InitializeCriticalSectionAndSpinCount(&csRegCriticalSection, 0x80000000) == FALSE ||
  3885. VRegistry.Init() == FALSE ||
  3886. ParseCommandLineA(COMMAND_LINE) == FALSE)
  3887. {
  3888. DPFN(eDbgLevelError, szOutOfMemory);
  3889. return FALSE;
  3890. }
  3891. }
  3892. // Ignore cleanup because some apps call registry functions during process detach.
  3893. /*
  3894. if (fdwReason == DLL_PROCESS_DETACH)
  3895. {
  3896. if (g_bInitialized)
  3897. {
  3898. VRegistry.Free();
  3899. DeleteCriticalSection(&csRegCriticalSection);
  3900. }
  3901. DeleteCriticalSection(&csRegTestCriticalSection);
  3902. return;
  3903. }
  3904. */
  3905. return TRUE;
  3906. }
  3907. HOOK_BEGIN
  3908. CALL_NOTIFY_FUNCTION
  3909. APIHOOK_ENTRY(ADVAPI32.DLL, RegConnectRegistryA);
  3910. APIHOOK_ENTRY(ADVAPI32.DLL, RegConnectRegistryW);
  3911. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA);
  3912. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExW);
  3913. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExA);
  3914. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExW);
  3915. APIHOOK_ENTRY(ADVAPI32.DLL, RegCloseKey);
  3916. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA);
  3917. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyW);
  3918. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueA);
  3919. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueW);
  3920. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyA);
  3921. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyW);
  3922. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExA);
  3923. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExW);
  3924. APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumValueA);
  3925. APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumValueW);
  3926. APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyA);
  3927. APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyW);
  3928. APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyExA);
  3929. APIHOOK_ENTRY(ADVAPI32.DLL, RegEnumKeyExW);
  3930. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryInfoKeyA);
  3931. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryInfoKeyW);
  3932. APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueExA);
  3933. APIHOOK_ENTRY(ADVAPI32.DLL, RegSetValueExW);
  3934. APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteKeyA);
  3935. APIHOOK_ENTRY(ADVAPI32.DLL, RegDeleteKeyW);
  3936. HOOK_END
  3937. IMPLEMENT_SHIM_END