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.

766 lines
25 KiB

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