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.

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