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.

738 lines
23 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. PopulateDefaultHKCUSettings.cpp
  5. Abstract:
  6. Populate HKCU with default values if they do not exist. Some apps installs HKCU values
  7. for only the user that ran setup on that app. In this case, if another users tries to use the
  8. application they will be unable to due to missing HKCU regkeys.
  9. To shim around this, we check for the existance of a regkey and if it does not exist, we then read
  10. a pre-defined .reg file our of our resource section and exec regedit on it to add the necessary
  11. registry keys. For example:
  12. COMMAND_LINE("Software\Lotus\SmartCenter\97.0!SmartCenter97")
  13. would mean that if the regkey 'HKCU\Software\Lotus\SmartCenter\97.0' does NOT exist, then we should
  14. read the named resource 'SmartCenter97' out of our dll and write it to a temp .reg file and then
  15. execute 'regedit.exe /s tempfile.reg' to properly populate the registry with the defaul HKCU values.
  16. Notes:
  17. This is an general shim. (Actually, its a Admiral shim, since its in the navy, hehe).
  18. History:
  19. 01/31/2001 reiner Created
  20. 03/30/2001 amarp Added %__AppSystemDir_% and %__AppLocalOrCDDir<Param1><Param2><Param3>_%
  21. (documented below)
  22. --*/
  23. #include "precomp.h"
  24. #include "stdio.h"
  25. // This module has been given an official blessing to use the str routines.
  26. #include "LegalStr.h"
  27. IMPLEMENT_SHIM_BEGIN(PopulateDefaultHKCUSettings)
  28. #include "ShimHookMacro.h"
  29. APIHOOK_ENUM_BEGIN
  30. APIHOOK_ENUM_ENTRY(RegOpenKeyA)
  31. APIHOOK_ENUM_ENTRY(RegOpenKeyW)
  32. APIHOOK_ENUM_ENTRY(RegOpenKeyExA)
  33. APIHOOK_ENUM_ENTRY(RegOpenKeyExW)
  34. APIHOOK_ENUM_END
  35. BOOL ParseCommandLine(const char* pszCmdLine, char* pszRegKeyName, DWORD cchRegKeyName, char* pszResourceName, DWORD cchResourceName)
  36. {
  37. BOOL bRet = FALSE;
  38. char* psz;
  39. psz = strstr(pszCmdLine, "!");
  40. if (psz)
  41. {
  42. DWORD cchKey;
  43. DWORD cchResource;
  44. cchKey = (DWORD)(((BYTE*)psz - (BYTE*)pszCmdLine) / sizeof(char));
  45. // move past the '!' so psz now points to the resource name
  46. psz++;
  47. cchResource = lstrlenA(psz);
  48. if ((cchRegKeyName >= (cchKey + 1)) &&
  49. (cchResourceName >= (cchResource + 1)))
  50. {
  51. // we have enough space in the output buffers to fit the strings
  52. lstrcpynA(pszRegKeyName, pszCmdLine, cchKey + 1);
  53. lstrcpynA(pszResourceName, psz, cchResourceName);
  54. bRet = TRUE;
  55. }
  56. }
  57. return bRet;
  58. }
  59. //
  60. // This actually creates the tempfile (0 bytes) and returns
  61. // the filename.
  62. //
  63. BOOL CreateTempName(char* szFileName)
  64. {
  65. char szTempPath[MAX_PATH];
  66. BOOL bRet = FALSE;
  67. if (GetTempPathA(sizeof(szTempPath)/sizeof(szTempPath[0]), szTempPath))
  68. {
  69. if (GetTempFileNameA(szTempPath,
  70. "AcGenral",
  71. 0,
  72. szFileName))
  73. {
  74. bRet = TRUE;
  75. }
  76. }
  77. return bRet;
  78. }
  79. //
  80. // Exec's "regedit /s" with the given file
  81. //
  82. BOOL SpawnRegedit(char* szFile)
  83. {
  84. STARTUPINFOA si = {0};
  85. PROCESS_INFORMATION pi = {0};
  86. char szApp[MAX_PATH * 2];
  87. BOOL bRet = FALSE;
  88. sprintf(szApp, "regedit.exe /s %s", szFile);
  89. si.cb = sizeof(si);
  90. si.dwFlags = STARTF_USESHOWWINDOW;
  91. si.wShowWindow = SW_HIDE;
  92. bRet = CreateProcessA(NULL,
  93. szApp,
  94. NULL,
  95. NULL,
  96. FALSE,
  97. 0,
  98. NULL,
  99. NULL,
  100. &si,
  101. &pi);
  102. if (bRet)
  103. {
  104. WaitForSingleObject(pi.hProcess, INFINITE);
  105. CloseHandle(pi.hProcess);
  106. CloseHandle(pi.hThread);
  107. }
  108. return bRet;
  109. }
  110. //
  111. // this function is used to change a path from:
  112. //
  113. // "C:\Lotus\Smartsuite" -> "C:\\Lotus\\Smartsuite"
  114. //
  115. // (.reg files use escaped backslashes)
  116. //
  117. BOOL DoubleUpBackslashes(WCHAR* pwszPath, DWORD cchPath)
  118. {
  119. BOOL bRet = FALSE;
  120. WCHAR wszTemp[MAX_PATH * 2];
  121. WCHAR* pwsz = pwszPath;
  122. WCHAR* pwszTemp = wszTemp;
  123. while (*pwszTemp = *pwsz)
  124. {
  125. if (*pwsz == L'\\')
  126. {
  127. // if we found a '\' then add another one
  128. pwszTemp++;
  129. *pwszTemp = L'\\';
  130. }
  131. pwsz++;
  132. pwszTemp++;
  133. }
  134. if (cchPath >= (DWORD)(lstrlenW(wszTemp) + 1))
  135. {
  136. lstrcpynW(pwszPath, wszTemp, cchPath);
  137. bRet = TRUE;
  138. }
  139. return bRet;
  140. }
  141. //
  142. // This fuction calculates the application dir (pszAppDir) and the application
  143. // parent dir (pszAppParentDir) based on the return from GetModuleFileName
  144. //
  145. BOOL InitAppDir(WCHAR* pwszSystemDir, DWORD cchSystemDir,
  146. WCHAR* pwszAppDir, DWORD cchAppDir,
  147. WCHAR* pwszAppParentDir, DWORD cchAppParentDir
  148. )
  149. {
  150. BOOL bRet = FALSE;
  151. WCHAR wszExePath[MAX_PATH];
  152. bRet = GetSystemDirectoryW(pwszSystemDir,cchSystemDir);
  153. if( !bRet )
  154. return FALSE;
  155. bRet = DoubleUpBackslashes(pwszSystemDir,cchSystemDir);
  156. if( !bRet )
  157. return FALSE;
  158. if (GetModuleFileNameW(NULL, wszExePath, sizeof(wszExePath)/sizeof(wszExePath[0])))
  159. {
  160. // find the last '\' in the path
  161. WCHAR* pwsz = wcsrchr(wszExePath, L'\\');
  162. if (pwsz)
  163. {
  164. *pwsz = L'\0';
  165. if (cchAppDir >= (DWORD)(lstrlenW(wszExePath) + 1))
  166. {
  167. lstrcpynW(pwszAppDir, wszExePath, cchAppDir);
  168. bRet = DoubleUpBackslashes(pwszAppDir, cchAppDir);
  169. if (bRet)
  170. {
  171. pwsz = wcsrchr(wszExePath, L'\\');
  172. if (pwsz)
  173. {
  174. *pwsz = L'\0';
  175. if (cchAppParentDir >= (DWORD)(lstrlenW(wszExePath) + 1))
  176. {
  177. lstrcpynW(pwszAppParentDir, wszExePath, cchAppParentDir);
  178. bRet = DoubleUpBackslashes(pwszAppParentDir, cchAppParentDir);
  179. }
  180. }
  181. else
  182. {
  183. // if there is not another '\' then just use the same path as pwszAppDir
  184. lstrcpynW(pwszAppParentDir, wszExePath, cchAppParentDir);
  185. bRet = TRUE;
  186. }
  187. }
  188. }
  189. }
  190. }
  191. return bRet;
  192. }
  193. //
  194. // This function is called to actually write stuff out to the file
  195. //
  196. BOOL WriteToFile(HANDLE hFile, void* pv, DWORD cb)
  197. {
  198. DWORD dwBytesWritten;
  199. BOOL bWriteSucceeded = FALSE;
  200. if (WriteFile(hFile, pv, cb, &dwBytesWritten, NULL) &&
  201. (dwBytesWritten == cb))
  202. {
  203. bWriteSucceeded = TRUE;
  204. }
  205. return bWriteSucceeded;
  206. }
  207. BOOL PathIsNonEmptyDirectory(WCHAR* pwszPath)
  208. {
  209. WCHAR wszSearchFilter[MAX_PATH];
  210. DWORD dwAttr = GetFileAttributesW(pwszPath);
  211. BOOL bRet = FALSE;
  212. if( (-1 != dwAttr) && (FILE_ATTRIBUTE_DIRECTORY & dwAttr ) )
  213. {
  214. if( _snwprintf(wszSearchFilter,MAX_PATH,L"%s\\*.*",pwszPath) < 0 )
  215. return bRet;
  216. WIN32_FIND_DATAW FindData;
  217. HANDLE hSearch = FindFirstFileW(wszSearchFilter,&FindData);
  218. if( INVALID_HANDLE_VALUE == hSearch )
  219. return bRet;
  220. do
  221. {
  222. if(L'.' != FindData.cFileName[0])
  223. {
  224. bRet = TRUE;
  225. break;
  226. }
  227. }
  228. while( FindNextFileW(hSearch,&FindData) );
  229. FindClose(hSearch);
  230. }
  231. return bRet;
  232. }
  233. BOOL FindCDDriveContainingDirectory(WCHAR* pwchCDDriveLetter, WCHAR* pwszCheckPath)
  234. {
  235. // Find out cd drive (looks for app cd in drive, else just chooses first cd drive found)
  236. // NOTE: This function only actually does anything the first time its called (to avoid
  237. // thrashing CD drive, or bringing up excessive dialogs if no CD in drive).
  238. // The assumption is that once a good CD drive is found, any other times you need
  239. // a CD drive in this shim, it will be the same one, so this function will just return
  240. // that drive.
  241. static BOOL s_bFoundDrive = FALSE;
  242. static BOOL s_bTriedOnce = FALSE;
  243. static WCHAR s_wchCDDriveLetter = L'\0';
  244. if( s_bTriedOnce )
  245. {
  246. *pwchCDDriveLetter = s_wchCDDriveLetter;
  247. return s_bFoundDrive;
  248. }
  249. s_bTriedOnce = TRUE;
  250. DWORD dwLogicalDrives = GetLogicalDrives();
  251. WCHAR wchCurrDrive = L'a';
  252. WCHAR wszPath[MAX_PATH];
  253. while( dwLogicalDrives )
  254. {
  255. if( dwLogicalDrives & 1 )
  256. {
  257. if( _snwprintf(wszPath,MAX_PATH,L"%c:",wchCurrDrive) < 0 )
  258. return FALSE;
  259. if( DRIVE_CDROM == GetDriveTypeW( wszPath ) )
  260. {
  261. if( L'\0' == s_wchCDDriveLetter )
  262. {
  263. s_bFoundDrive = TRUE;
  264. s_wchCDDriveLetter = wchCurrDrive;
  265. }
  266. wcscat( wszPath, pwszCheckPath );
  267. DWORD dwAttr = GetFileAttributesW(wszPath);
  268. if( (-1 != dwAttr) && (FILE_ATTRIBUTE_DIRECTORY & dwAttr ) )
  269. {
  270. // this drive seems to have the app cd in it based on
  271. // a very primitive heuristic... so lets use this as our cd drive.
  272. s_wchCDDriveLetter = wchCurrDrive;
  273. *pwchCDDriveLetter = s_wchCDDriveLetter;
  274. return TRUE;
  275. }
  276. }
  277. }
  278. dwLogicalDrives >>= 1;
  279. wchCurrDrive++;
  280. }
  281. *pwchCDDriveLetter = s_wchCDDriveLetter; //may be L'\0' if we didn't find anything.
  282. return s_bFoundDrive;
  283. }
  284. BOOL GrabNParameters( UINT uiNumParameters,
  285. WCHAR* pwszStart, WCHAR** ppwszEnd,
  286. WCHAR pwszParam[][MAX_PATH] )
  287. {
  288. WCHAR* pwszEnd;
  289. UINT uiLength;
  290. *ppwszEnd = NULL;
  291. for( UINT i = 0; i < uiNumParameters; i++ )
  292. {
  293. if( L'<' != *(pwszStart++) )
  294. return FALSE;
  295. pwszEnd = pwszStart;
  296. while( (L'\0' != *pwszEnd) )
  297. {
  298. if( L'>' != *pwszEnd )
  299. {
  300. pwszEnd++;
  301. continue;
  302. }
  303. uiLength = (pwszEnd - pwszStart);
  304. if( uiLength >= MAX_PATH )
  305. return FALSE;
  306. wcsncpy(pwszParam[i],pwszStart,uiLength);
  307. pwszParam[i][uiLength] = L'\0';
  308. break;
  309. }
  310. if( L'>' != *pwszEnd )
  311. return FALSE;
  312. pwszStart = pwszEnd + 1;
  313. }
  314. *ppwszEnd = pwszStart;
  315. return TRUE;
  316. }
  317. //
  318. // As we write out the resource to a temp file, we need to scan through looking
  319. // for the env variables:
  320. //
  321. // %__AppDir_%
  322. // %__AppParentDir_%
  323. //
  324. // and replace them with the proper path (the dir of the current .exe or its parent,
  325. // respectively).
  326. //
  327. // Additional vars (added by amarp):
  328. //
  329. // %__AppSystemDir_%
  330. // - Maps to GetSystemDir() (i.e. c:\windows\system32)
  331. //
  332. // %__AppLocalOrCDDir<Param1><Param2><Param3>_%
  333. //
  334. // - The three parameters are just paths (should start with a \\).
  335. // Any/all may be empty. They are defined as follows:
  336. // Param1 = a relative path under the app�s install directory (i.e. under AppDir)
  337. // Param2 = a relative path under the app�s CD drive (where CD Drive = "drive:")
  338. // Param3 = a relative path/filename under Param1 or Param2 (in most cases this will be empty)
  339. //
  340. // When this var is encountered, it is replaced as follows:
  341. // a) if AppDirParam1Param3 is a *nonempty* directory, output AppDirParam1Param3
  342. // b) else, if there is a CDDrive for which directory CDDrive:Param2 exists, output CDDrive:Param2Param3
  343. // c) else, output CDDrive:Param2Param3 for the first enumerated CD drive.
  344. //
  345. // Example: %__AppLocalOrCDDir<\\content\\clipart><\\clipart><\\index.dat>_% maps does the following:
  346. // (lets assume AppDir is c:\app, and there are cd drives d: and e:, neither of which have the app's CD inserted)
  347. // a) Is c:\app\content a directory? Yes! -> Is it nonempty (at least one file or directory that doesn't start with '.')?
  348. // yes! -> output c:\app\content\index.dat
  349. // <end>
  350. //
  351. // Or, this example could pan out to the following scenario:
  352. // a) Is c:\app\content a directory? Yes! -> Is it nonempty? No!
  353. // b) Is d:\clipart a directory? No! Is e:\clipart a directory? No!
  354. // c) The first cd drive we found was d: -> output d:\clipart\index.dat
  355. // <end>
  356. //
  357. // Anoter example: %__AppLocalOrCDDir<__UNUSED__><\\clipart><>_% maps does the following:
  358. // (lets assume AppDir is c:\app and app CD is in drive d:)
  359. // a) Is c:\app__UNUSED__ a directory? PROBABLY NOT! (thus we can essentially ignore this parameter by doing this)
  360. // b) Is d:\clipart a directory? Yes! --> output d:\clipart
  361. // <end>
  362. //
  363. //
  364. //
  365. // NOTE: cbResourceSize holds the size of the original resource (which is the 2 WCHAR's
  366. // smaller than pvData). We use this to set eof after we are done writing everything
  367. // out.
  368. //
  369. BOOL WriteResourceFile(HANDLE hFile, void* pvData, DWORD cbResourceSize)
  370. {
  371. DWORD cbFileSize = cbResourceSize;
  372. WCHAR* pwszEndOfLastWrite = (WCHAR*)pvData;
  373. WCHAR wszAppDir[MAX_PATH];
  374. WCHAR wszAppParentDir[MAX_PATH];
  375. WCHAR wszSystemDir[MAX_PATH];
  376. BOOL bRet = FALSE;
  377. bRet = InitAppDir(wszSystemDir, sizeof(wszSystemDir)/sizeof(wszSystemDir[0]),
  378. wszAppDir, sizeof(wszAppDir)/sizeof(wszAppDir[0]),
  379. wszAppParentDir, sizeof(wszAppParentDir)/sizeof(wszAppParentDir[0]));
  380. if (!bRet)
  381. return bRet;
  382. do
  383. {
  384. WCHAR* pwsz = wcsstr(pwszEndOfLastWrite, L"%__App");
  385. if (pwsz)
  386. {
  387. // first, write out anything before the tag we found
  388. bRet = WriteToFile(hFile, pwszEndOfLastWrite, (DWORD)((BYTE*)pwsz - (BYTE*)pwszEndOfLastWrite));
  389. if(!bRet)
  390. break;
  391. pwszEndOfLastWrite = pwsz;
  392. // found a tag that we need to replace. See which one it is
  393. if (wcsncmp(pwsz, L"%__AppDir_%", lstrlenW(L"%__AppDir_%")) == 0)
  394. {
  395. bRet = WriteToFile(hFile, wszAppDir, lstrlenW(wszAppDir) * sizeof(WCHAR));
  396. pwszEndOfLastWrite += lstrlenW(L"%__AppDir_%");
  397. }
  398. else if (wcsncmp(pwsz, L"%__AppParentDir_%", lstrlenW(L"%__AppParentDir_%")) == 0)
  399. {
  400. bRet = WriteToFile(hFile, wszAppParentDir, lstrlenW(wszAppParentDir) * sizeof(WCHAR));
  401. pwszEndOfLastWrite += lstrlenW(L"%__AppParentDir_%");
  402. }
  403. else if (wcsncmp(pwsz, L"%__AppSystemDir_%", lstrlenW(L"%__AppSystemDir_%")) == 0)
  404. {
  405. bRet = WriteToFile(hFile, wszSystemDir, lstrlenW(wszSystemDir) * sizeof(WCHAR));
  406. pwszEndOfLastWrite += lstrlenW(L"%__AppSystemDir_%");
  407. }
  408. else if (wcsncmp(pwsz, L"%__AppLocalOrCDDir", lstrlenW(L"%__AppLocalOrCDDir")) == 0)
  409. {
  410. WCHAR wszParams[3][MAX_PATH];
  411. WCHAR* pwszStart = pwsz + lstrlenW(L"%__AppLocalOrCDDir");
  412. WCHAR* pwszEnd;
  413. WCHAR wszDesiredPath[MAX_PATH];
  414. WCHAR wchDrive;
  415. if (!GrabNParameters(3,pwszStart,&pwszEnd,wszParams))
  416. {
  417. pwszEndOfLastWrite += lstrlenW(L"%__AppLocalOrCDDir");
  418. continue;
  419. }
  420. if (0 != wcsncmp(pwszEnd, L"_%", lstrlenW(L"_%")))
  421. {
  422. pwszEndOfLastWrite = pwszEnd;
  423. continue;
  424. }
  425. if ( _snwprintf( wszDesiredPath, MAX_PATH,L"%s%s", wszAppDir, wszParams[0] ) > 0 )
  426. {
  427. if( PathIsNonEmptyDirectory(wszDesiredPath) )
  428. {
  429. if( _snwprintf( wszDesiredPath, MAX_PATH,L"%s%s%s", wszAppDir, wszParams[0], wszParams[2] ) > 0 )
  430. bRet = WriteToFile(hFile, wszDesiredPath, lstrlenW(wszDesiredPath) * sizeof(WCHAR));
  431. }
  432. else
  433. {
  434. WCHAR wchDrive;
  435. UINT uiOffset;
  436. if( L'\\' == wszParams[1][0] && L'\\' == wszParams[1][1] )
  437. uiOffset = sizeof(WCHAR);
  438. else
  439. uiOffset = 0;
  440. if( FindCDDriveContainingDirectory(&wchDrive,wszParams[1]+uiOffset) &&
  441. (_snwprintf(wszDesiredPath,MAX_PATH,L"%c:%s%s",wchDrive,wszParams[1],wszParams[2]) > 0) )
  442. bRet = WriteToFile(hFile, wszDesiredPath, lstrlenW(wszDesiredPath) * sizeof(WCHAR));
  443. }
  444. }
  445. pwszEndOfLastWrite= pwszEnd + lstrlenW(L"_%");
  446. }
  447. else
  448. {
  449. // Strange... we found a string that started w/ "%__App" that wasen't one we are
  450. // intersted in. Just skip over it and keep going.
  451. bRet = WriteToFile(hFile, pwsz, lstrlenW(L"%__App") * sizeof(WCHAR));
  452. pwszEndOfLastWrite += lstrlenW(L"%__App");
  453. }
  454. }
  455. else
  456. {
  457. // didn't find anymore strings to replace
  458. // using lstrlenW should give us the size of the string w/out the null, which is what we
  459. // want since we added on the space for the null when we created the buffer
  460. bRet = WriteToFile(hFile, pwszEndOfLastWrite, lstrlenW(pwszEndOfLastWrite) * sizeof(WCHAR));
  461. // break out of the loop, as we are finished
  462. break;
  463. }
  464. } while (bRet);
  465. return bRet;
  466. }
  467. //
  468. // The job of this function is to read the specified string resource our
  469. // of our own DLL and write it to a temp file, and then to spawn regedit on
  470. // the file
  471. //
  472. BOOL ExecuteRegFileFromResource(char* pszResourceName)
  473. {
  474. // lame, but we aren't passed our hinst in our pseudo dllmain,
  475. // so we have to hardcode the dllname
  476. HMODULE hmod = GetModuleHandleA("AcGenral");
  477. BOOL bRet = FALSE;
  478. if (hmod)
  479. {
  480. HRSRC hrsrc = FindResourceA(hmod, pszResourceName, MAKEINTRESOURCEA(10)/* RT_RCDATA */);
  481. if (hrsrc)
  482. {
  483. DWORD dwSize;
  484. void* pvData;
  485. dwSize = SizeofResource(hmod, hrsrc);
  486. // allocate enough room for the entire resource including puting a null terminator on
  487. // the end since we will be treating it like huge LPWSTR.
  488. pvData = LocalAlloc(LPTR, dwSize + sizeof(WCHAR));
  489. if (pvData)
  490. {
  491. HGLOBAL hGlobal = LoadResource(hmod, hrsrc);
  492. if (hGlobal)
  493. {
  494. void* pv = LockResource(hGlobal);
  495. if (pv)
  496. {
  497. char szTempFile[MAX_PATH];
  498. // copy the resource into our buffer
  499. memcpy(pvData, pv, dwSize);
  500. if (CreateTempName(szTempFile))
  501. {
  502. // we use OPEN_EXISTING since the tempfile should always exist as it
  503. // was created in the call to CreateTempName()
  504. HANDLE hFile = CreateFileA(szTempFile,
  505. GENERIC_WRITE,
  506. FILE_SHARE_READ,
  507. NULL,
  508. OPEN_EXISTING,
  509. FILE_ATTRIBUTE_TEMPORARY,
  510. NULL);
  511. if (hFile != INVALID_HANDLE_VALUE)
  512. {
  513. DWORD dwBytesWritten;
  514. BOOL bWriteSucceeded = WriteResourceFile(hFile, pvData, dwSize);
  515. CloseHandle(hFile);
  516. if (bWriteSucceeded)
  517. {
  518. bRet = SpawnRegedit(szTempFile);
  519. }
  520. }
  521. DeleteFileA(szTempFile);
  522. }
  523. }
  524. }
  525. }
  526. }
  527. }
  528. return bRet;
  529. }
  530. BOOL PopulateHKCUValues()
  531. {
  532. static BOOL s_fAlreadyPopulated = FALSE;
  533. if (!s_fAlreadyPopulated)
  534. {
  535. char szRegKeyName[MAX_PATH];
  536. char szResourceName[64];
  537. UINT uiOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); // stop dialogs from coming up when we enumerate CD drives that are empty.
  538. // set this to true so we only do this check once
  539. s_fAlreadyPopulated = TRUE;
  540. if (ParseCommandLine(COMMAND_LINE,
  541. szRegKeyName,
  542. sizeof(szRegKeyName)/sizeof(szRegKeyName[0]),
  543. szResourceName,
  544. sizeof(szResourceName)/sizeof(szResourceName[0])))
  545. {
  546. DWORD dwError;
  547. HKEY hkCU;
  548. // check to see if the HKCU registry key is already present
  549. dwError = RegOpenKeyExA(HKEY_CURRENT_USER,
  550. szRegKeyName,
  551. 0,
  552. KEY_QUERY_VALUE,
  553. &hkCU);
  554. if (dwError == ERROR_SUCCESS)
  555. {
  556. // yep, its already there. Nothing to do.
  557. RegCloseKey(hkCU);
  558. }
  559. else if (dwError == ERROR_FILE_NOT_FOUND)
  560. {
  561. // the regkey is missing, we will assume that this is the first time
  562. // the user has run the app and populate HKCU with the proper stuff
  563. ExecuteRegFileFromResource(szResourceName);
  564. }
  565. }
  566. SetErrorMode(uiOldErrorMode);
  567. }
  568. return s_fAlreadyPopulated;
  569. }
  570. //
  571. // Its lame that we have to hook RegOpenKey/Ex but since we need to call
  572. // the advapi32 registry apis we can't do this as a straight NOTIFY_FUNCTION
  573. // because we need to wait for advapi to have its DLL_PROCESS_ATTACH called.
  574. //
  575. LONG
  576. APIHOOK(RegOpenKeyA)(HKEY hkey, LPCSTR pszSubKey, HKEY* phkResult)
  577. {
  578. PopulateHKCUValues();
  579. return ORIGINAL_API(RegOpenKeyA)(hkey, pszSubKey, phkResult);
  580. }
  581. LONG
  582. APIHOOK(RegOpenKeyW)(HKEY hkey, LPCWSTR pszSubKey, HKEY* phkResult)
  583. {
  584. PopulateHKCUValues();
  585. return ORIGINAL_API(RegOpenKeyW)(hkey, pszSubKey, phkResult);
  586. }
  587. LONG
  588. APIHOOK(RegOpenKeyExA)(HKEY hkey, LPCSTR pszSubKey, DWORD ulOptions, REGSAM samDesired, HKEY* phkResult)
  589. {
  590. PopulateHKCUValues();
  591. return ORIGINAL_API(RegOpenKeyExA)(hkey, pszSubKey, ulOptions, samDesired, phkResult);
  592. }
  593. LONG
  594. APIHOOK(RegOpenKeyExW)(HKEY hkey, LPCWSTR pszSubKey, DWORD ulOptions, REGSAM samDesired, HKEY* phkResult)
  595. {
  596. PopulateHKCUValues();
  597. return ORIGINAL_API(RegOpenKeyExW)(hkey, pszSubKey, ulOptions, samDesired, phkResult);
  598. }
  599. /*++
  600. Register hooked functions
  601. --*/
  602. HOOK_BEGIN
  603. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA)
  604. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyW)
  605. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA)
  606. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExW)
  607. HOOK_END
  608. IMPLEMENT_SHIM_END