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.

519 lines
16 KiB

  1. #include "init.h"
  2. #include "global.h"
  3. #include <shlwapi.h> // for DllInstall prototype
  4. #define MLUI_INIT
  5. #include <mluisupp.h>
  6. extern HRESULT CanonicalizeModuleUsage(void);
  7. // {88C6C381-2E85-11d0-94DE-444553540000}
  8. const GUID CLSID_ControlFolder = {0x88c6c381, 0x2e85, 0x11d0, 0x94, 0xde, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0};
  9. #define STRING_CLSID_CONTROLFOLDER TEXT("{88C6C381-2E85-11d0-94DE-444553540000}")
  10. // global variables
  11. HINSTANCE g_hInst = NULL;
  12. LONG g_cRefDll = 0;
  13. BOOL g_fAllAccess = FALSE; // we'll set to true if we can open our keys with KEY_ALL_ACCESS
  14. #define GUID_STR_LEN 40
  15. #define REG_PATH_IE_SETTINGS TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings")
  16. #define REG_PATH_IE_CACHE_LIST TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache")
  17. #define REG_ACTIVEX_CACHE TEXT("ActiveXCache")
  18. #define DEFAULT_CACHE_DIRECTORY TEXT("Occache")
  19. HRESULT CreateShellFolderPath(LPCTSTR pszPath, LPCTSTR pszGUID)
  20. {
  21. if (!PathFileExists(pszPath))
  22. CreateDirectory(pszPath, NULL);
  23. // Mark the folder as a system directory
  24. if (SetFileAttributes(pszPath, FILE_ATTRIBUTE_SYSTEM))
  25. {
  26. TCHAR szDesktopIni[MAX_PATH];
  27. // Write in the desktop.ini the cache folder class ID
  28. PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
  29. // If the desktop.ini already exists, make sure it is writable
  30. if (PathFileExists(szDesktopIni))
  31. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL);
  32. // (First, flush the cache to make sure the desktop.ini
  33. // file is really created.)
  34. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  35. WritePrivateProfileString(TEXT(".ShellClassInfo"), TEXT("CLSID"), pszGUID, szDesktopIni);
  36. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  37. // Hide the desktop.ini since the shell does not selectively
  38. // hide it.
  39. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_HIDDEN);
  40. return NOERROR;
  41. }
  42. else
  43. {
  44. DebugMsg(DM_TRACE, "Cannot make %s a system folder", pszPath);
  45. return E_FAIL;
  46. }
  47. }
  48. void CleanupShellFolder(LPCTSTR pszPath)
  49. {
  50. if (PathFileExists(pszPath))
  51. {
  52. TCHAR szDesktopIni[MAX_PATH];
  53. // make the history a normal folder
  54. SetFileAttributes(pszPath, FILE_ATTRIBUTE_NORMAL);
  55. PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
  56. // If the desktop.ini already exists, make sure it is writable
  57. if (PathFileExists(szDesktopIni))
  58. {
  59. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL);
  60. // Get the ini file cache to let go of this file
  61. WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
  62. DeleteFile(szDesktopIni);
  63. }
  64. // remove the history directory
  65. // RemoveDirectory(pszPath); // don't do this, we haven't uninstalled all the controls therein!
  66. }
  67. }
  68. HRESULT CallRegInstall(LPSTR szSection)
  69. {
  70. HRESULT hr = E_FAIL;
  71. HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL"));
  72. if (hinstAdvPack)
  73. {
  74. REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, achREGINSTALL);
  75. if (pfnri)
  76. {
  77. hr = pfnri(g_hInst, szSection, NULL);
  78. }
  79. FreeLibrary(hinstAdvPack);
  80. }
  81. return hr;
  82. }
  83. HRESULT GetControlFolderPath(LPTSTR szCacheDir, DWORD cchBuffer )
  84. {
  85. /*
  86. LONG lResult = ERROR_SUCCESS;
  87. HKEY hKeyIntSetting = NULL;
  88. Assert(lpszDir != NULL);
  89. if (lpszDir == NULL)
  90. return HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
  91. if ((lResult = RegOpenKeyEx(
  92. HKEY_LOCAL_MACHINE,
  93. REG_PATH_IE_SETTINGS,
  94. 0x0,
  95. KEY_READ,
  96. &hKeyIntSetting)) == ERROR_SUCCESS)
  97. {
  98. ULONG ulSize = ulSizeBuf;
  99. lResult = RegQueryValueEx(
  100. hKeyIntSetting,
  101. REG_ACTIVEX_CACHE,
  102. NULL,
  103. NULL,
  104. (unsigned char*)lpszDir,
  105. &ulSize);
  106. RegCloseKey(hKeyIntSetting);
  107. }
  108. return (lResult == ERROR_SUCCESS ? S_OK : HRESULT_FROM_WIN32(lResult));
  109. */
  110. // Compose the default path.
  111. int len;
  112. GetWindowsDirectory(szCacheDir, cchBuffer);
  113. len = lstrlen(szCacheDir);
  114. if ( len && (szCacheDir[len-1] != '\\'))
  115. lstrcat(szCacheDir, "\\");
  116. lstrcat(szCacheDir, REG_OCX_CACHE_DIR);
  117. return ((len != 0)? S_OK : E_FAIL);
  118. }
  119. STDAPI AddCacheToRegPathList( HKEY hkeyParent, LPCTSTR szCacheDir, DWORD cchCacheDir )
  120. {
  121. HRESULT hr = E_FAIL;
  122. LONG lResult;
  123. // Check to see if new path already exists in the list of paths under
  124. // HKLM\...\Windows\CurrentVersion\Internet Settings\ActiveX Cache\Paths.
  125. // If not, add it.
  126. HKEY hkeyCacheList = NULL;
  127. lResult = RegCreateKey( hkeyParent, REG_OCX_CACHE_SUBKEY, &hkeyCacheList );
  128. if (lResult == ERROR_SUCCESS) {
  129. DWORD dwIndex;
  130. TCHAR szName[MAX_PATH];
  131. DWORD cbName;
  132. TCHAR szValue[MAX_PATH];
  133. DWORD cbValue;
  134. LONG lValueIndex = -1;
  135. BOOL fFoundValue = FALSE;
  136. // iterate through the values of the cache subkey of the internet settings key.
  137. // The values have names which are simple, positive itegers. The idea here is
  138. // to have collection of values like so:
  139. // Name Value Source
  140. // "1" "C:\WINNT\OC Cache" IE3 legacy controls
  141. // "2" "C:\WINNT\Downloaded ActiveXControls" IE4 PR-1 legacy controls
  142. // "3" "C:\WINNT\Downloaded Components" IE4 controls.
  143. for ( dwIndex = 0, cbName = sizeof(szName), cbValue = sizeof(szValue);
  144. lResult == ERROR_SUCCESS;
  145. dwIndex++, cbName = sizeof(szName), cbValue = sizeof(szValue) )
  146. {
  147. lResult = RegEnumValue( hkeyCacheList, dwIndex,
  148. szName, &cbName,
  149. NULL, NULL,
  150. (LPBYTE)szValue, &cbValue );
  151. if (lResult == ERROR_SUCCESS)
  152. {
  153. // for find new unique value name later.
  154. lValueIndex = max(lValueIndex, StrToInt(szName));
  155. if ( !fFoundValue )
  156. fFoundValue = (lstrcmpi(szCacheDir, szValue) == 0);
  157. // Make sure that we're registered for all the (existing) old cache directories
  158. if ( !fFoundValue && PathFileExists(szValue) ) {
  159. CreateShellFolderPath( szValue, STRING_CLSID_CONTROLFOLDER );
  160. }
  161. }
  162. }
  163. if (lResult == ERROR_NO_MORE_ITEMS)
  164. { // we successfully inspected all the values
  165. if ( !fFoundValue )
  166. {
  167. TCHAR szSubKey[20]; // don't foresee moure than a few billion caches
  168. // add new path to list of paths
  169. wsprintf(szSubKey, "%i", ++lValueIndex);
  170. lResult = RegSetValueEx( hkeyCacheList, szSubKey, 0, REG_SZ,
  171. (LPBYTE)szCacheDir, cchCacheDir + 1);
  172. if ( lResult == ERROR_SUCCESS )
  173. hr = S_OK;
  174. else
  175. hr = HRESULT_FROM_WIN32(lResult);
  176. } else
  177. hr = S_OK; // it's already there
  178. } else
  179. hr = HRESULT_FROM_WIN32(lResult);
  180. RegCloseKey( hkeyCacheList );
  181. } else
  182. hr = HRESULT_FROM_WIN32(lResult);
  183. return hr;
  184. }
  185. STDAPI SetCacheRegEntries( LPCTSTR szCacheDir )
  186. {
  187. HRESULT hr = E_FAIL;
  188. LONG lResult;
  189. HKEY hkeyIS; // reg key for internet settings;
  190. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  191. REG_PATH_IE_SETTINGS,
  192. 0x0,
  193. KEY_ALL_ACCESS,
  194. &hkeyIS );
  195. if ( lResult == ERROR_SUCCESS)
  196. {
  197. // now the key is ours, oh, yes... it is ours...
  198. // set the value of the internet settings key used by Code Download.
  199. int cchCacheDir = lstrlen(szCacheDir);
  200. TCHAR szCacheDirOld[MAX_PATH];
  201. DWORD dwType = REG_SZ;
  202. DWORD cbOldCache = MAX_PATH;
  203. // Don't fail if we can't quite hook up with legacy caches
  204. hr = S_OK;
  205. // Add our old cache path, if any, to the cache path list if it differs from our new cache.
  206. lResult = RegQueryValueEx( hkeyIS, REG_OCX_CACHE_VALUE_NAME, 0, &dwType, (LPBYTE)szCacheDirOld, &cbOldCache );
  207. if ( lResult == ERROR_SUCCESS && dwType == REG_SZ &&
  208. lstrcmpi( szCacheDirOld, szCacheDir ) != 0 )
  209. AddCacheToRegPathList( hkeyIS, szCacheDirOld, cbOldCache - 1 );
  210. // Under NT, IE3 might not have been able to write the old cache path, so we'll cobble one up
  211. // and add it if that dir is present.
  212. if ( SUCCEEDED(GetWindowsDirectory( szCacheDirOld, MAX_PATH )) )
  213. {
  214. cbOldCache = lstrlen( szCacheDirOld );
  215. if ( cbOldCache && (szCacheDirOld[cbOldCache-1] != '\\'))
  216. lstrcat(szCacheDirOld, "\\");
  217. cbOldCache = lstrlen(lstrcat( szCacheDirOld, REG_OCX_OLD_CACHE_DIR ));
  218. if (PathFileExists(szCacheDirOld))
  219. {
  220. // Let's not fail if this doesn't work
  221. AddCacheToRegPathList( hkeyIS, szCacheDirOld, cbOldCache );
  222. CreateShellFolderPath( szCacheDirOld, STRING_CLSID_CONTROLFOLDER );
  223. }
  224. }
  225. if ( SUCCEEDED(hr) )
  226. {
  227. lResult = RegSetValueEx( hkeyIS, REG_OCX_CACHE_VALUE_NAME, 0, REG_SZ,
  228. (LPBYTE)szCacheDir, cchCacheDir + 1 ); // need '\0'
  229. if ( lResult == ERROR_SUCCESS )
  230. {
  231. // add the new (?) path to the collection of valid paths which are the
  232. // values for the cache subkey.
  233. hr = AddCacheToRegPathList( hkeyIS, szCacheDir, cchCacheDir );
  234. } else
  235. hr = HRESULT_FROM_WIN32(lResult);
  236. }
  237. RegCloseKey( hkeyIS );
  238. } else
  239. hr = HRESULT_FROM_WIN32(lResult);
  240. return hr;
  241. }
  242. STDAPI InitCacheFolder(void)
  243. {
  244. HRESULT hr = E_FAIL;
  245. TCHAR szCacheDir[MAX_PATH];
  246. // Compose the default path.
  247. GetControlFolderPath(szCacheDir, MAX_PATH);
  248. // Okay, now we know where we want to put things.
  249. // Create the directory, and/or claim it as our own
  250. hr = CreateShellFolderPath( szCacheDir, STRING_CLSID_CONTROLFOLDER );
  251. if ( SUCCEEDED(hr) )
  252. {
  253. hr = SetCacheRegEntries( szCacheDir );
  254. }
  255. return hr;
  256. }
  257. STDAPI DllUnregisterServer(void)
  258. {
  259. // Remove a bunch of stuff from the registry.
  260. //
  261. CallRegInstall("Unreg");
  262. return NOERROR;
  263. }
  264. STDAPI DllRegisterServer(void)
  265. {
  266. //
  267. // Add a bunch of stuff to the registry.
  268. //
  269. if (FAILED(CallRegInstall("Reg")))
  270. {
  271. goto CleanUp;
  272. }
  273. return NOERROR;
  274. CleanUp: // cleanup stuff if any of our reg stuff fails
  275. DllUnregisterServer();
  276. return E_FAIL;
  277. }
  278. STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine)
  279. {
  280. HRESULT hr = S_OK;
  281. if ( bInstall )
  282. {
  283. hr =InitCacheFolder();
  284. if ( SUCCEEDED(hr) )
  285. CanonicalizeModuleUsage();
  286. }
  287. else
  288. {
  289. LONG lResult;
  290. HKEY hkeyCacheList;
  291. // Unhook occache as a shell extension for the cache folders.
  292. lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  293. REG_PATH_IE_CACHE_LIST,
  294. 0x0,
  295. KEY_ALL_ACCESS,
  296. &hkeyCacheList );
  297. if ( lResult == ERROR_SUCCESS ) {
  298. DWORD dwIndex;
  299. TCHAR szName[MAX_PATH];
  300. DWORD cbName;
  301. TCHAR szValue[MAX_PATH];
  302. DWORD cbValue;
  303. for ( dwIndex = 0, cbName = sizeof(szName), cbValue = sizeof(szValue);
  304. lResult == ERROR_SUCCESS;
  305. dwIndex++, cbName = sizeof(szName), cbValue = sizeof(szValue) )
  306. {
  307. lResult = RegEnumValue( hkeyCacheList, dwIndex,
  308. szName, &cbName,
  309. NULL, NULL,
  310. (LPBYTE)szValue, &cbValue );
  311. if ( lResult == ERROR_SUCCESS && PathFileExists(szValue) )
  312. CleanupShellFolder(szValue);
  313. }
  314. // We leave this key in place because it is the only record we have of the
  315. // cache folders and would be useful to future installations of IE
  316. RegCloseKey( hkeyCacheList );
  317. }
  318. }
  319. return hr;
  320. }
  321. STDAPI_(BOOL) DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID dwReserved)
  322. {
  323. if (dwReason == DLL_PROCESS_ATTACH)
  324. {
  325. HKEY hkeyTest;
  326. g_hInst = hInst;
  327. DisableThreadLibraryCalls(g_hInst);
  328. MLLoadResources(g_hInst, TEXT("occachlc.dll"));
  329. // Test to see if we have permissions to modify HKLM subkeys.
  330. // We'll use this as an early test to see if we can remove controls.
  331. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  332. REG_PATH_IE_SETTINGS,
  333. 0x0,
  334. KEY_ALL_ACCESS,
  335. &hkeyTest ) == ERROR_SUCCESS )
  336. {
  337. g_fAllAccess = TRUE;
  338. RegCloseKey( hkeyTest );
  339. }
  340. }
  341. else if (dwReason == DLL_PROCESS_DETACH)
  342. {
  343. MLFreeResources(g_hInst);
  344. }
  345. return TRUE;
  346. }
  347. typedef struct {
  348. const IClassFactoryVtbl *cf;
  349. const CLSID *pclsid;
  350. HRESULT (STDMETHODCALLTYPE *pfnCreate)(IUnknown *, REFIID, void **);
  351. } OBJ_ENTRY;
  352. extern const IClassFactoryVtbl c_CFVtbl; // forward
  353. //
  354. // we always do a linear search here so put your most often used things first
  355. //
  356. const OBJ_ENTRY c_clsmap[] = {
  357. { &c_CFVtbl, &CLSID_ControlFolder, ControlFolder_CreateInstance },
  358. { &c_CFVtbl, &CLSID_EmptyControlVolumeCache, EmptyControl_CreateInstance },
  359. // add more entries here
  360. { NULL, NULL, NULL }
  361. };
  362. // static class factory (no allocs!)
  363. STDMETHODIMP CClassFactory_QueryInterface(IClassFactory *pcf, REFIID riid, void **ppvObj)
  364. {
  365. if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
  366. {
  367. *ppvObj = (void *)pcf;
  368. }
  369. else
  370. {
  371. *ppvObj = NULL;
  372. return E_NOINTERFACE;
  373. }
  374. DllAddRef();
  375. return NOERROR;
  376. }
  377. STDMETHODIMP_(ULONG) CClassFactory_AddRef(IClassFactory *pcf)
  378. {
  379. DllAddRef();
  380. return 2;
  381. }
  382. STDMETHODIMP_(ULONG) CClassFactory_Release(IClassFactory *pcf)
  383. {
  384. DllRelease();
  385. return 1;
  386. }
  387. STDMETHODIMP CClassFactory_CreateInstance(IClassFactory *pcf, IUnknown *punkOuter, REFIID riid, void **ppvObject)
  388. {
  389. OBJ_ENTRY *this = IToClass(OBJ_ENTRY, cf, pcf);
  390. return this->pfnCreate(punkOuter, riid, ppvObject);
  391. }
  392. STDMETHODIMP CClassFactory_LockServer(IClassFactory *pcf, BOOL fLock)
  393. {
  394. if (fLock)
  395. DllAddRef();
  396. else
  397. DllRelease();
  398. return S_OK;
  399. }
  400. const IClassFactoryVtbl c_CFVtbl = {
  401. CClassFactory_QueryInterface, CClassFactory_AddRef, CClassFactory_Release,
  402. CClassFactory_CreateInstance,
  403. CClassFactory_LockServer
  404. };
  405. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
  406. {
  407. if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
  408. {
  409. const OBJ_ENTRY *pcls;
  410. for (pcls = c_clsmap; pcls->pclsid; pcls++)
  411. {
  412. if (IsEqualIID(rclsid, pcls->pclsid))
  413. {
  414. *ppv = (void *)&(pcls->cf);
  415. DllAddRef(); // Class Factory keeps dll in memory
  416. return NOERROR;
  417. }
  418. }
  419. }
  420. // failure
  421. *ppv = NULL;
  422. return CLASS_E_CLASSNOTAVAILABLE;;
  423. }
  424. STDAPI_(void) DllAddRef()
  425. {
  426. InterlockedIncrement(&g_cRefDll);
  427. }
  428. STDAPI_(void) DllRelease()
  429. {
  430. InterlockedDecrement(&g_cRefDll);
  431. }
  432. STDAPI DllCanUnloadNow(void)
  433. {
  434. return g_cRefDll == 0 ? S_OK : S_FALSE;
  435. }