|
|
// ===========================================================================
// File: CDLAPI.CXX
// The main code downloader api file.
//
#include <cdlpch.h>
#include <mshtmhst.h>
#include <shlwapi.h>
#include <inseng.h>
// globals for code downloader
CMutexSem g_mxsCodeDownloadGlobals;
LCID g_lcidBrowser = 0x409; // default to english
char g_szBrowserLang[20]; int g_lenBrowserLang = 20; char g_szBrowserPrimaryLang[20]; int g_lenBrowserPrimaryLang = 20;
// Use SetupApi by default!
DWORD g_dwCodeDownloadSetupFlags = CDSF_USE_SETUPAPI;
char g_szOCXCacheDir[MAX_PATH]; char g_szOCXTempDir[MAX_PATH]; int g_OCXCacheDirSize = 0; static BOOL g_fHaveCacheDir = FALSE;
BOOL g_OSInfoInitialized = FALSE; int g_CPUType = PROCESSOR_ARCHITECTURE_UNKNOWN; // default
BOOL g_fRunningOnNT = FALSE; BOOL g_bRunOnWin95 = FALSE; #ifdef WX86
BOOL g_fWx86Present; // Set if running on RISC and Wx86 is installed
#endif
BOOL g_bLockedDown = FALSE;
// New default name for ActiveX cache folder! We only use this if occache fails to set up the cache folder.
// const static char *g_szOCXDir = "OCCACHE";
const char *g_szOCXDir = "Downloaded Program Files"; const char *g_szActiveXCache = "ActiveXCache"; const char *g_szRegKeyActiveXCache = "ActiveX Cache";
// This is the client platform specific location name that we look for in INF
// and is built by concatenating g_szProcessorTypes at end of g_szLocPrefix
char g_szPlatform[17]; // sizeof("file-win32-alpha"), (longest possible)
static char *g_szLocPrefix="file-win32-"; // directly indexed into with PROCESSOR_ARCH* returned by GetSystemInfo..
// The "" ones are those we don't support.
char *g_szProcessorTypes[] = { "x86", "", "", "", "", "", "ia64", "", "", "amd64" };
// used for Accept Types doing http based platform independence
// use alpha as the longest of possible g_szProcessorTypes strings
static char *g_szCABAcceptPrefix = "application/x-cabinet-win32-"; static char *g_szPEAcceptPrefix = "application/x-pe-win32-";
// Name of dll that implements ActiveX control cache shell extension
const char *g_szActiveXCacheDll = "occache.dll";
// list that goes into accept types
// this first 2 left null to substitue with strings for this platform (cab, pe)
// the number of media types are are registering as Accept types for
// HTTP based contente negotiation
#ifdef WX86
#define CDL_NUM_TYPES 7
#else
#define CDL_NUM_TYPES 5
#endif
LPSTR g_rgszMediaStr[CDL_NUM_TYPES] = { CFSTR_MIME_NULL, CFSTR_MIME_NULL, CFSTR_MIME_RAWDATASTRM, "application/x-setupscript", "*/*", #ifdef WX86
CFSTR_MIME_NULL, CFSTR_MIME_NULL, #endif
};
CLIPFORMAT g_rgclFormat[CDL_NUM_TYPES];
FORMATETC g_rgfmtetc[CDL_NUM_TYPES];
IEnumFORMATETC *g_pEFmtETC;
extern COleAutDll g_OleAutDll;
typedef HRESULT (STDAPICALLTYPE *PFNCOINSTALL)( IBindCtx *pbc, DWORD dwFlags, uCLSSPEC *pClassSpec, QUERYCONTEXT *pQuery, LPWSTR pszCodeBase);
PFNCOINSTALL g_pfnCoInstall=NULL; BOOL g_bCheckedForCoInstall=FALSE; HMODULE g_hOLE32 = 0; BOOL g_bUseOLECoInstall = FALSE;
HRESULT GetClassFromExt(LPSTR pszExt, CLSID *pclsid);
STDAPI WrapCoInstall ( REFCLSID rCLASSID, // CLSID of object (may be NULL)
LPCWSTR szCODE, // URL to code (may be NULL)
DWORD dwFileVersionMS, // Version of primary object
DWORD dwFileVersionLS, // Version of primary object
LPCWSTR szTYPE, // MIME type (may be NULL)
LPBINDCTX pBindCtx, // Bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
DWORD flags );
#define WRAP_OLE32_COINSTALL
STDAPI PrivateCoInstall( IBindCtx *pbc, DWORD dwFlags, uCLSSPEC *pClassSpec, QUERYCONTEXT *pQuery, LPWSTR pszCodeBase);
/*
* RegisterNewActiveXCacheFolder * change default ActiveX Cache path to lpszNewPath and properly * updates all registry entries */ /*
LONG RegisterNewActiveXCacheFolder(LPCTSTR lpszNewPath, DWORD dwPathLen) { Assert(lpszNewPath != NULL && lpszNewPath[0] != '\0'); if (lpszNewPath == NULL || lpszNewPath[0] == '\0') return ERROR_BAD_ARGUMENTS;
LONG lResult = ERROR_SUCCESS; HKEY hkeyIntSetting = NULL; HKEY hkeyActiveXCache = NULL; char szOldPath[MAX_PATH]; char szPath[MAX_PATH]; char szSubKey[MAX_PATH]; DWORD dwLen = MAX_PATH; DWORD dwKeyLen = MAX_PATH; DWORD dwIndex = 0; BOOL fOldFound = FALSE; BOOL fNewFound = FALSE; BOOL fEqual = FALSE; LONG lValueIndex = -1;
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0, KEY_ALL_ACCESS, &hkeyIntSetting); if (lResult != ERROR_SUCCESS) goto Exit;
// read ActiveXCache
lResult = RegQueryValueEx( hkeyIntSetting, g_szActiveXCache, NULL, NULL, (LPBYTE)szOldPath, &dwLen);
if (lResult != ERROR_SUCCESS) { fOldFound = TRUE; szOldPath[0] = '\0'; }
fEqual = (lstrcmpi(lpszNewPath, szOldPath) == 0);
lResult = RegSetValueEx( hkeyIntSetting, g_szActiveXCache, 0, REG_SZ, (LPBYTE)lpszNewPath, dwPathLen); if (lResult != ERROR_SUCCESS) goto Exit;
// 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.
lResult = RegCreateKey( hkeyIntSetting, g_szRegKeyActiveXCache, &hkeyActiveXCache); if (lResult != ERROR_SUCCESS) goto Exit;
for (dwLen = dwKeyLen = MAX_PATH; lResult == ERROR_SUCCESS; dwLen = dwKeyLen = MAX_PATH) { lResult = RegEnumValue( hkeyActiveXCache, dwIndex++, szSubKey, &dwKeyLen, NULL, NULL, (LPBYTE)szPath, &dwLen);
if (lResult == ERROR_SUCCESS) { // for find new unique value name later.
lValueIndex = max(lValueIndex, atol(szSubKey));
if (!fNewFound) fNewFound = (lstrcmpi(lpszNewPath, szPath) == 0); if (!fOldFound) fOldFound = (lstrcmpi(szOldPath, szPath) == 0); } }
// something goes wrong!
if (lResult != ERROR_NO_MORE_ITEMS) goto Exit;
// Add lpszNewPath to the list of paths
lResult = ERROR_SUCCESS;
// keep registry intact
if (!fOldFound && szOldPath[0] != '\0') { wsprintf(szSubKey, "%i", ++lValueIndex); lResult = RegSetValueEx( hkeyActiveXCache, szSubKey, 0, REG_SZ, (LPBYTE)szOldPath, lstrlen(szOldPath) + 1); }
// add new path to list of paths
if (lResult == ERROR_SUCCESS && !fNewFound && !fEqual) { wsprintf(szSubKey, "%i", ++lValueIndex); lResult = RegSetValueEx( hkeyActiveXCache, szSubKey, 0, REG_SZ, (LPBYTE)lpszNewPath, dwPathLen); }
Exit:
// restore old state if failed
if (lResult != ERROR_SUCCESS) { if (szOldPath[0] == '\0') RegDeleteValue(hkeyIntSetting, g_szActiveXCache); else RegSetValueEx( hkeyIntSetting, g_szActiveXCache, 0, REG_SZ, (LPBYTE)lpszNewPath, dwPathLen); }
if (hkeyActiveXCache != NULL) RegCloseKey(hkeyActiveXCache);
if (hkeyIntSetting != NULL) RegCloseKey(hkeyIntSetting);
return lResult; }
LONG SwitchToNewCachePath(LPCSTR lpszNewPath, DWORD dwPathLen) { Assert(lpszNewPath != NULL); if (lpszNewPath == NULL) return ERROR_BAD_ARGUMENTS;
LONG lResult = ERROR_SUCCESS; char szKey[MAX_PATH]; char szPath[MAX_PATH]; char *pCh = NULL; HKEY hkey = NULL; DWORD dwIndex = 0; DWORD dwLen = MAX_PATH;
wsprintf(szKey, "%s\\%s", REGSTR_PATH_IE_SETTINGS, g_szRegKeyActiveXCache);
lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szKey, 0, KEY_ALL_ACCESS, &hkey);
for (; lResult == ERROR_SUCCESS; dwLen = MAX_PATH) { lResult = RegEnumValue( hkey, dwIndex++, szKey, &dwLen, NULL, NULL, (LPBYTE)szPath, &dwLen);
if (lResult == ERROR_SUCCESS && lstrcmpi(szPath, lpszNewPath) == 0) break; }
RegCloseKey(hkey);
if (lResult != ERROR_SUCCESS) return RegisterNewActiveXCacheFolder(lpszNewPath, dwPathLen);
// return fail to indicate that path has not been changed to
// Downloaded ActiveX Controls
return HRESULT_CODE(E_FAIL); } */
HRESULT SetCoInstall() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "SetCoInstall", NULL )); HKEY hKeyIESettings = 0;
//execute entire function under critical section
CLock lck(g_mxsCodeDownloadGlobals);
if (!g_bCheckedForCoInstall && !g_pfnCoInstall) { // So we don't keep rechecking for this api.
g_bCheckedForCoInstall = TRUE;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0, KEY_READ, &hKeyIESettings) == ERROR_SUCCESS) { if (RegQueryValueEx(hKeyIESettings, REGVAL_USE_COINSTALL, NULL, NULL, NULL, 0) != ERROR_SUCCESS) {
g_bUseOLECoInstall = FALSE; g_pfnCoInstall = NULL;
RegCloseKey(hKeyIESettings);
DEBUG_LEAVE(S_OK); return S_OK; }
RegCloseKey(hKeyIESettings); } // find CoInstall entry point in OLE32
if (!g_hOLE32) { // BUGBUG: We never FreeLibrary on this. Realisticly, someone else will probably already be using this
// and it will be in use throughout the life of the process, so we won't worry too much.
g_hOLE32 = LoadLibraryA("ole32.dll"); }
if(g_hOLE32 != 0) { void *pfn = GetProcAddress(g_hOLE32, "CoInstall"); if(pfn != NULL) { g_bUseOLECoInstall = TRUE; g_pfnCoInstall = (PFNCOINSTALL) pfn; } } }
DEBUG_LEAVE(S_OK); return S_OK; }
VOID DetermineOSAndCPUVersion() { DEBUG_ENTER((DBG_DOWNLOAD, None, "DetermineOSAndCPUVersion", NULL )); OSVERSIONINFO osvi; SYSTEM_INFO sysinfo;
//execute entire function under critical section
CLock lck(g_mxsCodeDownloadGlobals);
if (g_OSInfoInitialized) {
DEBUG_LEAVE(0); return; }
// Determine which version of NT we're running on
osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi);
g_fRunningOnNT = (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId);
if (osvi.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS && osvi.dwMinorVersion == 0) { g_bRunOnWin95 = TRUE; } else { g_bRunOnWin95 = FALSE; }
#ifdef WX86
if (g_bNT5OrGreater) { //
// The pre-alpha Wx86 that runs on NT 4.0 does not support
// x86 ActiveX controls inside a RISC host. Only call Wx86
// on NT 5.0 machines.
//
HKEY hKey; LONG Error;
// Temp hack: allow users to disable Wx86 support in URLMON if this
// key is present.
// bugbug: probably rip this before ship.
Error = ::RegOpenKeyW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\Wx86\\DisableCDL", &hKey);
if (Error == ERROR_SUCCESS) { ::RegCloseKey(hKey); } else { g_fWx86Present = TRUE; } } #endif // WX86
GetSystemInfo(&sysinfo);
switch(sysinfo.wProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_INTEL: case PROCESSOR_ARCHITECTURE_AMD64: case PROCESSOR_ARCHITECTURE_IA64:
g_CPUType = sysinfo.wProcessorArchitecture; break;
case PROCESSOR_ARCHITECTURE_UNKNOWN: default: g_CPUType = PROCESSOR_ARCHITECTURE_UNKNOWN; break; }
g_OSInfoInitialized = TRUE; DEBUG_LEAVE(0); }
/*
* SetGlobals * set all the globals for the Code Downloader * called from AsyncGetClassBits. executes under a crit section */
HRESULT SetGlobals() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "SetGlobals", NULL )); SYSTEM_INFO sysinfo; int nCPUType; HRESULT hr = S_OK; DWORD lResult; // static const char szActiveXCache[] = "ActiveXCache";
BOOL fRegActiveXCacheDll = FALSE; // do we need to register occache.dll?
//execute entire function under critical section
CLock lck(g_mxsCodeDownloadGlobals);
if (!g_fHaveCacheDir) {
// do some init: get ocx ccahe dir
DWORD Size = MAX_PATH; DWORD dwType; HKEY hKeyIESettings = 0; char szOldCacheDir[MAX_PATH]; int len = 0; int CdlNumTypes;
lResult = ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0, KEY_READ, &hKeyIESettings );
if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
// Get Code Download flags
dwType = REG_DWORD; Size = sizeof(DWORD); lResult = ::RegQueryValueEx(hKeyIESettings, "CodeDownloadFlags", NULL, &dwType, (unsigned char *)&g_dwCodeDownloadSetupFlags, &Size); Size = MAX_PATH; dwType = REG_SZ;
// Get existing cache path from registry
lResult = ::RegQueryValueEx(hKeyIESettings, g_szActiveXCache, NULL, &dwType, (unsigned char *)g_szOCXCacheDir, &Size);
if (lResult != ERROR_SUCCESS || !PathFileExists( g_szOCXCacheDir ) ) { // OC Cache didn't set up the registry for us...
// Load it to make sure it has done if regsvring work...
HRESULT hr = E_FAIL; HINSTANCE h = LoadLibrary(g_szActiveXCacheDll); HRESULT (STDAPICALLTYPE *pfnReg)(void); HRESULT (STDAPICALLTYPE *pfnInst)(BOOL bInstall, LPCWSTR pszCmdLine); if (h != NULL) { (FARPROC&)pfnReg = GetProcAddress(h, "DllRegisterServer"); if (pfnReg != NULL) hr = (*pfnReg)();
// also need to call DllInstall to complete the wiring of the shell extension
(FARPROC&)pfnInst = GetProcAddress(h, "DllInstall"); if (pfnInst != NULL) hr = (*pfnInst)( TRUE, L"");
FreeLibrary(h); }
// Retry now that we're sure OCCACHE has had a shot at setting things up for us
if ( SUCCEEDED(hr) ) lResult = ::RegQueryValueEx(hKeyIESettings, g_szActiveXCache, NULL, &dwType, (unsigned char *)g_szOCXCacheDir, &Size); if ( lResult != ERROR_SUCCESS ) { // OC Cache is having a bad day. Don't let this stop code download.
// Compose the default path and see if we need to change
// old cache path to the new default path.
if(!(len = GetWindowsDirectory(g_szOCXCacheDir, MAX_PATH))) g_szOCXCacheDir[0] = '\0'; else { Assert(len <= MAX_PATH); if (g_szOCXCacheDir[len-1] != '\\') lstrcat(g_szOCXCacheDir, "\\"); } StrNCat(g_szOCXCacheDir, g_szOCXDir,MAX_PATH-len-2); // OC Cache or not, remember our directory
HKEY hkeyWriteIESettings; if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS,0, KEY_ALL_ACCESS, &hkeyWriteIESettings ) == ERROR_SUCCESS) {
RegSetValueEx(hkeyWriteIESettings,g_szActiveXCache,0,REG_SZ, (LPBYTE)g_szOCXCacheDir, lstrlen(g_szOCXCacheDir) + 1);
RegCloseKey(hkeyWriteIESettings); }
}
// load oleaut32.dll
lResult = g_OleAutDll.Init();
} // if reg key not set up.
if (hKeyIESettings) { RegCloseKey(hKeyIESettings); hKeyIESettings = 0; }
DWORD dwAttr = GetFileAttributes(g_szOCXCacheDir);
if (dwAttr == -1) { if (!CreateDirectory(g_szOCXCacheDir, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
// if cache dir has just been created, we also need
// to register occache shell extension
fRegActiveXCacheDll = TRUE; } else { if ( (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) || (dwAttr & FILE_ATTRIBUTE_READONLY)) { hr = OLE_E_NOCACHE; // closest we can get to!
goto Exit; } }
if (!GetTempPath(MAX_PATH, g_szOCXTempDir) ) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
// Set up g_bRunningOnNT, g_CpuType, and g_fWx86Present
DetermineOSAndCPUVersion();
// Record client architecture to make proper accept types
// and to use in INF for platform independent CODE=URL
LPSTR pBaseFileName = NULL; InitBrowserLangStrings();
nCPUType = g_CPUType; if (g_CPUType == PROCESSOR_ARCHITECTURE_UNKNOWN) { nCPUType = PROCESSOR_ARCHITECTURE_INTEL; }
lstrcpy(g_szPlatform, g_szLocPrefix); lstrcat(g_szPlatform, g_szProcessorTypes[nCPUType]);
// Register the Media types
// first build up the table of eight types we send out
char szCABStr[MAX_PATH]; char szPEStr[MAX_PATH];
lstrcpy(szCABStr, g_szCABAcceptPrefix); lstrcat(szCABStr, g_szProcessorTypes[nCPUType]); lstrcpy(szPEStr, g_szPEAcceptPrefix); lstrcat(szPEStr, g_szProcessorTypes[nCPUType]);
g_rgszMediaStr[0] = szCABStr; g_rgszMediaStr[1] = szPEStr;
#ifdef WX86
char szCABStrX86[MAX_PATH]; char szPEStrX86[MAX_PATH];
if (g_fWx86Present) { g_rgszMediaStr[6] = g_rgszMediaStr[4]; // move "*/*" to the end of the list
lstrcpy(szCABStrX86, g_szCABAcceptPrefix); lstrcat(szCABStrX86, g_szProcessorTypes[PROCESSOR_ARCHITECTURE_INTEL]); lstrcpy(szPEStrX86, g_szPEAcceptPrefix); lstrcat(szPEStrX86, g_szProcessorTypes[PROCESSOR_ARCHITECTURE_INTEL]);
g_rgszMediaStr[4] = szCABStrX86; g_rgszMediaStr[5] = szPEStrX86;
CdlNumTypes = CDL_NUM_TYPES; } else { CdlNumTypes = CDL_NUM_TYPES-2; } #else
CdlNumTypes = CDL_NUM_TYPES; #endif
hr = RegisterMediaTypes(CdlNumTypes, (const LPCSTR *)g_rgszMediaStr, g_rgclFormat);
if (FAILED(hr)) goto Exit;
// initialize the formatetc array
for (int i=0; i< CdlNumTypes; i++) { g_rgfmtetc[i].cfFormat = g_rgclFormat[i]; g_rgfmtetc[i].tymed = TYMED_NULL; g_rgfmtetc[i].dwAspect = DVASPECT_CONTENT; g_rgfmtetc[i].ptd = NULL; }
// BUGBUG: leaked!
hr = CreateFormatEnumerator(CdlNumTypes, g_rgfmtetc, &g_pEFmtETC); if (FAILED(hr)) goto Exit;
if (g_bNT5OrGreater) { HKEY hkeyLockedDown = 0;
// Test for lock-down. If we cannot write to HKLM, then we are in
// a locked-down environment, and should abort right away.
if (RegCreateKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_NT5_LOCKDOWN_TEST, &hkeyLockedDown) != ERROR_SUCCESS) { // We are in lock-down mode; abort.
g_bLockedDown = TRUE; } else { // Not locked-down. Delete the key, and continue
RegCloseKey(hkeyLockedDown); RegDeleteKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_NT5_LOCKDOWN_TEST); g_bLockedDown = FALSE; } }
g_fHaveCacheDir = TRUE; }
Exit:
if (FAILED(hr)) { UrlMkDebugOut((DEB_CODEDL, "ERR CodeDownload failed to initialize: hr(%lx)\n", hr)); }
DEBUG_LEAVE(hr); return hr; }
#define CLSID_ActiveXPlugin \
{0x06DD38D3L,0xD187,0x11CF, \ {0xA8,0x0D,0x00,0xC0,0x4F,0xD7,0x4A,0xD8}}
//
// FindPlugin - delegates this call to the plugin OCX
//
BOOL FindPlugin(char *szFileExt, char *szName, char *szMime) { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "FindPlugin", "%.80q, %.80q, %.80q", szFileExt, szName, szMime )); typedef BOOL (WINAPI *LPFINDPLUGIN_API)(char *ext, char *name, char *mime); LPFINDPLUGIN_API pfnFindPlugin; BOOL fRet = FALSE;
HMODULE hLib = LoadLibrary("plugin.ocx"); if (hLib == NULL) { goto Exit; }
pfnFindPlugin = (LPFINDPLUGIN_API)GetProcAddress(hLib, "FindPluginA"); if (pfnFindPlugin == NULL) { goto Exit; }
fRet = pfnFindPlugin(szFileExt, szName, szMime);
Exit:
if (hLib) FreeLibrary(hLib);
DEBUG_LEAVE(fRet); return fRet; }
// GetClsidFromExtOrMime
// fills up clsidout with rCLASSID if not CLSID_NULL
// or gets clsid from passed in ext or mime type
// returns:
// S_OK
// S_FALSE: couldn't convert to a clsid
HRESULT GetClsidFromExtOrMime( REFCLSID rclsid, CLSID &clsidout, LPCWSTR szExt, LPCWSTR szTYPE, LPSTR *ppFileName) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "GetClsidFromExtOrMime", "%#x, %#x, %.80wq, %.80wq, %#x", &rclsid, &clsidout, szExt, szTYPE, ppFileName )); BOOL fNullClsid; HRESULT hr = S_OK; char szTypeA[MAX_PATH]; char szExtA[MAX_PATH]; LPSTR lpName = NULL;
memcpy(&clsidout, &rclsid, sizeof(GUID));
if ((fNullClsid = IsEqualGUID(rclsid , CLSID_NULL))) {
if (!szTYPE && !szExt) { hr = S_FALSE; goto Exit; }
if (szTYPE) { if (!WideCharToMultiByte(CP_ACP, 0 , szTYPE , -1 ,szTypeA, MAX_PATH, NULL, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
// convert the mime/type into a clsid
if (SUCCEEDED((GetClassMime(szTypeA, &clsidout)))) { fNullClsid = FALSE; }
} else { // szExt
if (!WideCharToMultiByte(CP_ACP, 0 , szExt , -1 ,szExtA, MAX_PATH, NULL, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
if (SUCCEEDED(GetClassFromExt(szExtA, &clsidout))) { fNullClsid = FALSE; }
}
}
Exit:
if ((hr == S_OK) && fNullClsid) {
// still no clsid
char szName[MAX_PATH]; BOOL bRet = FindPlugin(szExtA, szName, szTypeA);
if (bRet) {
// found a plugin, instantiate the plugin ocx
CLSID plug = CLSID_ActiveXPlugin; clsidout = plug;
if (ppFileName) {
lpName = new char [lstrlen(szName) + 1];
if (lpName) lstrcpy(lpName, szName); else hr = E_OUTOFMEMORY; }
} else {
// not a plugin either!
hr = S_FALSE; } }
if (ppFileName) { *ppFileName = lpName; }
DEBUG_LEAVE(hr); return hr; }
//BUGBUG this must be defined in a public header. Is currently in ole32\ih\ole2com.h.
#if defined(_X86_)
#define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_INTEL
#elif defined(_AMD64_)
#define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_AMD64
#elif defined(_IA64_)
#define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_IA64
#else
#define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_UNKNOWN
#endif
//+-------------------------------------------------------------------------
//
// Function: GetDefaultPlatform (internal)
//
// Synopsis: Gets the current platform
//
// Returns: none
//
//--------------------------------------------------------------------------
void GetDefaultPlatform(CSPLATFORM *pPlatform) { DEBUG_ENTER((DBG_DOWNLOAD, None, "GetDefaultPlatform", "%#x", pPlatform )); OSVERSIONINFO VersionInformation;
VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&VersionInformation);
pPlatform->dwPlatformId = VersionInformation.dwPlatformId; pPlatform->dwVersionHi = VersionInformation.dwMajorVersion; pPlatform->dwVersionLo = VersionInformation.dwMinorVersion; pPlatform->dwProcessorArch = DEFAULT_ARCHITECTURE;
DEBUG_LEAVE(0); }
//+-------------------------------------------------------------------------
//
// Function: GetActiveXSafetyProvider (internal)
//
// Synopsis: Gets the ActiveXSafetyProvider, if there is one installed.
//
// Returns: none
//
//--------------------------------------------------------------------------
HRESULT GetActiveXSafetyProvider(IActiveXSafetyProvider **ppProvider) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "GetActiveXSafetyProvider", "%#x", ppProvider )); HRESULT hr; LONG l; HKEY hKey;
//
// See if an IActiveXSafetyProvider is present by peeking into the
// registry.
//
l = RegOpenKeyA(HKEY_CLASSES_ROOT, "CLSID\\{aaf8c6ce-f972-11d0-97eb-00aa00615333}", &hKey ); if (l != ERROR_SUCCESS) { //
// No ActiveXSafetyProvider installed.
//
*ppProvider = NULL; DEBUG_LEAVE(S_OK); return S_OK; } RegCloseKey(hKey);
//
// Call OLE to instantiate the ActiveXSafetyProvider.
//
hr = CoCreateInstance(CLSID_IActiveXSafetyProvider, NULL, CLSCTX_INPROC_SERVER, IID_IActiveXSafetyProvider, (void **)ppProvider ); DEBUG_LEAVE(hr); return hr; }
#ifdef WRAP_OLE32_COINSTALL
// This currently breaks trident for unknown reasons.
// For full class store integration (Darwin packages) this will need to be enabled!!!
// ===========================================================================
// CBSCCreateObject Implementation
// ===========================================================================
class CBSCCreateObject : public IServiceProvider, public IBindStatusCallback { private: DWORD m_cRef;
CLSID m_clsid; LPWSTR m_szExt; LPWSTR m_szType; DWORD m_dwClsContext; IID m_riid; IBindStatusCallback* m_pclientbsc; //IBindCtx* m_pbc;
CRITICAL_SECTION m_sect; LPVOID m_pvReserved; BOOL m_bObjectAvailableCalled; DWORD m_dwFlags;
public: CBSCCreateObject(REFCLSID rclsid, LPCWSTR szType, LPCWSTR szExt, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, IBindCtx* pbc, DWORD dwFlags, HRESULT &hr) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CBSCCreateObject::CBSCCreateObject", "this=%#x, %#x, %.80wq, %.80wq, %#x, %#x, %#x, %#x, %#x, %#x", this, &rclsid, szType, szExt, dwClsContext, pvReserved, &riid, pbc, dwFlags, &hr )); InitializeCriticalSection(&m_sect); m_cRef=1; m_clsid=rclsid; m_dwClsContext=dwClsContext; m_pvReserved=pvReserved; m_riid=riid; //m_pbc=NULL;
m_pclientbsc=NULL; m_bObjectAvailableCalled=FALSE;
m_dwFlags = dwFlags;
if ( szType != NULL ) { m_szType = new WCHAR[lstrlenW(szType) + 1]; if ( m_szType != NULL ) StrCpyW( m_szType, szType ); else hr = E_OUTOFMEMORY; } else m_szType = NULL;
if ( szExt != NULL ) { m_szExt = new WCHAR[lstrlenW(szExt) + 1]; if ( m_szExt != NULL ) StrCpyW( m_szExt, szExt ); else hr = E_OUTOFMEMORY; } else m_szExt = NULL;
if ( SUCCEEDED(hr) ) { // Get client's BSC and store away for delegation
hr=RegisterBindStatusCallback(pbc, (IBindStatusCallback*) this, &m_pclientbsc, NULL); if (SUCCEEDED(hr)) { if (m_pclientbsc) { //m_pbc=pbc;
//m_pbc->AddRef();
} else { hr=E_INVALIDARG; // need BSC in bind context!
} } }
DEBUG_LEAVE(0); }
~CBSCCreateObject() { DEBUG_ENTER((DBG_DOWNLOAD, None, "CBSCCreateObject::~CBSCCreateObject", "this=%#x", this )); //RevokeFromBC();
if ( m_szType != NULL ) delete m_szType;
if ( m_szExt != NULL ) delete m_szExt;
if (m_pclientbsc) { IBindStatusCallback* pclientbsc=m_pclientbsc; m_pclientbsc=NULL; pclientbsc->Release(); } DeleteCriticalSection(&m_sect);
DEBUG_LEAVE(0); }
IBindStatusCallback* GetClientBSC() { DEBUG_ENTER((DBG_DOWNLOAD, Pointer, "CBSCCreateObject::GetClientBSC", "this=%#x", this )); EnterCriticalSection(&m_sect); IBindStatusCallback* pbsc=m_pclientbsc; LeaveCriticalSection(&m_sect); DEBUG_LEAVE(pbsc); return pbsc; }
/* HRESULT RevokeFromBC()
{ // Remove from BSC and reestablish original BSC
HRESULT hr=S_OK;
EnterCriticalSection(&m_sect); if (m_pbc) { IBindCtx* pbc=m_pbc; IBindStatusCallback* pclientbsc=m_pclientbsc; m_pbc=NULL; m_pclientbsc=NULL; LeaveCriticalSection(&m_sect);
hr=RegisterBindStatusCallback(pbc, pclientbsc, NULL, NULL); pbc->Release(); if (pclientbsc) { pclientbsc->Release(); } } else { LeaveCriticalSection(&m_sect); } return hr; } */ STDMETHODIMP QueryInterface(REFIID riid, void** ppv) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IUnknown::QueryInterface", "this=%#x, %#x, %#x", this, &riid, ppv )); HRESULT hr = S_OK;
*ppv = NULL;
if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IBindStatusCallback)) { AddRef(); *ppv = (IBindStatusCallback *) this; } else if(IsEqualIID(riid, IID_IServiceProvider)) { AddRef(); *ppv = (IServiceProvider *) this; } else { hr = E_NOINTERFACE; } DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP_(ULONG) AddRef() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IUnknown::AddRef", "this=%#x", this )); InterlockedIncrement((long *) &m_cRef);
DEBUG_LEAVE(m_cRef); return m_cRef; }
STDMETHODIMP_(ULONG) Release() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IUnknown::Release", "this=%#x", this )); LONG count = m_cRef - 1;
if(0 == InterlockedDecrement((long *) &m_cRef)) { delete this; count = 0; }
DEBUG_LEAVE(count); return count; }
// IBindStatusCallback/Holder
STDMETHODIMP OnStartBinding(DWORD grfBSCOption, IBinding* pbinding) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::OnStartBinding", "this=%#x, %#x, %#x", this, grfBSCOption, pbinding )); m_bObjectAvailableCalled=FALSE; IBindStatusCallback* pclientbsc=GetClientBSC();
HRESULT hr = S_OK; if (pclientbsc) hr = pclientbsc->OnStartBinding(grfBSCOption, pbinding);
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP GetPriority(LONG* pnPriority) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::GetPriority", "this=%#x, %#x", this, pnPriority )); IBindStatusCallback* pclientbsc=GetClientBSC();
HRESULT hr = S_OK; if (pclientbsc) hr = pclientbsc->GetPriority(pnPriority);
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP OnLowResource(DWORD dwReserved) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::OnLowResource", "this=%#x, %#x", this, dwReserved )); IBindStatusCallback* pclientbsc=GetClientBSC();
HRESULT hr = S_OK; if (pclientbsc) hr = pclientbsc->OnLowResource(dwReserved);
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP OnStopBinding(HRESULT hrStatus, LPCWSTR pszError) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::OnStopBinding", "this=%#x, %#x, %.80wq", this, hrStatus, pszError )); HRESULT hr=S_OK;
// Save client BSC for last notification
IBindStatusCallback* pclientbsc=GetClientBSC(); if (!pclientbsc) { DEBUG_LEAVE(hr); return hr; } pclientbsc->AddRef();
// We are done with this bind context! Unregister before caller unregisters it's IBSC
//hr=RevokeFromBC();
if (SUCCEEDED(hrStatus)) { if (!m_bObjectAvailableCalled && (m_dwFlags & CD_FLAGS_NEED_CLASSFACTORY ) ) { IUnknown* punk=NULL; CLSID clsid;
hr = GetClsidFromExtOrMime( m_clsid, clsid, m_szExt, m_szType, NULL ); if ( SUCCEEDED(hr) ) hr = CoGetClassObject(clsid, m_dwClsContext, m_pvReserved, m_riid, (void**) &punk); if (FAILED(hr)) { hr = pclientbsc->OnStopBinding(hr, L""); pclientbsc->Release();
DEBUG_LEAVE(hr); return hr; } pclientbsc->OnObjectAvailable(m_riid, punk);
// release the IUnkown returned by CoGetClassObject
punk->Release();
m_bObjectAvailableCalled=TRUE; } }
hr=pclientbsc->OnStopBinding(hrStatus, pszError); pclientbsc->Release();
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::GetBindInfo", "this=%#x, %#x, %#x", this, pgrfBINDF, pbindInfo )); IBindStatusCallback* pclientbsc=GetClientBSC();
HRESULT hr = S_OK; if (pclientbsc) hr = pclientbsc->GetBindInfo(pgrfBINDF, pbindInfo);
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP OnDataAvailable( DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::OnDataAvailable", "this=%#x, %#x, %#x, %#x, %#x", this, grfBSCF, dwSize, pfmtetc, pstgmed )); IBindStatusCallback* pclientbsc=GetClientBSC();
HRESULT hr = S_OK; if (pclientbsc) hr = pclientbsc->OnDataAvailable(grfBSCF, dwSize, pfmtetc, pstgmed);
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown* punk) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::OnObjectAvailable", "this=%#x, %#x, %#x", this, &riid, punk )); HRESULT hr=S_OK; // Save client BSC
IBindStatusCallback* pclientbsc=GetClientBSC(); if (pclientbsc) { pclientbsc->AddRef(); hr=pclientbsc->OnObjectAvailable(riid, punk); pclientbsc->Release(); m_bObjectAvailableCalled=TRUE; }
DEBUG_LEAVE(hr); return hr; }
STDMETHODIMP OnProgress ( ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR pwzStatusText ) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IBindStatusCallback::OnProgress", "this=%#x, %#x, %#x, %#x, %.80wq", this, ulProgress, ulProgressMax, ulStatusCode, pwzStatusText )); IBindStatusCallback* pclientbsc=GetClientBSC();
HRESULT hr = S_OK; if (pclientbsc) hr = pclientbsc->OnProgress(ulProgress, ulProgressMax, ulStatusCode, pwzStatusText);
DEBUG_LEAVE(hr); return hr; }
// IServiceProvider, chains all other interfaces
STDMETHODIMP QueryService( REFGUID rsid, REFIID iid, void **ppvObj) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CBSCCreateObject::IserviceProvider::QueryService", "this=%#x, %#x, %#x, %#x", this, &rsid, &iid, ppvObj )); HRESULT hr=S_OK; IServiceProvider* pclientsp=NULL;
hr=m_pclientbsc->QueryInterface(IID_IServiceProvider, (void**) &pclientsp); if (SUCCEEDED(hr)) { hr=pclientsp->QueryService(rsid, iid, ppvObj); pclientsp->Release(); if (SUCCEEDED(hr)) { DEBUG_LEAVE(hr); return hr; } } IBindStatusCallback* pclientbsc=GetClientBSC(); if (pclientbsc) hr = pclientbsc->QueryInterface(iid, ppvObj); else hr = QueryInterface(iid, ppvObj);
DEBUG_LEAVE(hr); return hr; } };
#endif // WRAP_OLE32_COINSTALL
/*
* CoGetClassObjectFromURL * * This is the exposed entry point into the Code Downloader. * * It takes parameters closely matching the INSERT tag * REFCLSID rCLASSID, // CLSID of object (may be NULL)
* LPCWSTR szCODE, // URL to code (may be NULL)
* DWORD dwFileVersionMS, // Version of primary object
* DWORD dwFileVersionLS, // Version of primary object
* LPCWSTR szTYPE, // MIME type (may be NULL)
* LPBINDCTX pBindCtx, // Bind ctx
* DWORD dwClsContext, // CLSCTX flags
* LPVOID pvReserved, // Must be NULL
* REFIID riid, // Usually IID_IClassFactory
* LPVOID * ppv // Ret - usually IClassFactory *
*/
STDAPI CoGetClassObjectFromURL ( REFCLSID rCLASSID, // CLSID of object (may be NULL)
LPCWSTR szCODE, // URL to code (may be NULL)
DWORD dwFileVersionMS, // Version of primary object
DWORD dwFileVersionLS, // Version of primary object
LPCWSTR szTYPE, // MIME type (may be NULL)
LPBINDCTX pBindCtx, // Bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
LPVOID * ppv // Ret - usually IClassFactory *
) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "CoGetClassObjectFromURL", "%#x, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x", &rCLASSID, szCODE, dwFileVersionMS, dwFileVersionLS, szTYPE, pBindCtx, dwClsContext, pvReserved, &riid, ppv )); HRESULT hr = NO_ERROR; CLSID myclsid; int nForceDownload = 0; CDLDebugLog * pdlog = NULL; CodeDownloadData cdd; LPWSTR pwszClsid = NULL; WCHAR szCleanCODE[INTERNET_MAX_URL_LENGTH]; LPSTR szTmp = NULL; LPWSTR wzPtr = NULL; LPSTR szBuf = NULL;
cdd.szDistUnit = NULL; cdd.szClassString = NULL; cdd.szURL = NULL; cdd.szExtension = NULL; cdd.szMimeType = szTYPE; cdd.szDll = NULL; cdd.dwFileVersionMS = dwFileVersionMS; cdd.dwFileVersionLS = dwFileVersionLS; cdd.dwFlags = CD_FLAGS_NEED_CLASSFACTORY;
if (szCODE) { StrCpyNW(szCleanCODE, szCODE, INTERNET_MAX_URL_LENGTH); wzPtr = szCleanCODE; while (*wzPtr && *wzPtr != L'#') { wzPtr++; } *wzPtr = L'\0';
cdd.szURL = szCleanCODE;
if (FAILED(Unicode2Ansi(szCODE, &szBuf))) { goto Exit; } szTmp = szBuf; } if (szTmp) { while (*szTmp && *szTmp != L'#') { szTmp++; }
if (*szTmp == L'#') { // Actual codebase ends here. Anchor with NULL char.
*szTmp = L'\0'; szTmp++;
// parsing code
// Only allow: CODEBASE=http://foo.com#VERSION=1,0,0,0
// or: CODEBASE=http://foo.com#EXACTVERSION=1,0,0,0
LPSTR szStart = szTmp; while (*szTmp && *szTmp != '=') { szTmp++; }
if (*szTmp) { // Found '=' delimiter. Anchor NULL
*szTmp = '\0'; szTmp++;
if (!StrCmpI(szStart, "version")) { GetVersionFromString(szTmp, &dwFileVersionMS, &dwFileVersionLS, ','); cdd.dwFileVersionMS = dwFileVersionMS; cdd.dwFileVersionLS = dwFileVersionLS; } else if (!StrCmpI(szStart, ("exactversion"))) { cdd.dwFlags |= CD_FLAGS_EXACT_VERSION; GetVersionFromString(szTmp, &dwFileVersionMS, &dwFileVersionLS, ','); cdd.dwFileVersionMS = dwFileVersionMS; cdd.dwFileVersionLS = dwFileVersionLS; } } } }
hr = StringFromCLSID(rCLASSID, &pwszClsid); if(FAILED(hr)) pwszClsid = NULL;
// Prepare the debuglog for this download
pdlog = CDLDebugLog::MakeDebugLog(); if(pdlog) { pdlog->AddRef(); // If there is some way to name the debug log, go ahead and initialize it
if(pdlog->Init(pwszClsid, cdd.szMimeType, cdd.szExtension, cdd.szURL) != FALSE) { CDLDebugLog::AddDebugLog(pdlog); } else { pdlog->Release(); pdlog = NULL; } }
UrlMkDebugOut((DEB_CODEDL, "IN CoGetClassObjectFromURL CLASSID: %lx, TYPE=%ws...szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n", rCLASSID.Data1, cdd.szMimeType, cdd.szURL, cdd.dwFileVersionMS, cdd.dwFileVersionLS));
forcedownload:
// Note about pvReserved: this is used by DCOM to get in the remote server
// name and other info. If not NULL, then the caller wants us to use
// dcom. if (pvReserved) just call CoGetClassObject.
// call AsyncGetClassBits to do the real work
if (pvReserved == NULL && (nForceDownload <= 1) ) hr = AsyncGetClassBitsEx(rCLASSID, &cdd, pBindCtx, dwClsContext, pvReserved, riid);
if (SUCCEEDED(hr) && (hr != MK_S_ASYNCHRONOUS)) {
hr = GetClsidFromExtOrMime( rCLASSID, myclsid, cdd.szExtension, cdd.szMimeType, NULL);
Assert(hr == S_OK);
if (hr != S_OK) { hr = E_UNEXPECTED; if(pdlog) pdlog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FAILED_CONVERT_CLSID, cdd.szExtension, cdd.szMimeType); goto Exit; }
DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "EXTERNAL::CoGetClassObject", "%#x, %#x, %#x, %#x, %#x", &myclsid, dwClsContext, pvReserved, &riid, ppv )); hr = CoGetClassObject(myclsid, dwClsContext, pvReserved, riid, ppv);
DEBUG_LEAVE(hr); // BUGBUG: move this policy into the client with a CodeInstallProblem?
// this hack is easier than reprocessing INF from previous download
// if we're not using dcom, and the api thinks we're good to go (didn't need to
// install), yet for these reasons we couldn't get the class object, force a download
// If there's some other error, or the get class objct was successful, quit.
if ( !pvReserved && ((hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)) || (hr == REGDB_E_CLASSNOTREG) || (hr == HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND))) ) {
if (hr == REGDB_E_CLASSNOTREG) {
// if its a hack GUID that is not a COM object but just to
// get the OBJECT tag to automatically slam a reg key or
// install some software (like java vm) then don't
// force an install
if (!AdviseForceDownload(&myclsid, dwClsContext)) goto Exit;
}
UrlMkDebugOut((DEB_CODEDL, "WRN CoGetClassObjectFromURL hr:%lx%s, CLASSID: %lx..., szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n", hr,": dependent dll probably missing, forcing download!",myclsid.Data1, cdd.szURL, cdd.dwFileVersionMS, cdd.dwFileVersionLS));
cdd.dwFlags |= CD_FLAGS_FORCE_DOWNLOAD; nForceDownload++; goto forcedownload;
} // falling through to exit
}
Exit: // If we had some problem, dump the debuglog
if(FAILED(hr) && pdlog) { pdlog->DumpDebugLog(NULL, 0, NULL, hr); } if(pwszClsid) delete pwszClsid;
UrlMkDebugOut((DEB_CODEDL, "OUT CoGetClassObjectFromURL hr:%lx%s, CLASSID: %lx, TYPE=%ws..., szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n", hr,(hr == MK_S_ASYNCHRONOUS)?"(PENDING)":(hr == S_OK)?"(SUCCESS)":"",rCLASSID.Data1, cdd.szMimeType, cdd.szURL, cdd.dwFileVersionMS, cdd.dwFileVersionLS)); if(pdlog) { CDLDebugLog::RemoveDebugLog(pdlog); pdlog->Release(); pdlog = NULL; }
if (szBuf) { delete [] szBuf; }
DEBUG_LEAVE_API(hr); return hr; }
/*
* SetCodeDownloadTLSVars * * sets up a bunch of tls variables * eg, setup cookie, trust cookie list, code download list and * the CDLPacket list * since TLS vars are HeapAllocated rather than using the new operator * the constructors for classes won't get run automatically * which is why we have all pointers and the actual classes get allocated * here */
HRESULT SetCodeDownloadTLSVars() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "SetCodeDownloadTLSVars", NULL )); HRESULT hr = NO_ERROR; CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) // if tls ctor failed above
goto Exit;
if (!tls->pSetupCookie) { tls->pSetupCookie = new CCookie<CCodeDownload *>(CODE_DOWNLOAD_SETUP);
if (!tls->pSetupCookie) { hr = E_OUTOFMEMORY; goto Exit; } }
if (!tls->pTrustCookie) { tls->pTrustCookie = new CCookie<CDownload *>(CODE_DOWNLOAD_TRUST_PIECE);
if (!tls->pTrustCookie) { hr = E_OUTOFMEMORY; goto Exit; } }
if (!tls->pCodeDownloadList) { tls->pCodeDownloadList = new CList<CCodeDownload *, CCodeDownload *>;
if (!tls->pCodeDownloadList) { hr = E_OUTOFMEMORY; goto Exit; } }
if (!tls->pRejectedFeaturesList) { tls->pRejectedFeaturesList= new CList<LPCWSTR , LPCWSTR >;
if (!tls->pRejectedFeaturesList) { hr = E_OUTOFMEMORY; goto Exit; } }
if (!tls->pCDLPacketMgr) { tls->pCDLPacketMgr = new CCDLPacketMgr();
if (!tls->pCDLPacketMgr) { hr = E_OUTOFMEMORY; goto Exit; } }
Exit:
DEBUG_LEAVE(hr); return hr; }
/*
* CoInstall * * * CoInstall() is a public API, also used by CoGetClassObjectFromUrl * * It's primary implementation is in OLE32. */
STDAPI CoInstall( IBindCtx *pbc, DWORD dwFlags, uCLSSPEC *pClassSpec, QUERYCONTEXT *pQuery, LPWSTR pszCodeBase) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "CoInstall", "%#x, %#x, %#x, %#x, %.80wq", pbc, dwFlags, pClassSpec, pQuery, pszCodeBase )); HRESULT hr;
// BUGBUG: The real CoInstall needs this always set for now. MSICD/PrivateCoInstall shouldn't,
// so we'll only set it in the case where we're calling NT5 OLE.
// Setting this flag unconditionally may have bad side effects on offline mode.
dwFlags = dwFlags | CD_FLAGS_FORCE_INTERNET_DOWNLOAD; #ifndef WRAP_OLE32_COINSTALL
dwFlags = dwFlags | CD_FLAGS_NEED_CLASSFACTORY; #else
dwFlags = dwFlags & (~CD_FLAGS_NEED_CLASSFACTORY); #endif
hr = SetCoInstall();
if ( SUCCEEDED(hr) ) { if ( g_bUseOLECoInstall ) hr = (*g_pfnCoInstall)(pbc, dwFlags, pClassSpec, pQuery, pszCodeBase); else hr = PrivateCoInstall(pbc, dwFlags, pClassSpec, pQuery, pszCodeBase); }
DEBUG_LEAVE_API(hr); return hr; };
/*
* AsyncInstallDistUnit * * * AsyncInstallDistributionUnit() the entry into the Code downloader creates this obj * for the given CODE, DistUnit, FileVersion, BSC (from BindCtx) * * The CodeDownload obj once created is asked to perform its function * thru CCodeDownload::DoCodeDownload(). */
STDAPI AsyncInstallDistributionUnitEx( CodeDownloadData * pcdd, // Contains requested object's descriptors
IBindCtx *pbc, // bind ctx
REFIID riid, IUnknown **ppUnk, LPVOID pvReserved) // Must be NULL
{ DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "AsyncInstallDistributionUnitEx", "%#x, %#x, %#x, %#x, %#x", pcdd, pbc, &riid, ppUnk, pvReserved )); LPCWSTR szClientID = NULL;
pcdd->dwFlags &= (CD_FLAGS_EXTERNAL_MASK | CD_FLAGS_EXACT_VERSION);
HRESULT hr = AsyncGetClassBits2Ex(szClientID, pcdd, pbc, 0, NULL, riid, ppUnk);
DEBUG_LEAVE_API(hr); return hr; }
// backwards compatability (no dll name parameter)
STDAPI AsyncInstallDistributionUnit( LPCWSTR szDistUnit, LPCWSTR szTYPE, LPCWSTR szExt, DWORD dwFileVersionMS, // CODEBASE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
LPCWSTR szURL, // CODEBASE
IBindCtx *pbc, // bind ctx
LPVOID pvReserved, // Must be NULL
DWORD flags) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "AsyncInstallDistributionUnit", "%.80wq, %.80wq, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x", szDistUnit, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, szURL, pbc, pvReserved, flags )); CodeDownloadData cdd; cdd.szDistUnit = szDistUnit; cdd.szClassString = szDistUnit; // best choice we've got
cdd.szURL = szURL; cdd.szMimeType = szTYPE; cdd.szExtension = szExt; cdd.szDll = NULL; cdd.dwFileVersionMS = dwFileVersionMS; cdd.dwFileVersionLS = dwFileVersionLS; cdd.dwFlags = flags; HRESULT hr = AsyncInstallDistributionUnitEx(&cdd, pbc, IID_IUnknown, NULL, pvReserved);
DEBUG_LEAVE_API(hr); return hr; }
/*
* AsyncGetClassBits * * * AsyncGetClassBits() the entry into the Code downloader creates this obj * for the given CODE, CLSID, FileVersion, BSC (from BindCtx) * we do not check to see if a code download is already in progress * in the system at a given moment. Nor we do we keep track of individual * downloads and possible clashes between various silmultaneous code * downloads system wide. We leave it to URL moniker (above us) to ensure * that duplicate calls are not made into AsynGetClassBits. The second * problem of different code downloads trying to bring down a common * dependent DLL is POSTPONED to version 2 implementation. * * The CodeDownload obj once created is asked to perform its function * thru CCodeDownload::DoCodeDownload(). */
STDAPI AsyncGetClassBits( REFCLSID rclsid, // CLSID
LPCWSTR szTYPE, LPCWSTR szExt, DWORD dwFileVersionMS, // CODE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
LPCWSTR szURL, // CODE= in INSERT tag
IBindCtx *pbc, // bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
DWORD flags) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "AsyncGetClassBits", "%#x, %.80wq, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x", &rclsid, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, szURL, pbc, dwClsContext, pvReserved, &riid, flags )); CodeDownloadData cdd; cdd.szDistUnit = NULL; cdd.szClassString = NULL; cdd.szURL = szURL; cdd.szMimeType = szTYPE; cdd.szExtension = szExt; cdd.szDll = NULL; cdd.dwFileVersionMS = dwFileVersionMS; cdd.dwFileVersionLS = dwFileVersionLS; cdd.dwFlags = flags; HRESULT hr = AsyncGetClassBitsEx(rclsid, &cdd, pbc, dwClsContext, pvReserved, riid);
DEBUG_LEAVE_API(hr); return hr; }
STDAPI AsyncGetClassBitsEx( REFCLSID rclsid, // CLSID
CodeDownloadData *pcdd, IBindCtx *pbc, // bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid) // Usually IID_IClassFactory
{ DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "AsyncGetClassBitsEx", "%#x, %#x, %#x, %#x, %#x, %#x", &rclsid, pcdd, pbc, dwClsContext, pvReserved, &riid )); LPOLESTR pwcsClsid = NULL; LPCWSTR szClientID = NULL; HRESULT hr=S_OK; pcdd->dwFlags &= (CD_FLAGS_EXTERNAL_MASK | CD_FLAGS_EXACT_VERSION); CDLDebugLog * pdlog = NULL;
// return if we can't get a valid string representation of the CLSID
if (!IsEqualGUID(rclsid , CLSID_NULL) && (FAILED((hr=StringFromCLSID(rclsid, &pwcsClsid)))) ) { pdlog = CDLDebugLog::GetDebugLog(NULL, pcdd->szMimeType, pcdd->szExtension, pcdd->szURL); if(pdlog) { pdlog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FAILED_STRING_FROM_CLSID); } goto Exit; } pcdd->szDistUnit = pwcsClsid; pcdd->szClassString = pwcsClsid; // dist unit and clsid are the same from this entry point
#ifndef WRAP_OLE32_COINSTALL
// Work around a problem with OLE32's CoInstall (until wrappers are enabled or OLE calls PrivateCoInstall):
// since CoInstall doesn't known the IID,
// it calls AsyncGetClassBits with IID_IUnknown (instead of IID_IClassFactory)
if ((pcdd->dwFlags & CD_FLAGS_FORCE_INTERNET_DOWNLOAD) && IsEqualGUID(riid, IID_IUnknown)) { hr = AsyncGetClassBits2Ex(szClientID, pcdd, pbc,dwClsContext,pvReserved,IID_IClassFactory,NULL); } else { #endif
hr = AsyncGetClassBits2Ex(szClientID, pcdd, pbc,dwClsContext,pvReserved,riid,NULL);
#ifndef WRAP_OLE32_COINSTALL
} #endif
Exit:
if (pwcsClsid != NULL) delete pwcsClsid;
DEBUG_LEAVE_API(hr); return hr; }
HRESULT GetIEFeatureVersion( LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
LPCWSTR szTYPE, CLSID clsid, QUERYCONTEXT *pqc) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "GetIEFeatureVersion", "%.80wq, %.80wq, %#x, %#x", szDistUnit, szTYPE, &clsid, pqc )); HRESULT hr = S_OK;
memset(pqc, 0, sizeof(QUERYCONTEXT));
if (!IsEqualGUID(clsid, CLSID_NULL)) { hr = GetIEFeatureFromClass(NULL, clsid, pqc);
} else if (szTYPE) { hr = GetIEFeatureFromMime(NULL, szTYPE, pqc);
} else { // not an IE feature
hr = S_FALSE; goto Exit; }
Exit:
DEBUG_LEAVE(hr); return hr; }
HRESULT InstallIEFeature( LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
LPCWSTR szTYPE, CLSID clsid, IBindCtx *pbc, DWORD dwFileVersionMS, DWORD dwFileVersionLS, DWORD dwFlags, BOOL bIEVersion ) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "InstallIEFeature", "%.80wq, %.80wq, %#x, %#x, %#x, %#x, %#x, %B", szDistUnit, szTYPE, &clsid, pbc, dwFileVersionMS, dwFileVersionLS, dwFlags, bIEVersion )); HRESULT hr = S_OK; uCLSSPEC classpec; IWindowForBindingUI *pWindowForBindingUI = NULL; IBindStatusCallback *pclientbsc = NULL; HWND hWnd = NULL; REFGUID rguidReason = IID_ICodeInstall; QUERYCONTEXT qc; DWORD dwJITFlags = 0;
memset(&qc, 0, sizeof(qc));
qc.dwVersionHi = dwFileVersionMS; qc.dwVersionLo = dwFileVersionLS;
if (!IsEqualGUID(clsid, CLSID_NULL)) { classpec.tyspec=TYSPEC_CLSID; classpec.tagged_union.clsid=clsid; } else if (szTYPE) { classpec.tyspec=TYSPEC_MIMETYPE; classpec.tagged_union.pMimeType=(LPWSTR)szTYPE; } else { // not an IE feature
hr = S_FALSE; goto Exit; }
hr = FaultInIEFeature(hWnd, &classpec, &qc, (bIEVersion?0:FIEF_FLAG_CHECK_CIFVERSION)|FIEF_FLAG_PEEK);
if ( hr == HRESULT_FROM_WIN32(ERROR_UNKNOWN_REVISION) || hr == E_ACCESSDENIED) {
// the version in the CIF will not satisfy the requested version
// or the admin has turned off JIT or the user has turned off
// JIT in Inetcpl: if they wanted to turn off code download
// they should do it per-zone activex signed/unsigned policy.
// fall thru to code download from the CODEBASE
hr = S_FALSE; }
if (hr == S_OK) {
// We always come in here from code downloader at a point
// where looking at the com branch and DU key, something is
// busted and so needs code download. We can't at this point
// succeed. Likely the AS keys are just orphaned and it looks
// installed, but is not.
// However, to account for cases where JIT could be right
// we will only force JIT download when instrcuted to
if (dwFlags & CD_FLAGS_FORCE_DOWNLOAD) { hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED); dwJITFlags |= FIEF_FLAG_SKIP_INSTALLED_VERSION_CHECK; }
}
if (hr != HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED)) { goto Exit; }
// must really install now, get an hwnd
hr = pbc->GetObjectParam(REG_BSCB_HOLDER, (IUnknown **)&pclientbsc); if (FAILED(hr)) goto Exit;
// don't JIT if web crawling
{ DWORD grfBINDF = 0; BINDINFO bindInfo; memset(&bindInfo, 0, sizeof(BINDINFO)); bindInfo.cbSize = sizeof(BINDINFO);
pclientbsc->GetBindInfo(&grfBINDF, &bindInfo);
ReleaseBindInfo(&bindInfo);
if (grfBINDF & BINDF_SILENTOPERATION) { hr = MK_E_MUSTBOTHERUSER; goto Exit; }
}
// Get IWindowForBindingUI ptr
hr = pclientbsc->QueryInterface(IID_IWindowForBindingUI, (LPVOID *)&pWindowForBindingUI);
if (FAILED(hr)) { IServiceProvider *pServProv; hr = pclientbsc->QueryInterface(IID_IServiceProvider, (LPVOID *)&pServProv);
if (hr == NOERROR) { pServProv->QueryService(IID_IWindowForBindingUI,IID_IWindowForBindingUI, (LPVOID *)&pWindowForBindingUI); pServProv->Release(); } }
// get hWnd
if (pWindowForBindingUI) { pWindowForBindingUI->GetWindow(rguidReason, &hWnd); pWindowForBindingUI->Release();
memset(&qc, 0, sizeof(qc)); // reset, peek state modifies this with
// currently installed version info!
qc.dwVersionHi = dwFileVersionMS; qc.dwVersionLo = dwFileVersionLS;
hr = FaultInIEFeature(hWnd, &classpec, &qc, dwJITFlags);
} else { hr = MK_E_MUSTBOTHERUSER; // fallthru to Exit
// goto Exit;
}
Exit:
if (pclientbsc) pclientbsc->Release();
DEBUG_LEAVE(hr); return hr; }
// if both signed and unsigned activex is disallowed then return failure
// so we can avoid downloading the CAB altogether
HRESULT CheckActiveXDownloadEnabled( IInternetHostSecurityManager *pHostSecurityManager, LPCWSTR szCodebase, IBindStatusCallback* pBSC) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CheckActiveXDownloadEnabled", "%#x, %.80wq", pHostSecurityManager, szCodebase )); HRESULT hr = S_OK; DWORD dwPolicy; DWORD grfBINDF = 0; BINDINFO bindInfo; memset(&bindInfo, 0, sizeof(BINDINFO)); bindInfo.cbSize = sizeof(BINDINFO); BOOL fEnforceRestricted = FALSE; hr = pBSC->GetBindInfo(&grfBINDF, &bindInfo); if (SUCCEEDED(hr)) { ReleaseBindInfo(&bindInfo); if (grfBINDF & BINDF_ENFORCERESTRICTED) fEnforceRestricted = TRUE; } hr = GetActivePolicy(pHostSecurityManager, szCodebase, URLACTION_DOWNLOAD_SIGNED_ACTIVEX, dwPolicy, fEnforceRestricted);
if (FAILED(hr)) { hr = GetActivePolicy(pHostSecurityManager, szCodebase, URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX, dwPolicy, fEnforceRestricted); }
DEBUG_LEAVE(hr); return hr; }
// backwards compatability
STDAPI AsyncGetClassBits2( LPCWSTR szClientID, // client ID, root object if NULL
LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
LPCWSTR szTYPE, LPCWSTR szExt, DWORD dwFileVersionMS, // CODE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
LPCWSTR szURL, // CODE= in INSERT tag
IBindCtx *pbc, // bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
DWORD flags) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "AsyncGetClassBits2", "%.80wq, %.80wq, %.80wq, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x", szClientID, szDistUnit, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, szURL, pbc, dwClsContext, pvReserved, &riid, flags )); CodeDownloadData cdd; cdd.szDistUnit = szDistUnit; cdd.szClassString = szDistUnit; // best choice we've got
cdd.szURL = szURL; cdd.szMimeType = szTYPE; cdd.szExtension = szExt; cdd.szDll = NULL; cdd.dwFileVersionMS = dwFileVersionMS; cdd.dwFileVersionLS = dwFileVersionLS; cdd.dwFlags = flags; HRESULT hr = AsyncGetClassBits2Ex(szClientID,&cdd,pbc,dwClsContext, pvReserved,riid,NULL);
DEBUG_LEAVE_API(hr); return hr; }
STDAPI AsyncGetClassBits2Ex( LPCWSTR szClientID, // client ID, root object if NULL
CodeDownloadData * pcdd, IBindCtx *pbc, // bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
IUnknown **ppUnk) // pass back pUnk for synchronous case
{ DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "AsyncGetClassBits2Ex", "%.80wq, %#x, %#x, %#x, %#x, %#x, %#x", szClientID, pcdd, pbc, dwClsContext, pvReserved, &riid, ppUnk )); LPCWSTR szDistUnit = pcdd->szDistUnit; // Name of dist unit, may be a clsid
LPCWSTR szClassString = pcdd->szClassString; // Clsid to call com with/get object on
LPCWSTR szTYPE = pcdd->szMimeType; LPCWSTR szExt = pcdd->szExtension; DWORD dwFileVersionMS = pcdd->dwFileVersionMS; // CODE=http://foo#Version=a,b,c,d
DWORD dwFileVersionLS = pcdd->dwFileVersionLS; // MAKEDWORD(c,b) of above
LPCWSTR szURL = pcdd->szURL; // CODE= in INSERT tag
LPCWSTR szDll = pcdd->szDll; // Dll name for zero impact (can be NULL)
DWORD flags = pcdd->dwFlags; CCodeDownload* pcdl = NULL; HRESULT hr = NO_ERROR; IBindStatusCallback *pclientbsc = NULL; LISTPOSITION pos; CClBinding *pClientbinding; char szExistingBuf[MAX_PATH]; DWORD cExistingSize = MAX_PATH; char *pBaseExistingName = NULL; HKEY hKeyIESettings = 0; LONG lResult; CLSID myclsid; CLSID inclsid = CLSID_NULL; LPSTR pPluginFileName = NULL; BOOL bHintActiveX = (flags & CD_FLAGS_HINT_ACTIVEX)?TRUE:FALSE; BOOL bHintJava = (flags & CD_FLAGS_HINT_JAVA)?TRUE:FALSE; BOOL bNullClsid; BOOL bIEVersion = FALSE; CLocalComponentInfo* plci = NULL; IInternetHostSecurityManager *pHostSecurityManager = NULL; CDLDebugLog * pdlog = NULL; CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) // if tls ctor failed above
goto AGCB_Exit;
pdlog = CDLDebugLog::GetDebugLog(szDistUnit, szTYPE, szExt, szURL); if(pdlog) pdlog->AddRef();
plci = new CLocalComponentInfo(); if(!plci) { hr = E_OUTOFMEMORY; goto AGCB_Exit; }
if(szClassString) CLSIDFromString((LPOLESTR)szClassString, &inclsid);// if fails szClassString is not clsid
// Fill myclsid with inclsid (if not null-clsid), the clsid corresponding
// to the mime type in szTYPE (if not NULL), the clsid corresponding
// to the file extension in szExt (if not NULL), or the clsid for the
// plugin corresponging to the mime type or extension (if not NULL),
// in that order of preference
hr = GetClsidFromExtOrMime( inclsid, myclsid, szExt, szTYPE, &pPluginFileName);
// hr = S_OK: mapped to a clsid
// hr = S_FALSE: don't know what it is
// hr error, fail
if (FAILED(hr)) { if(pdlog) { pdlog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FAILED_CONVERT_CLSID, szExt, szTYPE); } goto AGCB_Exit; }
hr = S_OK; //reset
if (!(dwFileVersionMS | dwFileVersionLS)) {
// maybe this is an IE feature like Java
// that may require that a matching version
// that is later than one currently installed
// is needed
if (!g_bNT5OrGreater) { QUERYCONTEXT qc; hr = GetIEFeatureVersion(szDistUnit, szTYPE, inclsid, &qc); if (FAILED(hr)) goto AGCB_Exit; dwFileVersionMS = qc.dwVersionHi; dwFileVersionLS = qc.dwVersionLo; if (dwFileVersionMS | dwFileVersionLS) { bIEVersion = TRUE; } } }
bNullClsid = IsEqualGUID(myclsid, CLSID_NULL);
if (szDistUnit || !bNullClsid ) {
// manage to map to a clsid or has a distunit name
CLSID pluginclsid = CLSID_ActiveXPlugin; if (!IsEqualGUID(myclsid , pluginclsid)) { // mark that we now have a clsid throw away TYPE, Ext
szTYPE = NULL; szExt = NULL; }
// check to see if locally installed.
HRESULT hrExact; HRESULT hrAny; if (FAILED((hrAny = IsControlLocallyInstalled(pPluginFileName, (pPluginFileName)?(LPCLSID)&inclsid:&myclsid, szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, NULL, FALSE)))) { goto AGCB_Exit; }
if (pcdd->dwFlags & CD_FLAGS_EXACT_VERSION) {
if (FAILED((hrExact = IsControlLocallyInstalled(pPluginFileName, (pPluginFileName)?(LPCLSID)&inclsid:&myclsid, szDistUnit, dwFileVersionMS, dwFileVersionLS, plci, NULL, TRUE)))) { goto AGCB_Exit; }
if (hrAny != S_OK) { // Don't have at least the requested version. Do the download.
hr = hrAny; } else if (hrAny == S_OK && hrExact == S_FALSE) { // Newer control installed, must downgrade
// Check if this is a system control, and disallow if it is
BOOL bIsDPFComponent = FALSE; HKEY hKeyIESettings = 0; CHAR szOCXCacheDirSFN[MAX_PATH]; CHAR szFNameSFN[MAX_PATH]; DWORD dwType; DWORD Size; Size = MAX_PATH; dwType = REG_SZ;
if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0, KEY_READ, &hKeyIESettings))) { if (SUCCEEDED(RegQueryValueEx(hKeyIESettings, g_szActiveXCache, NULL, &dwType, (unsigned char *)g_szOCXCacheDir, &Size))) { if (plci->szExistingFileName[0]) {
GetShortPathName(plci->szExistingFileName, szFNameSFN, MAX_PATH); GetShortPathName(g_szOCXCacheDir, szOCXCacheDirSFN, MAX_PATH);
if (StrStrI(szFNameSFN, szOCXCacheDirSFN)) { bIsDPFComponent = TRUE; } } RegCloseKey(hKeyIESettings); } }
if (!bIsDPFComponent) { // Trying to do a downgrade of a non-DPF component.
// Cut this off, and just act as if the existing (newer)
// version is already good enough. No download/install.
hr = S_OK; } else { // Do the download
hr = hrExact; }
} else { // hrAny == hrExact == S_OK, so we're done
Assert(hrAny == S_OK && hrExact == S_OK); hr = hrAny; }
} else { // Continue as before
hr = hrAny; }
if ( hr == S_OK) { // local version OK
if (!(flags & CD_FLAGS_FORCE_DOWNLOAD)) { // check here is a new version has been
// advertised for this DU. If so, force a -1 or Get Latest
if (!((plci->dwAvailMS > plci->dwLocFVMS) || ((plci->dwAvailMS == plci->dwLocFVMS) && (plci->dwAvailLS > plci->dwLocFVLS))) ) {
// Code Download thinks the
// current version is good enough
goto AGCB_Exit; }
dwFileVersionMS = 0xffffffff; dwFileVersionLS = 0xffffffff; }
// force download flag! Fall thru and Do it!
} } else {
// couldn't map to a clsid
// just have ext or mime type
}
// here if we are going to do a code download.
if ((flags & CD_FLAGS_NEED_CLASSFACTORY) && (dwFileVersionMS == 0) && (dwFileVersionLS == 0)) {
HRESULT hrResult = S_OK; IUnknown *punk = NULL;
// We don't care about the version. Check if someone registered
// themselves with COM via CoRegisterClassObject, and if it
// succeeds, we don't need to download.
hrResult = CoGetClassObject(((pPluginFileName) ? (inclsid) : (myclsid)), dwClsContext, pvReserved, riid, (void**)&punk); if (SUCCEEDED(hrResult)) { punk->Release(); hr = S_OK; goto AGCB_Exit; } }
if (flags & CD_FLAGS_PEEK_STATE) { hr = S_FALSE; goto AGCB_Exit; }
// check language being right version
if (plci->bForceLangGetLatest) { dwFileVersionMS = 0xffffffff; dwFileVersionLS = 0xffffffff; } else if ((dwFileVersionMS != 0xffffffff) && (dwFileVersionLS != 0xffffffff)) { // try the JIT API first before code download
hr = InstallIEFeature(szDistUnit, szTYPE, inclsid, pbc, dwFileVersionMS, dwFileVersionLS, flags, bIEVersion);
if (hr != S_FALSE) goto AGCB_Exit; } hr = SetCoInstall(); if ( FAILED(hr) ) goto AGCB_Exit;
if ( g_bUseOLECoInstall && !(flags & CD_FLAGS_FORCE_INTERNET_DOWNLOAD) ) { CLSID inclsid;
CLSIDFromString((LPOLESTR)szDistUnit, &inclsid); hr = WrapCoInstall( inclsid, szURL, dwFileVersionMS, dwFileVersionLS, szTYPE, pbc, dwClsContext,pvReserved, riid, flags);
if ( SUCCEEDED(hr) ) goto AGCB_Exit; }
hr = SetCodeDownloadTLSVars(); if (FAILED(hr)) goto AGCB_Exit;
hr = SetGlobals(); if (FAILED(hr)) goto AGCB_Exit;
if (g_bLockedDown) { hr = E_ACCESSDENIED; goto AGCB_Exit; }
hr = pbc->GetObjectParam(REG_BSCB_HOLDER, (IUnknown **)&pclientbsc); if (FAILED(hr)) goto AGCB_Exit;
pbc->AddRef(); // pbc gets saved in the CClBinding and gets released in
// ~CClBinding()
// after this point if a CClBinding does not get
// created, we will leak the client BC and BSC
// check appropriately and release client
// check to see if a code download is in progress for this CLSID
// Note, this only checks for top level objects now.
pHostSecurityManager = GetHostSecurityManager(pclientbsc);
hr = CCodeDownload::HandleDuplicateCodeDownloads(szURL, szTYPE, szExt, myclsid, szDistUnit, dwClsContext, pvReserved, riid, pbc, pclientbsc, flags, pHostSecurityManager);
// if it was a dulplicate request and got piggybacked to
// a CodeDownload in progress we will get back MK_S_ASYNCHRONOUS
// return of S_OK means that no DUP was found and we are to issue
// fresh code download
if (FAILED(hr)) { // release client here
pclientbsc->Release(); pbc->Release(); goto AGCB_Exit; }
if (hr == MK_S_ASYNCHRONOUS) goto AGCB_Exit;
pcdl = new CCodeDownload(szDistUnit, szURL, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, &hr);
if (FAILED(hr)) { // constructor failed!
pcdl->Release(); }
if (!pcdl) { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) { // release client here
pclientbsc->Release(); pbc->Release(); goto AGCB_Exit; }
// Pass off the debug log to the ccodedownload
if(pdlog) { pcdl->SetDebugLog(pdlog); }
pcdl->SetExactVersion((pcdd->dwFlags & CD_FLAGS_EXACT_VERSION) != 0);
CClBinding *pClientBinding; hr = pcdl->CreateClientBinding( &pClientBinding, pbc, pclientbsc, inclsid, dwClsContext, pvReserved, riid, TRUE /* fAddHead */, pHostSecurityManager);
if (FAILED(hr)) { // release client here
pclientbsc->Release(); pbc->Release(); pcdl->Release(); goto AGCB_Exit; }
pClientBinding->SetClassString(szClassString);
// check if our current security settings allow us to do a code download
// this is a quick out to avoid doing a download when all activex is
// disabled and we think this is ActiveX.
if (bHintActiveX || (!bNullClsid && !bHintJava)) {
// get the zone mgr and check for policy on signed and unsigned
// activex controls. If both are disabled then stop here
// otherwise proceed to download main CAB and WVT will determine the
// policy based on the appropriate urlaction (singed/unsigned)
hr = CheckActiveXDownloadEnabled(pHostSecurityManager, szURL, pclientbsc);
if (FAILED(hr)) { pcdl->Release(); goto AGCB_Exit; } }
// chain this CodeDownload to the list of downloads in this thread
pos = tls->pCodeDownloadList->AddHead(pcdl); pcdl->SetListCookie(pos);
hr = pcdl->DoCodeDownload(plci, flags); plci = NULL;
pcdl->Release(); // if async binding OnStartBinding would have addref'ed
AGCB_Exit:
if (pPluginFileName) delete pPluginFileName;
if(pdlog) pdlog->Release();
SAFEDELETE(plci);
SAFERELEASE(pHostSecurityManager);
DEBUG_LEAVE_API(hr); return hr;
}
STDAPI WrapCoInstall ( REFCLSID rCLASSID, // CLSID of object (may be NULL)
LPCWSTR szCODE, // URL to code (may be NULL)
DWORD dwFileVersionMS, // Version of primary object
DWORD dwFileVersionLS, // Version of primary object
LPCWSTR szTYPE, // MIME type (may be NULL)
LPBINDCTX pBindCtx, // Bind ctx
DWORD dwClsContext, // CLSCTX flags
LPVOID pvReserved, // Must be NULL
REFIID riid, // Usually IID_IClassFactory
DWORD flags ) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "WrapCoInstall", "%#x, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x", &rCLASSID, szCODE, dwFileVersionMS, dwFileVersionLS, szTYPE, pBindCtx, dwClsContext, pvReserved, &riid, flags )); HRESULT hr = NO_ERROR; // DWORD flags = 0; // CD_FLAGS_NEED_CLASSFACTORY;
WCHAR *szExt = NULL;
#ifdef WRAP_OLE32_COINSTALL
CBSCCreateObject* pobjectbsc=NULL; #endif
UrlMkDebugOut((DEB_CODEDL, "IN WrapCoInstall CLASSID: %lx, TYPE=%ws...szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n", rCLASSID.Data1, szTYPE, szCODE, dwFileVersionMS, dwFileVersionLS));
// Note about pvReserved: this is used by DCOM to get in the remote server
// name and other info. If not NULL, then the caller wants us to use
// dcom. if (pvReserved) just call CoGetClassObject.
// call AsyncGetClassBits to do the real work
if (pvReserved == NULL) { // Set up CoInstall parameters
uCLSSPEC classpec; QUERYCONTEXT query; if (!IsEqualGUID(rCLASSID, CLSID_NULL)) { classpec.tyspec=TYSPEC_CLSID; classpec.tagged_union.clsid=rCLASSID; // use original class ID so that MIME can still be processed
} else if (szTYPE && *szTYPE) { classpec.tyspec=TYSPEC_MIMETYPE; classpec.tagged_union.pMimeType=(LPWSTR) szTYPE; // BUGBUG uCLSSPEC::pMimeType should be declared const!
} else { hr=E_INVALIDARG; goto Exit; }
query.dwContext = dwClsContext; GetDefaultPlatform(&query.Platform); query.Locale = GetThreadLocale(); query.dwVersionHi = dwFileVersionMS; query.dwVersionLo = dwFileVersionLS;
#ifdef WRAP_OLE32_COINSTALL
// Override the client's BSC with a BSC that will create the object when it receives a successful OnStopBinding
// CBSCCreateObject registers itself in the bind context and saves a pointer to the client's BSC
// it unregisters itself upon OnStopBinding
pobjectbsc=new CBSCCreateObject(rCLASSID, szTYPE, szExt, dwClsContext, pvReserved, riid, pBindCtx, flags, hr); // hr by reference!
if (!pobjectbsc) { hr = E_OUTOFMEMORY; goto Exit; }
if (FAILED(hr)) { goto Exit; } #endif
hr=CoInstall(pBindCtx, flags, &classpec, &query, (LPWSTR) szCODE); //BUGBUG CoInstall szCodeBase should be const!
if (hr!=MK_S_ASYNCHRONOUS) { // clean up the bind context for synchronous and failure case
// in asynchronous case pobjectbsc revokes itself in OnStopBinding!
//pobjectbsc->RevokeFromBC();
} //hr = AsyncGetClassBits( rCLASSID,
// szTYPE, szExt,
// dwFileVersionMS, dwFileVersionLS, szCODE,
// pBindCtx, dwClsContext, pvReserved, riid, flags);
#ifdef WRAP_OLE32_COINSTALL
pobjectbsc->Release(); pobjectbsc=NULL; #endif
}
Exit: #ifdef WRAP_OLE32_COINSTALL
if (pobjectbsc) { pobjectbsc->Release(); pobjectbsc=NULL; } #endif
UrlMkDebugOut((DEB_CODEDL, "OUT WrapCoInstall hr:%lx%s, CLASSID: %lx, TYPE=%ws..., szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n", hr,(hr == MK_S_ASYNCHRONOUS)?"(PENDING)":(hr == S_OK)?"(SUCCESS)":"", rCLASSID.Data1, szTYPE, szCODE, dwFileVersionMS, dwFileVersionLS));
DEBUG_LEAVE_API(hr); return hr; }
STDAPI PrivateCoInstall( IBindCtx *pbc, DWORD dwFlags, uCLSSPEC *pClassSpec, QUERYCONTEXT *pQuery, LPWSTR pszCodeBase) { DEBUG_ENTER_API((DBG_DOWNLOAD, Hresult, "PrivateCoInstall", "%#x, %#x, %#x, %#x, %.80wq", pbc, dwFlags, pClassSpec, pQuery, pszCodeBase ));
HRESULT hr = NO_ERROR; CLSID inclsid = CLSID_NULL; LPCWSTR pszDistUnit=NULL; LPCWSTR pszFileExt=NULL; LPCWSTR pszMimeType=NULL; QUERYCONTEXT query;
// "Parse" the parameters from the CLSSPEC and QUERYCONTEXT
// Get the class spec.
if(pClassSpec != NULL) { switch(pClassSpec->tyspec) { case TYSPEC_CLSID: inclsid = pClassSpec->tagged_union.clsid; break; case TYSPEC_MIMETYPE: pszMimeType = (LPCWSTR) pClassSpec->tagged_union.pMimeType; break; case TYSPEC_FILEEXT: pszFileExt = (LPCWSTR) pClassSpec->tagged_union.pFileExt; break; case TYSPEC_FILENAME: pszDistUnit= (LPCWSTR) pClassSpec->tagged_union.pFileName; // clean-up: this is the only case where we assign existing mem to pszDistUnit!
// BUGBUG: need to do this in OLE's CoInstall as well!
CLSIDFromString((LPOLESTR)pszDistUnit, &inclsid);// if fails szDistUnit is not clsid
break; default: break; } }
//Get the query context.
if(pQuery != NULL) { query = *pQuery; } else { query.dwContext = CLSCTX_ALL; GetDefaultPlatform(&query.Platform); query.Locale = GetThreadLocale(); query.dwVersionHi = (DWORD) -1; query.dwVersionLo = (DWORD) -1; }
hr = AsyncInstallDistributionUnit( pszDistUnit, pszMimeType, pszFileExt, query.dwVersionHi, query.dwVersionLo, pszCodeBase, pbc, NULL, dwFlags | CD_FLAGS_FORCE_INTERNET_DOWNLOAD // ensure no mutual recursion
);
DEBUG_LEAVE_API(hr); return hr; }
|