Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

671 lines
19 KiB

  1. #include "stdinc.h"
  2. #include "detours.h"
  3. #include "user32detours.h"
  4. #define NUMBER_OF(x) (sizeof(x)/sizeof(*x))
  5. namespace User32Trampolines
  6. {
  7. bool fInitialized = false;
  8. CSimpleMap<CString, bool> m_ItemMap;
  9. HKEY g_hkLocalMachine = NULL;
  10. HKEY g_hkClasses = NULL;
  11. HKEY g_hkCurrentUser = NULL;
  12. HKEY g_hkRedirectionRoot = NULL;
  13. HKEY g_hkUsers = NULL;
  14. GUID g_uuidRedirection;
  15. HKEY RemapRegKey(HKEY);
  16. extern "C" {
  17. DETOUR_TRAMPOLINE(
  18. ATOM WINAPI Real_RegisterClassW(CONST WNDCLASSW *lpWndClass),
  19. RegisterClassW);
  20. DETOUR_TRAMPOLINE(
  21. ATOM WINAPI Real_RegisterClassA(CONST WNDCLASSA *lpWndClass),
  22. RegisterClassA);
  23. DETOUR_TRAMPOLINE(
  24. ATOM WINAPI Real_RegisterClassExW(CONST WNDCLASSEXW *),
  25. RegisterClassExW);
  26. DETOUR_TRAMPOLINE(
  27. ATOM WINAPI Real_RegisterClassExA(CONST WNDCLASSEXA *),
  28. RegisterClassExA);
  29. DETOUR_TRAMPOLINE(
  30. LONG APIENTRY Real_RegOpenKeyW ( IN HKEY hKey, IN LPCWSTR lpSubKey, OUT PHKEY phkResult ),
  31. RegOpenKeyW);
  32. DETOUR_TRAMPOLINE(
  33. LONG APIENTRY Real_RegOpenKeyA ( IN HKEY hKey, IN LPCSTR lpSubKey, OUT PHKEY phkResult ),
  34. RegOpenKeyA);
  35. DETOUR_TRAMPOLINE(
  36. LONG APIENTRY Real_RegOpenKeyExW ( IN HKEY hKey, IN LPCWSTR lpSubKey, DWORD, REGSAM, PHKEY),
  37. RegOpenKeyExW);
  38. DETOUR_TRAMPOLINE(
  39. LONG APIENTRY Real_RegOpenKeyExA ( IN HKEY hKey, IN LPCSTR lpSubKey, DWORD, REGSAM, PHKEY),
  40. RegOpenKeyExA);
  41. DETOUR_TRAMPOLINE(
  42. LONG APIENTRY Real_RegSetValueExA (HKEY,LPCSTR,DWORD,DWORD,CONST BYTE*,DWORD),
  43. RegSetValueExA);
  44. DETOUR_TRAMPOLINE(
  45. LONG APIENTRY Real_RegSetValueExW (HKEY,LPCWSTR,DWORD,DWORD,CONST BYTE*,DWORD),
  46. RegSetValueExW);
  47. DETOUR_TRAMPOLINE(
  48. LONG APIENTRY Real_RegSetValueW(HKEY,LPCWSTR,DWORD,LPCWSTR,DWORD),
  49. RegSetValueW);
  50. DETOUR_TRAMPOLINE(
  51. LONG APIENTRY Real_RegSetValueA(HKEY,LPCSTR,DWORD,LPCSTR,DWORD),
  52. RegSetValueA);
  53. DETOUR_TRAMPOLINE(
  54. LONG APIENTRY Real_RegQueryValueExA(HKEY,LPCSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD),
  55. RegQueryValueExA);
  56. DETOUR_TRAMPOLINE(
  57. LONG APIENTRY Real_RegQueryValueExW(HKEY,LPCWSTR,LPDWORD,LPDWORD,LPBYTE,LPDWORD),
  58. RegQueryValueExW);
  59. DETOUR_TRAMPOLINE(
  60. LONG APIENTRY Real_RegQueryValueA(HKEY,LPCSTR,LPSTR,PLONG),
  61. RegQueryValueA);
  62. DETOUR_TRAMPOLINE(
  63. LONG APIENTRY Real_RegQueryValueW(HKEY,LPCWSTR,LPWSTR,PLONG),
  64. RegQueryValueW);
  65. DETOUR_TRAMPOLINE(
  66. LONG APIENTRY Real_RegCreateKeyW(HKEY, PWSTR, PHKEY),
  67. RegCreateKeyW);
  68. DETOUR_TRAMPOLINE(
  69. LONG APIENTRY Real_RegCreateKeyA(HKEY, PSTR, PHKEY),
  70. RegCreateKeyA);
  71. DETOUR_TRAMPOLINE(
  72. LONG APIENTRY Real_RegCreateKeyExW(HKEY, PCWSTR, DWORD, PCWSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, PDWORD),
  73. RegCreateKeyExW);
  74. DETOUR_TRAMPOLINE(
  75. LONG APIENTRY Real_RegCreateKeyExA(HKEY, PCSTR, DWORD, PCSTR, DWORD, REGSAM, LPSECURITY_ATTRIBUTES, PHKEY, PDWORD),
  76. RegCreateKeyExA);
  77. }
  78. };
  79. //
  80. // Remap from a well-known registry value to our internal ones.
  81. //
  82. HKEY
  83. User32Trampolines::RemapRegKey(HKEY hKey)
  84. {
  85. if (hKey == HKEY_CLASSES_ROOT) return User32Trampolines::g_hkClasses;
  86. else if (hKey == HKEY_CURRENT_USER) return User32Trampolines::g_hkCurrentUser;
  87. else if (hKey == HKEY_LOCAL_MACHINE) return User32Trampolines::g_hkLocalMachine;
  88. else if (hKey == HKEY_USERS) return User32Trampolines::g_hkUsers;
  89. else return hKey;
  90. }
  91. LONG APIENTRY
  92. User32Trampolines::InternalRegSetValueA (
  93. IN HKEY hKey,
  94. IN PCSTR lpSubKey,
  95. IN DWORD dwType,
  96. IN PCSTR lpData,
  97. IN DWORD cbData
  98. )
  99. {
  100. hKey = User32Trampolines::RemapRegKey(hKey);
  101. return Real_RegSetValueA(hKey, lpSubKey, dwType, lpData, cbData);
  102. }
  103. LONG APIENTRY
  104. User32Trampolines::InternalRegSetValueW (
  105. IN HKEY hKey,
  106. IN PCWSTR lpSubKey,
  107. IN DWORD dwType,
  108. IN PCWSTR lpData,
  109. IN DWORD cbData
  110. )
  111. {
  112. hKey = User32Trampolines::RemapRegKey(hKey);
  113. return Real_RegSetValueW(hKey, lpSubKey, dwType, lpData, cbData);
  114. }
  115. LONG
  116. APIENTRY
  117. User32Trampolines::InternalRegSetValueExA (
  118. IN HKEY hKey,
  119. IN LPCSTR lpValueName,
  120. IN DWORD Reserved,
  121. IN DWORD dwType,
  122. IN CONST BYTE* lpData,
  123. IN DWORD cbData
  124. )
  125. {
  126. //
  127. // Always translate on a set.
  128. //
  129. hKey = User32Trampolines::RemapRegKey(hKey);
  130. return Real_RegSetValueExA(hKey, lpValueName, Reserved, dwType, lpData, cbData);
  131. }
  132. LONG
  133. APIENTRY
  134. User32Trampolines::InternalRegSetValueExW (
  135. IN HKEY hKey,
  136. IN LPCWSTR lpValueName,
  137. IN DWORD Reserved,
  138. IN DWORD dwType,
  139. IN CONST BYTE* lpData,
  140. IN DWORD cbData
  141. )
  142. {
  143. hKey = User32Trampolines::RemapRegKey(hKey);
  144. return Real_RegSetValueExW(hKey, lpValueName, Reserved, dwType, lpData, cbData);
  145. }
  146. LONG APIENTRY User32Trampolines::InternalRegOpenKeyA (
  147. IN HKEY hKey,
  148. IN LPCSTR lpSubKey,
  149. OUT PHKEY phkResult
  150. )
  151. {
  152. //
  153. // Opening a key remaps the hKey to our set of values if possible first. If that
  154. // fails, then try the unremapped version to read from the 'real' registry.
  155. //
  156. ULONG ulResult;
  157. ulResult = Real_RegOpenKeyA(RemapRegKey(hKey), lpSubKey, phkResult);
  158. if (ulResult != 0)
  159. {
  160. ulResult = Real_RegOpenKeyA(hKey, lpSubKey, phkResult);
  161. }
  162. return ulResult;
  163. }
  164. LONG APIENTRY User32Trampolines::InternalRegOpenKeyW (
  165. IN HKEY hKey,
  166. IN LPCWSTR lpSubKey,
  167. OUT PHKEY phkResult
  168. )
  169. {
  170. //
  171. // Opening a key remaps the hKey to our set of values if possible first. If that
  172. // fails, then try the unremapped version to read from the 'real' registry.
  173. //
  174. ULONG ulResult;
  175. ulResult = Real_RegOpenKeyW(RemapRegKey(hKey), lpSubKey, phkResult);
  176. if (ulResult != 0)
  177. {
  178. ulResult = Real_RegOpenKeyW(hKey, lpSubKey, phkResult);
  179. }
  180. return ulResult;
  181. }
  182. LONG APIENTRY User32Trampolines::InternalRegCreateKeyA(HKEY hk, PSTR ps, PHKEY phk)
  183. {
  184. return Real_RegCreateKeyA(RemapRegKey(hk), ps, phk);
  185. }
  186. LONG APIENTRY User32Trampolines::InternalRegCreateKeyExA(HKEY a, PCSTR b, DWORD c, PCSTR d, DWORD e, REGSAM f, LPSECURITY_ATTRIBUTES g, PHKEY h, PDWORD i)
  187. {
  188. return Real_RegCreateKeyExA(RemapRegKey(a), b, c, d, e, f, g, h, i);
  189. }
  190. LONG APIENTRY User32Trampolines::InternalRegCreateKeyW(HKEY hk, PWSTR ps, PHKEY phk)
  191. {
  192. return Real_RegCreateKeyW(RemapRegKey(hk), ps, phk);
  193. }
  194. LONG APIENTRY User32Trampolines::InternalRegCreateKeyExW(HKEY a, PCWSTR b, DWORD c, PCWSTR d, DWORD e, REGSAM f, LPSECURITY_ATTRIBUTES g, PHKEY h, PDWORD i)
  195. {
  196. return Real_RegCreateKeyExW(RemapRegKey(a), b, c, d, e, f, g, h, i);
  197. }
  198. LONG APIENTRY User32Trampolines::InternalRegOpenKeyExA (
  199. IN HKEY hKey,
  200. IN LPCSTR lpSubKey,
  201. IN DWORD ulOptions,
  202. IN REGSAM samDesired,
  203. OUT PHKEY phkResult
  204. )
  205. {
  206. //
  207. // Opening a key remaps the hKey to our set of values if possible first. If that
  208. // fails, then try the unremapped version to read from the 'real' registry.
  209. //
  210. ULONG ulResult;
  211. ulResult = Real_RegOpenKeyExA(RemapRegKey(hKey), lpSubKey, ulOptions, samDesired, phkResult);
  212. if (ulResult != 0)
  213. {
  214. ulResult = Real_RegOpenKeyExA(hKey, lpSubKey, ulOptions, samDesired, phkResult);
  215. }
  216. return ulResult;
  217. }
  218. LONG APIENTRY User32Trampolines::InternalRegOpenKeyExW (
  219. IN HKEY hKey,
  220. IN LPCWSTR lpSubKey,
  221. IN DWORD ulOptions,
  222. IN REGSAM samDesired,
  223. OUT PHKEY phkResult
  224. )
  225. {
  226. //
  227. // Opening a key remaps the hKey to our set of values if possible first. If that
  228. // fails, then try the unremapped version to read from the 'real' registry.
  229. //
  230. ULONG ulResult;
  231. ulResult = Real_RegOpenKeyExW(RemapRegKey(hKey), lpSubKey, ulOptions, samDesired, phkResult);
  232. if (ulResult != 0)
  233. {
  234. ulResult = Real_RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
  235. }
  236. return ulResult;
  237. }
  238. LONG APIENTRY User32Trampolines::InternalRegQueryValueA(
  239. HKEY hKey,
  240. LPCSTR lpSubKey,
  241. LPSTR lpValue,
  242. PLONG pcbData)
  243. {
  244. ULONG ulResult;
  245. ulResult = Real_RegQueryValueA(RemapRegKey(hKey), lpSubKey, lpValue, pcbData);
  246. if (ulResult != 0)
  247. {
  248. ulResult = Real_RegQueryValueA(hKey, lpSubKey, lpValue, pcbData);
  249. }
  250. return ulResult;
  251. }
  252. LONG APIENTRY User32Trampolines::InternalRegQueryValueW(
  253. HKEY hKey,
  254. LPCWSTR lpSubKey,
  255. LPWSTR lpValue,
  256. PLONG pcbData)
  257. {
  258. ULONG ulResult;
  259. ulResult = Real_RegQueryValueW(RemapRegKey(hKey), lpSubKey, lpValue, pcbData);
  260. if (ulResult != 0)
  261. {
  262. ulResult = Real_RegQueryValueW(hKey, lpSubKey, lpValue, pcbData);
  263. }
  264. return ulResult;
  265. }
  266. LONG APIENTRY User32Trampolines::InternalRegQueryValueExA(
  267. HKEY hKey,
  268. LPCSTR lpValueName,
  269. LPDWORD lpReserved,
  270. LPDWORD lpType,
  271. LPBYTE lpData,
  272. LPDWORD pdwData
  273. )
  274. {
  275. ULONG ulResult;
  276. ulResult = Real_RegQueryValueExA(RemapRegKey(hKey), lpValueName, lpReserved, lpType, lpData, pdwData);
  277. if (ulResult != 0)
  278. {
  279. ulResult = Real_RegQueryValueExA(hKey, lpValueName, lpReserved, lpType, lpData, pdwData);
  280. }
  281. return ulResult;
  282. }
  283. LONG APIENTRY User32Trampolines::InternalRegQueryValueExW(
  284. HKEY hKey,
  285. LPCWSTR lpValueName,
  286. LPDWORD lpReserved,
  287. LPDWORD lpType,
  288. LPBYTE lpData,
  289. LPDWORD pdwData
  290. )
  291. {
  292. ULONG ulResult;
  293. ulResult = Real_RegQueryValueExW(RemapRegKey(hKey), lpValueName, lpReserved, lpType, lpData, pdwData);
  294. if (ulResult != 0)
  295. {
  296. ulResult = Real_RegQueryValueExW(hKey, lpValueName, lpReserved, lpType, lpData, pdwData);
  297. }
  298. return ulResult;
  299. }
  300. BOOL
  301. User32Trampolines::GetRedirectedStrings(CSimpleList<CString>& Strings)
  302. {
  303. CSimpleList<CString> FoundStrings;
  304. m_ItemMap.GetKeys(FoundStrings);
  305. for ( SIZE_T sz = 0; sz < FoundStrings.Size(); sz++ )
  306. {
  307. SIZE_T c = 0;
  308. for ( c = 0; c < Strings.Size(); c++ )
  309. {
  310. if ( lstrcmpiW(Strings[c], FoundStrings[sz]) == 0 )
  311. break;
  312. }
  313. //
  314. // Not found?
  315. //
  316. if ( c == Strings.Size() )
  317. Strings.Append(FoundStrings[sz]);
  318. }
  319. return TRUE;
  320. }
  321. void
  322. User32Trampolines::ClearRedirections()
  323. {
  324. m_ItemMap.Clear();
  325. }
  326. BOOL
  327. User32Trampolines::Initialize()
  328. {
  329. if ( fInitialized )
  330. return TRUE;
  331. fInitialized = TRUE;
  332. //
  333. // Set up registry redirection before actually doing redirection. Generate
  334. // a virtual-root that all calls will be rerouted to first. Do this by
  335. // generating a GUIDized path off of HKCU.
  336. //
  337. LPOLESTR pstrGuid;
  338. WCHAR wchRegPath[MAX_PATH];
  339. ULONG ulResult;
  340. HKEY hkDump;
  341. if (FAILED(CoCreateGuid(&g_uuidRedirection)))
  342. return FALSE;
  343. StringFromCLSID(g_uuidRedirection, &pstrGuid);
  344. _snwprintf(wchRegPath, MAX_PATH, L"ManBuilderRedirect\\%ls", pstrGuid);
  345. //
  346. // Create root key. For purposes of argument, we'll allow all access to all
  347. // subchildren, no matter what. If we were a real app, we'd take into account
  348. // propagating security down the heirarchy, but for now, we don't really care.
  349. //
  350. ulResult = ::RegCreateKeyExW(
  351. HKEY_CURRENT_USER,
  352. wchRegPath,
  353. 0,
  354. NULL,
  355. 0,
  356. KEY_ALL_ACCESS,
  357. NULL,
  358. &User32Trampolines::g_hkRedirectionRoot,
  359. NULL);
  360. if (ulResult != 0) return FALSE;
  361. //
  362. // Generate all the pseudo-roots for the various keys
  363. //
  364. struct {
  365. HKEY* phkTarget;
  366. PCWSTR pcwszKeyName;
  367. } s_KeyRedirections[] = {
  368. { &User32Trampolines::g_hkClasses, L"HKEY_CLASSES_ROOT" },
  369. { &User32Trampolines::g_hkCurrentUser, L"HKEY_CURRENT_USER" },
  370. { &User32Trampolines::g_hkLocalMachine, L"HKEY_LOCAL_MACHINE" },
  371. { &User32Trampolines::g_hkUsers, L"HKEY_USERS" }
  372. };
  373. for (ULONG ul = 0; ul < NUMBER_OF(s_KeyRedirections); ul++)
  374. {
  375. ulResult = RegCreateKeyExW(
  376. g_hkRedirectionRoot,
  377. s_KeyRedirections[ul].pcwszKeyName,
  378. 0,
  379. NULL,
  380. 0,
  381. KEY_ALL_ACCESS,
  382. NULL,
  383. s_KeyRedirections[ul].phkTarget,
  384. NULL);
  385. if (ulResult != 0) return FALSE;
  386. }
  387. //
  388. // Let's also create (but close) the following 'special' keys for COM:
  389. // - CLSID
  390. // - Interface
  391. //
  392. ulResult = RegCreateKeyExW(User32Trampolines::g_hkClasses, L"CLSID", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkDump, NULL);
  393. if (ulResult != 0)
  394. RegCloseKey(hkDump);
  395. ulResult = RegCreateKeyExW(User32Trampolines::g_hkClasses, L"Interface", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkDump, NULL);
  396. if (ulResult != 0)
  397. RegCloseKey(hkDump);
  398. ulResult = RegCreateKeyExW(User32Trampolines::g_hkClasses, L"TypeLib", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkDump, NULL);
  399. if (ulResult != 0)
  400. RegCloseKey(hkDump);
  401. #define MAP(f) { (PBYTE)Real_##f, (PBYTE)Internal##f }
  402. PBYTE Remapping[][2] = {
  403. MAP(RegisterClassW),
  404. MAP(RegisterClassExW),
  405. MAP(RegisterClassA),
  406. MAP(RegisterClassExA),
  407. MAP(RegOpenKeyW),
  408. MAP(RegOpenKeyA),
  409. MAP(RegOpenKeyExW),
  410. MAP(RegOpenKeyExA),
  411. MAP(RegSetValueExA),
  412. MAP(RegSetValueExW),
  413. MAP(RegSetValueA),
  414. MAP(RegSetValueW),
  415. MAP(RegQueryValueExA),
  416. MAP(RegQueryValueExW),
  417. MAP(RegQueryValueW),
  418. MAP(RegQueryValueA),
  419. MAP(RegCreateKeyA),
  420. MAP(RegCreateKeyW),
  421. MAP(RegCreateKeyExA),
  422. MAP(RegCreateKeyExW)
  423. };
  424. //
  425. // All redirections
  426. //
  427. for (int i = 0; i < NUMBER_OF(Remapping); i++)
  428. {
  429. DetourFunctionWithTrampoline(Remapping[i][0], Remapping[i][1]);
  430. }
  431. return TRUE;
  432. }
  433. ATOM WINAPI
  434. User32Trampolines::InternalRegisterClassA(CONST WNDCLASSA * lpWndClass)
  435. {
  436. m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
  437. return Real_RegisterClassA(lpWndClass);
  438. }
  439. ATOM WINAPI
  440. User32Trampolines::InternalRegisterClassW(CONST WNDCLASSW * lpWndClass)
  441. {
  442. m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
  443. return Real_RegisterClassW(lpWndClass);
  444. }
  445. ATOM WINAPI
  446. User32Trampolines::InternalRegisterClassExA(CONST WNDCLASSEXA * lpWndClass)
  447. {
  448. m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
  449. return Real_RegisterClassExA(lpWndClass);
  450. }
  451. ATOM WINAPI
  452. User32Trampolines::InternalRegisterClassExW(CONST WNDCLASSEXW * lpWndClass)
  453. {
  454. m_ItemMap[CString(lpWndClass->lpszClassName)] = true;
  455. return Real_RegisterClassExW(lpWndClass);
  456. }
  457. namespace User32Trampolines {
  458. void RegDestroyKeyTree(HKEY hk, PWSTR pwszBuffer)
  459. {
  460. bool fCreatedBuffer = false;
  461. PWSTR strKeyName;
  462. if (pwszBuffer == NULL)
  463. {
  464. fCreatedBuffer = true;
  465. pwszBuffer = new WCHAR[MAX_PATH];
  466. }
  467. pwszBuffer[0] = UNICODE_NULL;
  468. while (1)
  469. {
  470. HKEY hkSub;
  471. if (ERROR_SUCCESS == RegEnumKeyW(hk, 0, pwszBuffer, MAX_PATH))
  472. {
  473. if ((strKeyName = new WCHAR[lstrlenW(pwszBuffer) + 1]) == NULL)
  474. break;
  475. lstrcpyW(strKeyName, pwszBuffer);
  476. if (ERROR_SUCCESS == RegOpenKeyW(hk, pwszBuffer, &hkSub))
  477. {
  478. RegDestroyKeyTree(hkSub, pwszBuffer);
  479. }
  480. RegDeleteKeyW(hk, strKeyName);
  481. delete[] strKeyName;
  482. }
  483. else
  484. {
  485. break;
  486. }
  487. }
  488. if (fCreatedBuffer && pwszBuffer)
  489. {
  490. delete [] pwszBuffer;
  491. pwszBuffer = NULL;
  492. fCreatedBuffer = false;
  493. }
  494. }
  495. BOOL Stop()
  496. {
  497. PHKEY hkToClose[] = {
  498. &g_hkClasses,
  499. &g_hkLocalMachine,
  500. &g_hkUsers,
  501. &g_hkCurrentUser,
  502. };
  503. PBYTE Remapping[][2] = {
  504. MAP(RegisterClassW),
  505. MAP(RegisterClassExW),
  506. MAP(RegisterClassA),
  507. MAP(RegisterClassExA),
  508. MAP(RegOpenKeyW),
  509. MAP(RegOpenKeyA),
  510. MAP(RegOpenKeyExW),
  511. MAP(RegOpenKeyExA),
  512. MAP(RegSetValueExA),
  513. MAP(RegSetValueExW),
  514. MAP(RegSetValueA),
  515. MAP(RegSetValueW),
  516. MAP(RegQueryValueExA),
  517. MAP(RegQueryValueExW),
  518. MAP(RegQueryValueW),
  519. MAP(RegQueryValueA),
  520. MAP(RegCreateKeyA),
  521. MAP(RegCreateKeyW),
  522. MAP(RegCreateKeyExA),
  523. MAP(RegCreateKeyExW)
  524. };
  525. int i;
  526. //
  527. // Close open keys
  528. //
  529. for (i = 0; i < NUMBER_OF(hkToClose); i++)
  530. {
  531. if (*hkToClose[i] != NULL)
  532. {
  533. RegCloseKey(*hkToClose[i]);
  534. *hkToClose[i] = NULL;
  535. }
  536. }
  537. //
  538. // Undo detours
  539. //
  540. for (int i = 0; i < NUMBER_OF(Remapping); i++)
  541. {
  542. DetourRemove(Remapping[i][0], Remapping[i][1]);
  543. }
  544. LPOLESTR psz;
  545. WCHAR wchKeyNameBuffer[MAX_PATH];
  546. if (SUCCEEDED(StringFromCLSID(User32Trampolines::g_uuidRedirection, &psz)))
  547. {
  548. _snwprintf(wchKeyNameBuffer, MAX_PATH, L"ManBuilderRedirect\\%ls", psz);
  549. // Destroy the tree pointed at
  550. RegDestroyKeyTree(User32Trampolines::g_hkRedirectionRoot, NULL);
  551. // Close our handle
  552. RegCloseKey(User32Trampolines::g_hkRedirectionRoot);
  553. // And try to delete the key
  554. RegDeleteKeyW(HKEY_CURRENT_USER, wchKeyNameBuffer);
  555. // And maybe delete the parent key
  556. RegDeleteKeyW(HKEY_CURRENT_USER, L"ManBuilderRedirect");
  557. // Free guid string memory, too
  558. CoTaskMemFree(psz);
  559. }
  560. return TRUE;
  561. }
  562. }