windows-nt/Source/XPSP1/NT/shell/ext/occache/init.c
2020-09-26 16:20:57 +08:00

520 lines
16 KiB
C

#include "init.h"
#include "global.h"
#include <shlwapi.h> // for DllInstall prototype
#define MLUI_INIT
#include <mluisupp.h>
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;
}
STDAPI_(BOOL) DllMain(HINSTANCE hInst, DWORD dwReason, LPVOID dwReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
HKEY hkeyTest;
g_hInst = hInst;
DisableThreadLibraryCalls(g_hInst);
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()
{
InterlockedDecrement(&g_cRefDll);
}
STDAPI DllCanUnloadNow(void)
{
return g_cRefDll == 0 ? S_OK : S_FALSE;
}