|
|
#include "init.h"
#include "global.h"
#include <shlwapi.h> // for DllInstall prototype
#define MLUI_INIT
#include <mluisupp.h>
// Downlevel delay load support (we forward to shlwapi)
#include <delayimp.h>
PfnDliHook __pfnDliFailureHook; HANDLE BaseDllHandle;
extern HRESULT CanonicalizeModuleUsage(void);
// {88C6C381-2E85-11d0-94DE-444553540000}
const GUID CLSID_ControlFolder = {0x88c6c381, 0x2e85, 0x11d0, 0x94, 0xde, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0}; #define STRING_CLSID_CONTROLFOLDER TEXT("{88C6C381-2E85-11d0-94DE-444553540000}")
// global variables
HINSTANCE g_hInst = NULL; LONG g_cRefDll = 0; BOOL g_fAllAccess = FALSE; // we'll set to true if we can open our keys with KEY_ALL_ACCESS
#define GUID_STR_LEN 40
#define REG_PATH_IE_SETTINGS TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings")
#define REG_PATH_IE_CACHE_LIST TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\ActiveX Cache")
#define REG_ACTIVEX_CACHE TEXT("ActiveXCache")
#define DEFAULT_CACHE_DIRECTORY TEXT("Occache")
HRESULT CreateShellFolderPath(LPCTSTR pszPath, LPCTSTR pszGUID) { if (!PathFileExists(pszPath)) CreateDirectory(pszPath, NULL);
// Mark the folder as a system directory
if (SetFileAttributes(pszPath, FILE_ATTRIBUTE_SYSTEM)) { TCHAR szDesktopIni[MAX_PATH]; // Write in the desktop.ini the cache folder class ID
PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
// If the desktop.ini already exists, make sure it is writable
if (PathFileExists(szDesktopIni)) SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL);
// (First, flush the cache to make sure the desktop.ini
// file is really created.)
WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni); WritePrivateProfileString(TEXT(".ShellClassInfo"), TEXT("CLSID"), pszGUID, szDesktopIni); WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni);
// Hide the desktop.ini since the shell does not selectively
// hide it.
SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_HIDDEN);
return NOERROR; } else { DebugMsg(DM_TRACE, "Cannot make %s a system folder", pszPath); return E_FAIL; } }
void CleanupShellFolder(LPCTSTR pszPath) { if (PathFileExists(pszPath)) { TCHAR szDesktopIni[MAX_PATH];
// make the history a normal folder
SetFileAttributes(pszPath, FILE_ATTRIBUTE_NORMAL); PathCombine(szDesktopIni, pszPath, TEXT("desktop.ini"));
// If the desktop.ini already exists, make sure it is writable
if (PathFileExists(szDesktopIni)) { SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_NORMAL); // Get the ini file cache to let go of this file
WritePrivateProfileString(NULL, NULL, NULL, szDesktopIni); DeleteFile(szDesktopIni); }
// remove the history directory
// RemoveDirectory(pszPath); // don't do this, we haven't uninstalled all the controls therein!
} }
HRESULT CallRegInstall(LPSTR szSection) { HRESULT hr = E_FAIL; HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL")); if (hinstAdvPack) { REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, achREGINSTALL); if (pfnri) { hr = pfnri(g_hInst, szSection, NULL); }
FreeLibrary(hinstAdvPack); }
return hr; }
HRESULT GetControlFolderPath(LPTSTR szCacheDir, DWORD cchBuffer ) { /*
LONG lResult = ERROR_SUCCESS; HKEY hKeyIntSetting = NULL;
Assert(lpszDir != NULL); if (lpszDir == NULL) return HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS);
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_PATH_IE_SETTINGS, 0x0, KEY_READ, &hKeyIntSetting)) == ERROR_SUCCESS) { ULONG ulSize = ulSizeBuf; lResult = RegQueryValueEx( hKeyIntSetting, REG_ACTIVEX_CACHE, NULL, NULL, (unsigned char*)lpszDir, &ulSize); RegCloseKey(hKeyIntSetting); }
return (lResult == ERROR_SUCCESS ? S_OK : HRESULT_FROM_WIN32(lResult)); */ // Compose the default path.
int len;
GetWindowsDirectory(szCacheDir, cchBuffer); len = lstrlen(szCacheDir); if ( len && (szCacheDir[len-1] != '\\')) lstrcat(szCacheDir, "\\"); lstrcat(szCacheDir, REG_OCX_CACHE_DIR);
return ((len != 0)? S_OK : E_FAIL); }
STDAPI AddCacheToRegPathList( HKEY hkeyParent, LPCTSTR szCacheDir, DWORD cchCacheDir ) { HRESULT hr = E_FAIL; LONG lResult;
// Check to see if new path already exists in the list of paths under
// HKLM\...\Windows\CurrentVersion\Internet Settings\ActiveX Cache\Paths.
// If not, add it.
HKEY hkeyCacheList = NULL;
lResult = RegCreateKey( hkeyParent, REG_OCX_CACHE_SUBKEY, &hkeyCacheList ); if (lResult == ERROR_SUCCESS) { DWORD dwIndex; TCHAR szName[MAX_PATH]; DWORD cbName; TCHAR szValue[MAX_PATH]; DWORD cbValue; LONG lValueIndex = -1; BOOL fFoundValue = FALSE;
// iterate through the values of the cache subkey of the internet settings key.
// The values have names which are simple, positive itegers. The idea here is
// to have collection of values like so:
// Name Value Source
// "1" "C:\WINNT\OC Cache" IE3 legacy controls
// "2" "C:\WINNT\Downloaded ActiveXControls" IE4 PR-1 legacy controls
// "3" "C:\WINNT\Downloaded Components" IE4 controls.
for ( dwIndex = 0, cbName = sizeof(szName), cbValue = sizeof(szValue); lResult == ERROR_SUCCESS; dwIndex++, cbName = sizeof(szName), cbValue = sizeof(szValue) ) { lResult = RegEnumValue( hkeyCacheList, dwIndex, szName, &cbName, NULL, NULL, (LPBYTE)szValue, &cbValue );
if (lResult == ERROR_SUCCESS) { // for find new unique value name later.
lValueIndex = max(lValueIndex, StrToInt(szName));
if ( !fFoundValue ) fFoundValue = (lstrcmpi(szCacheDir, szValue) == 0); // Make sure that we're registered for all the (existing) old cache directories
if ( !fFoundValue && PathFileExists(szValue) ) { CreateShellFolderPath( szValue, STRING_CLSID_CONTROLFOLDER ); } } }
if (lResult == ERROR_NO_MORE_ITEMS) { // we successfully inspected all the values
if ( !fFoundValue ) { TCHAR szSubKey[20]; // don't foresee moure than a few billion caches
// add new path to list of paths
wsprintf(szSubKey, "%i", ++lValueIndex); lResult = RegSetValueEx( hkeyCacheList, szSubKey, 0, REG_SZ, (LPBYTE)szCacheDir, cchCacheDir + 1); if ( lResult == ERROR_SUCCESS ) hr = S_OK; else hr = HRESULT_FROM_WIN32(lResult); } else hr = S_OK; // it's already there
} else hr = HRESULT_FROM_WIN32(lResult);
RegCloseKey( hkeyCacheList ); } else hr = HRESULT_FROM_WIN32(lResult);
return hr; }
STDAPI SetCacheRegEntries( LPCTSTR szCacheDir ) { HRESULT hr = E_FAIL; LONG lResult; HKEY hkeyIS; // reg key for internet settings;
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_PATH_IE_SETTINGS, 0x0, KEY_ALL_ACCESS, &hkeyIS ); if ( lResult == ERROR_SUCCESS) { // now the key is ours, oh, yes... it is ours...
// set the value of the internet settings key used by Code Download.
int cchCacheDir = lstrlen(szCacheDir); TCHAR szCacheDirOld[MAX_PATH]; DWORD dwType = REG_SZ; DWORD cbOldCache = MAX_PATH;
// Don't fail if we can't quite hook up with legacy caches
hr = S_OK;
// Add our old cache path, if any, to the cache path list if it differs from our new cache.
lResult = RegQueryValueEx( hkeyIS, REG_OCX_CACHE_VALUE_NAME, 0, &dwType, (LPBYTE)szCacheDirOld, &cbOldCache ); if ( lResult == ERROR_SUCCESS && dwType == REG_SZ && lstrcmpi( szCacheDirOld, szCacheDir ) != 0 ) AddCacheToRegPathList( hkeyIS, szCacheDirOld, cbOldCache - 1 );
// Under NT, IE3 might not have been able to write the old cache path, so we'll cobble one up
// and add it if that dir is present.
if ( SUCCEEDED(GetWindowsDirectory( szCacheDirOld, MAX_PATH )) ) { cbOldCache = lstrlen( szCacheDirOld ); if ( cbOldCache && (szCacheDirOld[cbOldCache-1] != '\\')) lstrcat(szCacheDirOld, "\\"); cbOldCache = lstrlen(lstrcat( szCacheDirOld, REG_OCX_OLD_CACHE_DIR ));
if (PathFileExists(szCacheDirOld)) { // Let's not fail if this doesn't work
AddCacheToRegPathList( hkeyIS, szCacheDirOld, cbOldCache ); CreateShellFolderPath( szCacheDirOld, STRING_CLSID_CONTROLFOLDER ); } } if ( SUCCEEDED(hr) ) { lResult = RegSetValueEx( hkeyIS, REG_OCX_CACHE_VALUE_NAME, 0, REG_SZ, (LPBYTE)szCacheDir, cchCacheDir + 1 ); // need '\0'
if ( lResult == ERROR_SUCCESS ) { // add the new (?) path to the collection of valid paths which are the
// values for the cache subkey.
hr = AddCacheToRegPathList( hkeyIS, szCacheDir, cchCacheDir ); } else hr = HRESULT_FROM_WIN32(lResult); }
RegCloseKey( hkeyIS );
} else hr = HRESULT_FROM_WIN32(lResult); return hr; }
STDAPI InitCacheFolder(void) { HRESULT hr = E_FAIL; TCHAR szCacheDir[MAX_PATH];
// Compose the default path.
GetControlFolderPath(szCacheDir, MAX_PATH); // Okay, now we know where we want to put things.
// Create the directory, and/or claim it as our own
hr = CreateShellFolderPath( szCacheDir, STRING_CLSID_CONTROLFOLDER ); if ( SUCCEEDED(hr) ) { hr = SetCacheRegEntries( szCacheDir ); }
return hr; }
STDAPI DllUnregisterServer(void) { // Remove a bunch of stuff from the registry.
//
CallRegInstall("Unreg");
return NOERROR; }
STDAPI DllRegisterServer(void) { //
// Add a bunch of stuff to the registry.
//
if (FAILED(CallRegInstall("Reg"))) { goto CleanUp; }
return NOERROR;
CleanUp: // cleanup stuff if any of our reg stuff fails
DllUnregisterServer(); return E_FAIL; }
STDAPI DllInstall(BOOL bInstall, LPCWSTR pszCmdLine) { HRESULT hr = S_OK;
if ( bInstall ) { hr =InitCacheFolder(); if ( SUCCEEDED(hr) ) CanonicalizeModuleUsage(); } else { LONG lResult; HKEY hkeyCacheList;
// Unhook occache as a shell extension for the cache folders.
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_PATH_IE_CACHE_LIST, 0x0, KEY_ALL_ACCESS, &hkeyCacheList );
if ( lResult == ERROR_SUCCESS ) { DWORD dwIndex; TCHAR szName[MAX_PATH]; DWORD cbName; TCHAR szValue[MAX_PATH]; DWORD cbValue;
for ( dwIndex = 0, cbName = sizeof(szName), cbValue = sizeof(szValue); lResult == ERROR_SUCCESS; dwIndex++, cbName = sizeof(szName), cbValue = sizeof(szValue) ) { lResult = RegEnumValue( hkeyCacheList, dwIndex, szName, &cbName, NULL, NULL, (LPBYTE)szValue, &cbValue );
if ( lResult == ERROR_SUCCESS && PathFileExists(szValue) ) CleanupShellFolder(szValue); } // We leave this key in place because it is the only record we have of the
// cache folders and would be useful to future installations of IE
RegCloseKey( hkeyCacheList ); } }
return hr; }
// we use shlwapi as our delayload error handler.
// NOTE: this only works if we are statically linked to shlwapi!
void SetupDelayloadErrorHandler() { BaseDllHandle = GetModuleHandleA("shlwapi.dll"); ASSERTMSG(BaseDllHandle != NULL, "OCCACHE must be statically linked to shlwapi.dll for delayload failure handling to work!"); __pfnDliFailureHook = (PfnDliHook)GetProcAddress((HMODULE)BaseDllHandle, "DelayLoadFailureHook"); }
STDAPI_(BOOL) DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID dwReserved) { if (dwReason == DLL_PROCESS_ATTACH) { HKEY hkeyTest;
g_hInst = hInst; DisableThreadLibraryCalls(g_hInst);
SetupDelayloadErrorHandler();
MLLoadResources(g_hInst, TEXT("occachlc.dll")); // Test to see if we have permissions to modify HKLM subkeys.
// We'll use this as an early test to see if we can remove controls.
if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_PATH_IE_SETTINGS, 0x0, KEY_ALL_ACCESS, &hkeyTest ) == ERROR_SUCCESS ) { g_fAllAccess = TRUE; RegCloseKey( hkeyTest ); } } else if (dwReason == DLL_PROCESS_DETACH) { MLFreeResources(g_hInst); } return TRUE; }
typedef struct { const IClassFactoryVtbl *cf; const CLSID *pclsid; HRESULT (STDMETHODCALLTYPE *pfnCreate)(IUnknown *, REFIID, void **); } OBJ_ENTRY;
extern const IClassFactoryVtbl c_CFVtbl; // forward
//
// we always do a linear search here so put your most often used things first
//
const OBJ_ENTRY c_clsmap[] = { { &c_CFVtbl, &CLSID_ControlFolder, ControlFolder_CreateInstance }, { &c_CFVtbl, &CLSID_EmptyControlVolumeCache, EmptyControl_CreateInstance }, // add more entries here
{ NULL, NULL, NULL } };
// static class factory (no allocs!)
STDMETHODIMP CClassFactory_QueryInterface(IClassFactory *pcf, REFIID riid, void **ppvObj) { if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) { *ppvObj = (void *)pcf; } else { *ppvObj = NULL; return E_NOINTERFACE; } DllAddRef(); return NOERROR; }
STDMETHODIMP_(ULONG) CClassFactory_AddRef(IClassFactory *pcf) { DllAddRef(); return 2; }
STDMETHODIMP_(ULONG) CClassFactory_Release(IClassFactory *pcf) { DllRelease(); return 1; }
STDMETHODIMP CClassFactory_CreateInstance(IClassFactory *pcf, IUnknown *punkOuter, REFIID riid, void **ppvObject) { OBJ_ENTRY *this = IToClass(OBJ_ENTRY, cf, pcf); return this->pfnCreate(punkOuter, riid, ppvObject); }
STDMETHODIMP CClassFactory_LockServer(IClassFactory *pcf, BOOL fLock) { if (fLock) DllAddRef(); else DllRelease(); return S_OK; }
const IClassFactoryVtbl c_CFVtbl = { CClassFactory_QueryInterface, CClassFactory_AddRef, CClassFactory_Release, CClassFactory_CreateInstance, CClassFactory_LockServer };
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) { if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) { const OBJ_ENTRY *pcls; for (pcls = c_clsmap; pcls->pclsid; pcls++) { if (IsEqualIID(rclsid, pcls->pclsid)) { *ppv = (void *)&(pcls->cf); DllAddRef(); // Class Factory keeps dll in memory
return NOERROR; } } } // failure
*ppv = NULL; return CLASS_E_CLASSNOTAVAILABLE;; }
STDAPI_(void) DllAddRef() { InterlockedIncrement(&g_cRefDll); }
STDAPI_(void) DllRelease() { ASSERT( 0 != g_cRefDll ); InterlockedDecrement(&g_cRefDll); }
STDAPI DllCanUnloadNow(void) { return g_cRefDll == 0 ? S_OK : S_FALSE; }
|