|
|
// ===========================================================================
// File: CDL.CXX
// The main code downloader file.
//
#include <cdlpch.h>
#include <stdio.h>
#include <shlwapi.h>
#include <regstr.h>
#include <initguid.h>
#include <pkgguid.h>
#include <winineti.h>
#include <shlwapip.h>
#include "advpub.h"
#include "advpkp.h"
#include "shlobj.h"
#include "helpers.hxx"
typedef HRESULT (WINAPI *REMOVECONTROLBYNAME)( LPCTSTR lpszFile, LPCTSTR lpszCLSID, LPCTSTR lpszTypeLibID, BOOL bForceRemove /*= FALSE*/, DWORD dwIsDistUnit /*= FALSE*/ );
typedef BOOL (*pfnSfcIsFileProtected)(HANDLE RpcHandle,LPCWSTR ProtFileName);
extern LCID g_lcidBrowser; // default to english
extern char g_szOCXCacheDir[]; extern char g_szPlatform[]; // platform specific string for location of file
extern HINSTANCE g_hInst;
const static char *sz_USE_CODE_URL = "CODEBASE"; const static char szCLSID[] = "CLSID"; const static char szVersion[] = "Version";
const static char *szTHISCAB = "thiscab"; const static char *szIGNORE = "ignore";
extern LPCSTR szWinNT; extern LPCSTR szWin95;
extern LPCSTR szPlatform;
extern char *g_szProcessorTypes[];
extern CRunSetupHook g_RunSetupHook;
extern int g_CPUType; extern BOOL g_bRunOnWin95;
#define RANDNUM_MAX 0x7fff
#define MAX_ATOM_SIZE 255
LONG InitializeRandomSeed() { DEBUG_ENTER((DBG_DOWNLOAD, Dword, "InitializeRandomSeed", NULL )); SYSTEMTIME st; GetSystemTime(&st);
DEBUG_LEAVE((LONG)st.wMilliseconds); return (LONG)st.wMilliseconds; }
//+-------------------------------------------------------------------------
//
// Function: randnum
//
// Synopsys: Generate random number based on seed. (copied from crt)
//
//+-------------------------------------------------------------------------
int randnum (void) { DEBUG_ENTER((DBG_DOWNLOAD, Int, "randnum", NULL )); static long holdrand = InitializeRandomSeed(); holdrand = ((holdrand * 214013L + 2531011L) >> 16) & RANDNUM_MAX; DEBUG_LEAVE(holdrand); return(holdrand); }
// Disabled by adding a DWORD value "DisableImprovedZoneCheck" with non=zero value under SETTINGS key
BOOL CanUseImprovedZoneCheck() { DEBUG_ENTER((DBG_APP, Bool, "CanUseImprovedZoneCheck", NULL )); DWORD dwErr = ERROR_SUCCESS; BOOL fRet = TRUE; HKEY hKeyClient; DWORD dwDisable = 0; DWORD dwSize = sizeof(DWORD); DWORD dwType;
dwErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0, KEY_QUERY_VALUE, &hKeyClient );
if( dwErr == ERROR_SUCCESS ) { dwErr = RegQueryValueEx( hKeyClient, "DisableImprovedZoneCheck", 0, &dwType, (LPBYTE)&dwDisable, &dwSize );
if((dwErr == ERROR_SUCCESS) && dwDisable) { fRet = FALSE; } RegCloseKey(hKeyClient); }
DEBUG_LEAVE(fRet); return fRet; }
BOOL CCodeDownload::FileProtectionCheckSucceeded(LPCSTR pszExistingFileName) { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "CCodeDownload::FileProtectionCheckSucceeded", "this=%#x, %.200q", this, (pszExistingFileName ? pszExistingFileName : "NULL") )); BOOL bRetval = FALSE;
if (IsFileProtected(pszExistingFileName)) { LPSTR pszCatalogFile = GetCatalogFile(); LPSTR pszAtomStr;
if (IsCatalogInstalled()) { bRetval = TRUE; goto Exit; } if (pszCatalogFile && pszCatalogFile[0]) { int cbLen = lstrlen(pszCatalogFile); if (cbLen >= MAX_ATOM_SIZE) { pszAtomStr = pszCatalogFile+cbLen+1-MAX_ATOM_SIZE; } else { pszAtomStr = pszCatalogFile; }
ATOM atom = FindAtom(pszAtomStr); if (!atom) { DEBUG_PRINT(DOWNLOAD, INFO, ("No atom %d for catalog file atom-str: %.200q\n", atom, pszAtomStr )); HRESULT hr = m_wvt.InstallCatalogFile(pszCatalogFile);
if (SUCCEEDED(hr)) { SetCatalogInstalled(); atom = AddAtom(pszAtomStr); SetAtom(atom); bRetval = TRUE; } } else { DEBUG_PRINT(DOWNLOAD, INFO, ("Found atom! %d for catalog file atom-str: %.200q\n", atom, pszAtomStr )); SetCatalogInstalled(); bRetval = TRUE; } } } else { bRetval = TRUE; }
Exit: DEBUG_LEAVE(bRetval); return bRetval; }
HRESULT ExtractFromCabinet(PSESSION ps, LPCSTR lpCabFileName) { LPSTR lpFileName = NULL;
if (ps && ps->pFilesToExtract) lpFileName = ps->pFilesToExtract->pszFilename; DEBUG_ENTER((DBG_DOWNLOAD, None, "ExtractFromCabinet", "%#x, %.80q, %.80q", ps, lpCabFileName, (lpFileName ? lpFileName : "NULL") ));
#ifdef DBG
PFNAME pfName = ps->pFilesToExtract;
while(pfName) { lpFileName = pfName->pszFilename; DEBUG_PRINT(DOWNLOAD, INFO, ("ExtractFromCabinet filename: %.80q \n", (lpFileName ? lpFileName : "NULL") ));
pfName = pfName->pNextName; } #endif
HRESULT hr = ::Extract(ps, lpCabFileName);
#ifdef DBG
if (ps->flags & SESSION_FLAG_EXTRACT_ALL) { pfName = ps->pFileList;
while(pfName) { lpFileName = pfName->pszFilename; DEBUG_PRINT(DOWNLOAD, INFO, ("ExtractFromCabinet ALL: filename: %.80q \n", (lpFileName ? lpFileName : "NULL") ));
pfName = pfName->pNextName; } } #endif
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::CCodeDownload
// CCodeDownload (main class tracking as a whole)
// It has the client's BSC and creates a CClBinding for client.
// ---------------------------------------------------------------------------
CCodeDownload::CCodeDownload( LPCWSTR szDistUnit, LPCWSTR szURL, LPCWSTR szType, LPCWSTR szExt, DWORD dwFileVersionMS, DWORD dwFileVersionLS, HRESULT *phr) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::CCodeDownload", "this=%#x, %.80wq, %.80wq, %.80wq, %.80wq, %#x, %#x, %#x", this, szDistUnit, szURL, szType, szExt, dwFileVersionMS, dwFileVersionLS, phr )); DllAddRef(); m_szLastMod[0] = '\0'; m_plci = NULL;
m_cRef = 1;
m_hr = S_OK; // assume success
m_url = 0;
m_szDistUnit = NULL;
m_pmkContext = NULL;
m_dwFileVersionMS = dwFileVersionMS; m_dwFileVersionLS = dwFileVersionLS;
m_lcid = GetThreadLocale();
DEBUG_PRINT(DOWNLOAD, INFO, ("CCodeDownload::CCodeDownload::this=%#x, m_lcid: %d (%#x)\n", this, m_lcid, m_lcid )); m_flags = CD_FLAGS_INIT;
m_szInf = NULL; m_szOSD = NULL; m_szDisplayName = NULL;
m_szCacheDir = NULL; // set to default of g_szOCXCacheDir by DoSetup
// the non-zeroness of this is also used by DoSetup
// to find it it's state machine has been init'ed
m_szWaitForEXE = NULL;
m_state = CDL_NoOperation;
m_hKeySearchPath = NULL; m_pSearchPath = NULL; m_pSearchPathNextComp = NULL;
m_pDownloads.RemoveAll(); // init to NULL
m_pClientbinding.RemoveAll(); // init to NULL
m_ModuleUsage.RemoveAll(); // init to NULL
m_pDependencies.RemoveAll(); // init to NULL
m_dwSystemComponent = FALSE;
m_pCurCode = m_pAddCodeSection = NULL;
if (szURL) {
DWORD len = lstrlenW(szURL) +1;
if (len <= INTERNET_MAX_URL_LENGTH) {
m_url = new WCHAR [len]; // make private copy
if (m_url) StrCpyW(m_url, szURL); else *phr = E_OUTOFMEMORY; } else { // we make assumptions all over that URL size is less than
// INTERNET_MAX_URL_LENGTH
*phr = E_INVALIDARG; } }
if (szDistUnit) {
DWORD len = lstrlenW(szDistUnit) +1;
m_szDistUnit = new WCHAR [len]; // make private copy
if (m_szDistUnit) StrCpyW(m_szDistUnit, szDistUnit); else *phr = E_OUTOFMEMORY; }
m_pi.hProcess = INVALID_HANDLE_VALUE; m_pi.hThread = INVALID_HANDLE_VALUE;
if (szExt) {
DWORD len = lstrlenW(szExt) +1;
m_szExt = new WCHAR [len]; // make private copy
if (m_szExt) StrCpyW(m_szExt, szExt); else *phr = E_OUTOFMEMORY; }
if (szType) {
DWORD len = lstrlenW(szType) +1;
m_szType = new WCHAR [len]; // make private copy
if (m_szType) StrCpyW(m_szType, szType); else *phr = E_OUTOFMEMORY; }
m_szVersionInManifest = NULL; m_szCatalogFile = NULL; m_dwExpire = 0xFFFFFFFF;
m_pbEtag = NULL; m_pbJavaTrust = NULL; m_debuglog = CDLDebugLog::MakeDebugLog(); if(! m_debuglog) *phr = E_OUTOFMEMORY; else m_debuglog->Init(this); m_bUninstallOld = FALSE; m_bExactVersion = FALSE; m_hModSFC = 0;
m_bCatalogInstalled = FALSE; m_atom = NULL; DEBUG_LEAVE(0); } // CCodeDownload
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::~CCodeDownload
// ---------------------------------------------------------------------------
CCodeDownload::~CCodeDownload() { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::~CCodeDownload", "this=%#x", this )); Assert(m_cRef == 0); if (RelContextMk()) SAFERELEASE(m_pmkContext);
LISTPOSITION pos = m_pClientbinding.GetHeadPosition(); int iNum = m_pClientbinding.GetCount();
for (int i=0; i < iNum; i++) { CClBinding *pbinding = m_pClientbinding.GetNext(pos); // pass ref!
pbinding->ReleaseClient(); pbinding->Release(); } m_pClientbinding.RemoveAll();
pos = m_ModuleUsage.GetHeadPosition(); iNum = m_ModuleUsage.GetCount();
for (i=0; i < iNum; i++) { CModuleUsage *pModuleUsage = m_ModuleUsage.GetNext(pos); // pass ref!
delete pModuleUsage; } m_ModuleUsage.RemoveAll(); // init to NULL
m_pDownloads.RemoveAll(); // init to NULL
pos = m_pDependencies.GetHeadPosition(); iNum = m_pDependencies.GetCount();
for (i=0; i < iNum; i++) { LPWSTR szDistUnit = m_pDependencies.GetNext(pos); delete szDistUnit; }
if (m_szCacheDir != g_szOCXCacheDir) SAFEDELETE(m_szCacheDir);
if (m_hKeySearchPath) ::RegCloseKey(m_hKeySearchPath);
SAFEDELETE(m_szDistUnit);
SAFEDELETE(m_url); SAFEDELETE(m_szType); SAFEDELETE(m_szExt);
SAFEDELETE(m_szVersionInManifest); SAFEDELETE(m_szWaitForEXE);
SAFEDELETE(m_pSearchPath); SAFEDELETE(m_szOSD); SAFEDELETE(m_szInf); SAFEDELETE(m_szDisplayName); SAFEDELETE(m_pAddCodeSection); SAFEDELETE(m_plci); SAFEDELETE(m_pbEtag);
SAFERELEASE(m_pPackageManager); SAFEDELETE(m_szCatalogFile); DllRelease();
if (m_pbJavaTrust) { if (m_pbJavaTrust->pwszZone) { delete (LPWSTR)m_pbJavaTrust->pwszZone; } SAFEDELETE(m_pbJavaTrust->pbSigner); SAFEDELETE(m_pbJavaTrust->pbJavaPermissions); delete m_pbJavaTrust; }
if(m_debuglog) { m_debuglog->Release(); m_debuglog = NULL; }
if (m_hModSFC) { FreeLibrary(m_hModSFC); }
if(m_atom) DeleteAtom(m_atom); DEBUG_LEAVE(0); } // ~CCodeDownload
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetDebugLog()
// Remove the old log and set a new one
// If debuglog is NULL, starts a new log
// ---------------------------------------------------------------------------
void CCodeDownload::SetDebugLog(CDLDebugLog * debuglog) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::SetDebugLog", "this=%#x, %#x", this, debuglog )); CDLDebugLog * pdlNew = NULL;
if(debuglog) pdlNew = debuglog; else { pdlNew = CDLDebugLog::MakeDebugLog(); if(!pdlNew) {
DEBUG_LEAVE(0); // Out of Memory
return; } pdlNew->Init(this); }
if(pdlNew) { m_debuglog->Release(); pdlNew->AddRef(); m_debuglog = pdlNew; } DEBUG_LEAVE(0); }
HRESULT CCodeDownload::CreateClientBinding( CClBinding **ppClientBinding, IBindCtx* pClientBC, IBindStatusCallback* pClientbsc, REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, BOOL fAddHead, IInternetHostSecurityManager *pHostSecurityManager) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::CreateClientBinding", "this=%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %B, %#x", this, ppClientBinding, pClientBC, pClientbsc, &rclsid, dwClsContext, pvReserved, &riid, fAddHead, pHostSecurityManager )); HRESULT hr = S_OK;
Assert(ppClientBinding); *ppClientBinding = NULL;
// make an IBinding for the client
// this gets passed on the OnstartBinding of first download
// as parameter for clientbsc::OnstartBinding
CClBinding *pClientbinding= new CClBinding(this, pClientbsc, pClientBC, rclsid, dwClsContext, pvReserved, riid, pHostSecurityManager);
if (pClientbinding) {
if (fAddHead) { m_pClientbinding.AddHead(pClientbinding); } else { m_pClientbinding.AddTail(pClientbinding); }
} else { hr = E_OUTOFMEMORY; }
*ppClientBinding = pClientbinding;
DEBUG_LEAVE(hr); return hr; }
HRESULT CCodeDownload::AbortBinding( CClBinding *pbinding) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::AbortBinding", "this=%#x, %#x", this, pbinding )); IBindStatusCallback* pbsc; int iNumBindings = m_pClientbinding.GetCount(); ICodeInstall *pCodeInstall; HRESULT hr = S_OK; LISTPOSITION curpos;
Assert(iNumBindings > 1);
if (GetState() == CDL_Completed) { goto Exit; }
curpos = m_pClientbinding.Find(pbinding);
Assert(pbinding == m_pClientbinding.GetAt(curpos));
if (pbinding != m_pClientbinding.GetAt(curpos)) { hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION); goto Exit; }
// now that we know the position of the binding,
// pull out the binding and its related BSC from the list
m_pClientbinding.RemoveAt(curpos);
pbsc = pbinding->GetAssBSC();
// report completion for this binding
// note: if we are called to abort on a thread other than the one that
// initiated the code download, then we report this onstopbinding on the
// aborting thread (this one).
pbsc->OnStopBinding(HRESULT_FROM_WIN32(ERROR_CANCELLED), NULL);
// since we removed this binding from the list
// we have to release this now. This will release the client BSC, BC
pbinding->ReleaseClient(); pbinding->Release();
Exit: DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::PiggybackDupRequest
// piggy backs DUP request on to this exitsing CCodeDownload
// with matching szURL or rclsid
// Returns:
// S_OK: piggyback successful
// Any other error: fatal error: fail
HRESULT CCodeDownload::PiggybackDupRequest( IBindStatusCallback *pDupClientBSC, IBindCtx *pbc, REFCLSID rclsid, DWORD dwClsContext, LPVOID pvReserved, REFIID riid) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::PiggybackDupRequest", "this=%#x, %#x, %#x, %#x, %#x, %#x, %#x", this, pDupClientBSC, pbc, &rclsid, dwClsContext, pvReserved, &riid )); HRESULT hr = S_OK; CClBinding *pClientBinding = NULL;
Assert(m_pClientbinding.GetCount() > 0); if (m_pClientbinding.GetCount() <= 0) { hr = E_UNEXPECTED; goto Exit; }
hr = CreateClientBinding( &pClientBinding, pbc, pDupClientBSC, rclsid, dwClsContext, pvReserved, riid, FALSE /* fAddHead */, NULL);
if (SUCCEEDED(hr)) {
Assert(pClientBinding);
pClientBinding->SetState(CDL_Downloading); pDupClientBSC->OnStartBinding(0, pClientBinding); }
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::AnyCodeDownloadsInThread
// checks if any code downloads are in progress in this thread
// Returns:
// S_OK: yes, downloads in progress
// S_FALSE: none in progress
// Any other error: fatal error: fail
HRESULT CCodeDownload::AnyCodeDownloadsInThread() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::AnyCodeDownloadsInThread", NULL )); HRESULT hr = S_OK;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) { DEBUG_LEAVE(hr); return hr; } int iNumCDL = tls->pCodeDownloadList->GetCount();
if (!iNumCDL) hr = S_FALSE;
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::IsDuplicateJavaSetup
// Returns:
// S_OK: Yes its a DUP
HRESULT CCodeDownload::IsDuplicateJavaSetup( LPCWSTR szPackage) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::IsDuplicateJavaSetup", "this=%#x, %.80wq", this, szPackage )); HRESULT hr = S_FALSE; // assume not found
CDownload *pdlCur = NULL;
LISTPOSITION curpos = m_pDownloads.GetHeadPosition(); for (int i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if (pdlCur->FindJavaSetup(szPackage) != NULL) { hr = S_OK; break; }
}
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::IsDuplicateHook
// Returns:
// S_OK: Yes its a DUP
HRESULT CCodeDownload::IsDuplicateHook( LPCSTR szHook) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::IsDuplicateHook", "this=%#x, %.80q", this, szHook )); HRESULT hr = S_FALSE; // assume not found
CDownload *pdlCur = NULL;
LISTPOSITION curpos = m_pDownloads.GetHeadPosition(); for (int i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if (pdlCur->FindHook(szHook) != NULL) { hr = S_OK; break; }
}
DEBUG_LEAVE(hr); return hr; }
HRESULT SetComponentDeclined( LPCWSTR pwszDistUnit, LPSTR pszSecId) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "SetComponentDeclined", "%.80wq, %.80q", pwszDistUnit, pszSecId )); HRESULT hr = S_FALSE; // assume need to fault in
LPSTR pszDistUnit = NULL; LONG lResult = ERROR_SUCCESS; HKEY hkeyDec = NULL; DWORD dwSize; DWORD dwValue; LPSTR szNull = ""; char szKey[MAX_PATH*2];
if (FAILED((hr=::Unicode2Ansi(pwszDistUnit, &pszDistUnit)))) { goto Exit; }
lstrcpyn(szKey, REGKEY_DECLINED_COMPONENTS, MAX_PATH*2);
#ifndef ENABLE_PERSIST_DECLINED_COMPONNETS
if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_WRITE, &hkeyDec) != ERROR_SUCCESS) { hr = S_OK; goto Exit; } else { if (hkeyDec) { RegCloseKey(hkeyDec); hkeyDec = 0; } } #endif
StrCatBuff(szKey, "\\", MAX_PATH*2); StrCatBuff(szKey, pszDistUnit, MAX_PATH*2);
if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_WRITE, &hkeyDec) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( HKEY_CURRENT_USER, szKey, &hkeyDec)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
if (((lResult = RegSetValueEx (hkeyDec, pszSecId, 0, REG_SZ, (unsigned char *)szNull, 1))) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); }
Exit:
if (hkeyDec) RegCloseKey(hkeyDec);
SAFEDELETE(pszDistUnit);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetUserDeclined
HRESULT CCodeDownload::SetUserDeclined() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetUserDeclined", "this=%#x", this )); HRESULT hr = S_OK; LISTPOSITION pos = m_pClientbinding.GetHeadPosition(); int iNum = m_pClientbinding.GetCount(); int i; BYTE pbSecIdDocBase[INTERNET_MAX_URL_LENGTH]; DWORD dwSecIdDocBase = INTERNET_MAX_URL_LENGTH; IInternetHostSecurityManager *pHostSecurityManager = GetClientBinding()->GetHostSecurityManager();
if (!pHostSecurityManager) { // called by a host without sec mgr, don't record that you have
// declined this component
goto Exit; }
hr = pHostSecurityManager->GetSecurityId(pbSecIdDocBase, &dwSecIdDocBase, 0);
Assert(hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
if (FAILED(hr)) goto Exit;
// Hack!
// Assumes internal knowledge of security id
// the security has the zone id as the last dword, the rest of the stuff is
// just the protocol followed by the site
if (dwSecIdDocBase - sizeof(DWORD)) { pbSecIdDocBase[dwSecIdDocBase - sizeof(DWORD)] = '\0'; }
if (GetMainDistUnit()) { hr = SetComponentDeclined(GetMainDistUnit(), (char *)pbSecIdDocBase);
if (FAILED(hr)) goto Exit; }
if (GetMainType()) { hr = SetComponentDeclined(GetMainType(), (char *)pbSecIdDocBase);
if (FAILED(hr)) goto Exit; }
if (GetMainExt()) { hr = SetComponentDeclined(GetMainExt(), (char *)pbSecIdDocBase);
if (FAILED(hr)) goto Exit; }
for (i=0; i < iNum; i++) {
CClBinding *pbinding = m_pClientbinding.GetNext(pos); // pass ref!
LPOLESTR pwszClsid;
pwszClsid = NULL;
if (!IsEqualGUID(pbinding->GetClsid() , CLSID_NULL)) {
hr=StringFromCLSID(pbinding->GetClsid(), &pwszClsid);
if (FAILED(hr)) goto Exit;
hr = SetComponentDeclined(pwszClsid, (char *)pbSecIdDocBase); SAFEDELETE(pwszClsid);
if (FAILED(hr)) goto Exit; } }
Exit:
DEBUG_LEAVE(hr); return hr; }
BOOL IsDeclined( LPCWSTR pwszDistUnit, IInternetHostSecurityManager *pHostSecurityManager) { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "IsDeclined", "%.80wq, %#x", pwszDistUnit, pHostSecurityManager )); BOOL bDeclined = FALSE; LPSTR pszDistUnit = NULL; BYTE pbSecIdDocBase[INTERNET_MAX_URL_LENGTH]; DWORD dwSecIdDocBase = INTERNET_MAX_URL_LENGTH; HRESULT hr = S_OK; char szKey[MAX_PATH*2];
Assert(pHostSecurityManager);
hr = pHostSecurityManager->GetSecurityId(pbSecIdDocBase, &dwSecIdDocBase, 0);
Assert(hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
if (FAILED(hr)) goto Exit;
// Hack!
// Assumes internal knowledge of security id
// the security has the zone id as the last dword, the rest of the stuff is
// just the protocol followed by the site
if (dwSecIdDocBase - sizeof(DWORD)) { pbSecIdDocBase[dwSecIdDocBase - sizeof(DWORD)] = '\0'; }
lstrcpyn(szKey, REGKEY_DECLINED_COMPONENTS, MAX_PATH*2);
if (SUCCEEDED(::Unicode2Ansi(pwszDistUnit, &pszDistUnit))) { StrCatBuff(szKey, "\\", MAX_PATH*2); StrCatBuff(szKey, pszDistUnit, MAX_PATH*2);
SAFEDELETE(pszDistUnit);
if (SHRegGetUSValue( szKey, (char *)pbSecIdDocBase, NULL, NULL, NULL, 0,NULL,0) == ERROR_SUCCESS) { bDeclined = TRUE; } }
Exit:
DEBUG_LEAVE(bDeclined); return bDeclined; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::HasUserDeclined
HRESULT CCodeDownload::HasUserDeclined( LPCWSTR szDistUnit, LPCWSTR szType, LPCWSTR szExt, IBindStatusCallback *pClientBSC, IInternetHostSecurityManager *pHostSecurityManager) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::HasUserDeclined", "%.80wq, %.80wq, %.80wq, %#x, %#x", szDistUnit, szType, szExt, pClientBSC, pHostSecurityManager ));
HRESULT hr = S_OK; DWORD grfBINDF = 0; BINDINFO bindInfo; memset(&bindInfo, 0, sizeof(BINDINFO)); bindInfo.cbSize = sizeof(BINDINFO);
if (pHostSecurityManager) {
pClientBSC->GetBindInfo(&grfBINDF, &bindInfo);
ReleaseBindInfo(&bindInfo);
if (!(grfBINDF & BINDF_RESYNCHRONIZE)) { // User has hit refresh
if ((szDistUnit && IsDeclined(szDistUnit,pHostSecurityManager)) || (szType && IsDeclined(szType,pHostSecurityManager)) || (szExt && IsDeclined(szExt,pHostSecurityManager))) {
hr = INET_E_CODE_DOWNLOAD_DECLINED;
} } }
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::HandleDuplicateCodeDownloads
// handles duplicates by piggy backing them on to exitsing CCodeDownloads
// with matching szURL or rclsid
// Returns:
// S_OK: no dups found, do separate code download
// MK_S_ASYNCHRONOUS: dup piggybacked
// Any other error: fatal error: fail
HRESULT CCodeDownload::HandleDuplicateCodeDownloads( LPCWSTR szURL, LPCWSTR szType, LPCWSTR szExt, REFCLSID rclsid, LPCWSTR szDistUnit, DWORD dwClsContext, LPVOID pvReserved, REFIID riid, IBindCtx* pbc, IBindStatusCallback *pDupClientBSC, DWORD dwFlags, IInternetHostSecurityManager *pHostSecurityManager) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::HandleDuplicateCodeDownloads", "%.80wq, %.80wq, %.80wq, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x, %#x, %#x", szURL, szType, szExt, &rclsid, szDistUnit, dwClsContext, pvReserved, &riid, pbc, pDupClientBSC, dwFlags, pHostSecurityManager )); HRESULT hr = S_OK; LISTPOSITION curpos; CCodeDownload *pcdl; int iNumCDL; int i;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) goto Exit;
// first check to make sure that
// this object has not been cancelled before by user
// we will skip this check only when the user hits refresh on a page
if (!(dwFlags & CD_FLAGS_SKIP_DECLINED_LIST_CHECK)) { hr = HasUserDeclined(szDistUnit, szType, szExt,pDupClientBSC,pHostSecurityManager); if (FAILED(hr)) goto Exit; }
iNumCDL = tls->pCodeDownloadList->GetCount(); curpos = tls->pCodeDownloadList->GetHeadPosition();
// walk thru all the code downloads in the thread and check for DUPs
for (i=0; i < iNumCDL; i++) {
pcdl = tls->pCodeDownloadList->GetNext(curpos);
BOOL bNullClsid = IsEqualGUID(rclsid , CLSID_NULL);
if (bNullClsid) {
// handle dups based on TYPE and Ext
if (! ( ( szDistUnit && pcdl->GetMainDistUnit() && (StrCmpIW(szDistUnit, pcdl->GetMainDistUnit()) == 0)) || ( szType && pcdl->GetMainType() && (StrCmpIW(szType, pcdl->GetMainType()) == 0)) || ( szExt && pcdl->GetMainExt() && (StrCmpIW(szExt, pcdl->GetMainExt()) == 0)) ) ) {
// no match by type or ext
continue; }
// found match, fall thru to piggyback
} else if (IsEqualGUID(rclsid , pcdl->GetClsid())) {
if (szURL) {
if(StrCmpIW(szURL, pcdl->GetMainURL()) != 0) { pcdl->m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_OBJ_TAG_MIXED_USAGE, (pcdl->GetClsid()).Data1,szURL, pcdl->GetMainURL());
}
} else {
if(pcdl->GetMainURL() != NULL) {
pcdl->m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_OBJ_TAG_MIXED_USAGE, (pcdl->GetClsid()).Data1, pcdl->GetMainURL(), NULL);
} }
// found matching GUID, fall thru to piggyback
} else if (szURL && (pcdl->GetMainURL() != NULL)) {
if (StrCmpIW(szURL, pcdl->GetMainURL()) != 0) { continue; }
// found matching CODEBASE, fall thru to piggyback
} else { continue; }
// found DUP!
if (pcdl->GetState() != CDL_Completed) { hr = pcdl->PiggybackDupRequest(pDupClientBSC, pbc, rclsid, dwClsContext, pvReserved, riid);
if (hr == S_OK) { // piggy back was successful
hr = MK_S_ASYNCHRONOUS; } }
break;
} /* for */
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetWaitingForEXE
// set that we are waiting for an EXE
// either a self-registering localserver32 or a setup program
HRESULT CCodeDownload::SetWaitingForEXE( LPCSTR szEXE, BOOL bDeleteEXEWhenDone) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetWaitingForEXE", "this=%#x, %.80q, %B", this, szEXE, bDeleteEXEWhenDone )); m_flags |= CD_FLAGS_WAITING_FOR_EXE;
SAFEDELETE(m_szWaitForEXE);
int len = 0;
if (szEXE) len = lstrlen(szEXE);
if (len) { m_szWaitForEXE = new CHAR [len + 1]; } else { DEBUG_LEAVE(E_INVALIDARG); return E_INVALIDARG; }
if (!m_szWaitForEXE) { DEBUG_LEAVE(E_OUTOFMEMORY); return E_OUTOFMEMORY; }
lstrcpy(m_szWaitForEXE, szEXE);
if (bDeleteEXEWhenDone) SetDeleteEXEWhenDone();
DEBUG_LEAVE(S_OK); return S_OK; }
typedef HRESULT (STDAPICALLTYPE *LPFNREGSVR)();
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::RegisterPEDll
// Self-register's the PE OCX.
HRESULT CCodeDownload::RegisterPEDll( LPCSTR lpSrcFileName) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::RegisterPEDll", "this=%#x, %.80q", this, lpSrcFileName )); HMODULE hMod; LPFNREGSVR lpRegSvrFn; HRESULT hr = S_OK; IActiveXSafetyProvider *pProvider;
if ((hr = IsRegisterableDLL(lpSrcFileName)) != S_OK) {
// no DllRegisterServer entry point, don't LoadLibarary it.
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_MISSING_DLLREGISTERSERVER, lpSrcFileName); goto Exit; }
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DLL_REGISTERED, lpSrcFileName);
// assuming oleinitialze
hr = GetActiveXSafetyProvider(&pProvider); if (hr != S_OK) { goto Exit; }
if (pProvider) {
hr = pProvider->SafeDllRegisterServerA(lpSrcFileName); pProvider->Release();
} else { if ((hMod = LoadLibraryEx(lpSrcFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
lpRegSvrFn = (LPFNREGSVR) GetProcAddress(hMod, "DllRegisterServer"); if (lpRegSvrFn == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); }
if (lpRegSvrFn) hr = (*lpRegSvrFn)();
FreeLibrary(hMod); }
Exit:
DEBUG_LEAVE(hr); return hr; }
#ifdef WX86
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::RegisterWx86Dll
// Self-register's the PE OCX.
HRESULT CCodeDownload::RegisterWx86Dll( LPCSTR lpSrcFileName) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::RegisterWx86Dll", "this=%#x, %.80q", this, lpSrcFileName )); HMODULE hModWx86; HMODULE hMod; FARPROC lpfnDllRegisterServerX86; FARPROC lpfnDllRegisterServer; HRESULT hr = S_OK; LPWSTR lpwSrcFileName;
typedef HMODULE (*pfnLoadFn)(LPCWSTR name, DWORD dwFlags); typedef PVOID (*pfnThunkFn)(PVOID pvAddress, PVOID pvCbDispatch, BOOLEAN fNativeToX86); typedef BOOL (*pfnUnloadFn)(HMODULE hMod); pfnLoadFn pfnLoad; pfnThunkFn pfnThunk; pfnUnloadFn pfnUnload;
if ((hr = IsRegisterableDLL(lpSrcFileName)) != S_OK) {
// no DllRegisterServer entry point, don't LoadLibarary it.
CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_MISSING_DLLREGISTERSERVER, lpSrcFileName); goto Exit; }
// Load Wx86 and get pointers to some useful exports
hModWx86 = LoadLibrary("wx86.dll"); if (!hModWx86) { hr = HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH); CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_INCOMPATIBLE_BINARY, lpSrcFileName); goto Exit; } pfnLoad = (pfnLoadFn)GetProcAddress(hModWx86, "Wx86LoadX86Dll"); pfnThunk = (pfnThunkFn)GetProcAddress(hModWx86, "Wx86ThunkProc"); pfnUnload = (pfnUnloadFn)GetProcAddress(hModWx86, "Wx86FreeX86Dll"); if (!pfnLoad || !pfnThunk || !pfnUnload) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit1; }
CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DLL_REGISTERED, lpSrcFileName);
// assuming oleinitialze
if (FAILED((hr=::Ansi2Unicode(lpSrcFileName, &lpwSrcFileName)))) { goto Exit1; }
if ((hMod = (*pfnLoad)(lpwSrcFileName, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit1; }
delete lpwSrcFileName;
if ( (lpfnDllRegisterServerX86 = GetProcAddress( hMod, "DllRegisterServer")) == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); }
if (lpfnDllRegisterServerX86) { //
// lpfnDllRegisterServerX86 is a pointer to an x86 function which
// takes no parameters. Create a native-to-x86 thunk for it.
//
lpfnDllRegisterServer = (FARPROC)(*pfnThunk)(lpfnDllRegisterServerX86, (PVOID)0, TRUE ); if (lpfnDllRegisterServer == (FARPROC)-1) { //
// Something went wrong. Possibly out-of-memory.
//
hr = E_UNEXPECTED; goto Exit1; }
hr = (*lpfnDllRegisterServer)(); }
(*pfnUnload)(hMod);
Exit1: FreeLibrary(hModWx86);
Exit:
DEBUG_LEAVE(hr); return hr; } #endif //WX86
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::DelayRegisterOCX
// Self-register's the OCX.
HRESULT CCodeDownload::DelayRegisterOCX( LPCSTR pszSrcFileName, FILEXTN extn) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::DelayRegisterOCX", "this=%#x, %.80q, %#x", this, pszSrcFileName, extn )); HRESULT hr = S_OK; HKEY hKeyRunOnce = NULL; int line = 0; char szPath[MAX_PATH]; char lpszCmdLine[2*MAX_PATH]; char lpSrcFileName[MAX_PATH]; char szTgtFileName[MAX_PATH]; DWORD dwTmp; const char *szICDRUNONCE = "ICDRegOCX%d"; const char *szICDRUNDLL="rundll32.exe advpack.dll,RegisterOCX %s";
// See comment in UpdateFileList to see why this is necessary
// The reason we do this here is the same, except we need to use
// the ANSI code page for regsvr32 this time.
//pszSrcFileName restricted to MAX_PATH in context of use (See CSetup::DoSetup)
if (g_bRunOnWin95) { OemToCharBuff(pszSrcFileName, lpSrcFileName, sizeof(lpSrcFileName) / sizeof(lpSrcFileName[0])); lstrcpy(szTgtFileName, lpSrcFileName); } else { lstrcpy(szTgtFileName, pszSrcFileName); }
if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, (ULONG)0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyRunOnce, &dwTmp ) != ERROR_SUCCESS ) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
// Check if key already exists -- if so, go with next number.
//
for (;;) { wsprintf( szPath, szICDRUNONCE, line++ ); if ( RegQueryValueEx( hKeyRunOnce, szPath, 0, NULL, NULL, &dwTmp ) != ERROR_SUCCESS ) { break; } }
#ifdef WX86
if (GetMultiArch()->GetRequiredArch() == PROCESSOR_ARCHITECTURE_INTEL) { char szSysDirX86[MAX_PATH];
// An x86 control is downloading. Tell GetSystemDirectory
// to return the sys32x86 dir instead of system32
NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = TRUE; GetSystemDirectory(szSysDirX86, MAX_PATH);
// Run the RISC rundll32.exe but specify the fully-qualified name of
// the x86 advpack.dll installed in %windir%\sys32x86. RISC rundll32
// is Wx86-aware and will load and run the x86 DLL.
wnsprintf( lpszCmdLine, sizeof(lpszCmdLine)-1, "rundll32.exe %s\advpack.dll,RegisterOCX %s", szSysDirX86, szTgtFileName );
} else { wnsprintf( lpszCmdLine, sizeof(lpszCmdLine)-1, szICDRUNDLL, szTgtFileName ); } #else
wnsprintf( lpszCmdLine, sizeof(lpszCmdLine)-1, szICDRUNDLL, szTgtFileName ); #endif
if ( RegSetValueEx( hKeyRunOnce, szPath, 0, REG_SZ, (CONST UCHAR *) lpszCmdLine, lstrlen(lpszCmdLine)+1 ) != ERROR_SUCCESS ) {
hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
Exit:
if ( hKeyRunOnce != NULL ) { RegCloseKey( hKeyRunOnce ); }
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::InstallOCX
// Self-register's the OCX.
HRESULT CCodeDownload::InstallOCX( LPCSTR lpSrcFileName, FILEXTN extn, BOOL bLocalServer) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::InstallOCX", "this=%#x, %.80q, %#x, %B", this, lpSrcFileName, extn, bLocalServer )); HMODULE hMod; FARPROC lpfnDllRegisterServer; HRESULT hr = S_OK; const static char *szREGSVR = " /RegServer"; char szCmdLine[MAX_PATH+sizeof(szREGSVR)]; STARTUPINFO si; DWORD dwResult; DWORD dwMachineType = 0;
switch (extn) {
case FILEXTN_CAB: case FILEXTN_INF:
// can't install cab or INF
hr = E_INVALIDARG; break;
case FILEXTN_EXE:
//lpSrcFileName constrained to MAX_PATH in context of use (See CSetup::DoSetup)
lstrcpy(szCmdLine, lpSrcFileName); if (bLocalServer) lstrcat(szCmdLine, szREGSVR);
memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
if (!CreateProcess(NULL, szCmdLine, 0, // security
0, // security
FALSE, // Don't inherit my handles!
0, // Creation flags
NULL, // env = inherit
NULL, // cur dir. = inherit
&si, // no startup info
&m_pi)) {
hr = HRESULT_FROM_WIN32(GetLastError());
} else {
hr = SetWaitingForEXE(lpSrcFileName, !bLocalServer); }
goto Exit;
case FILEXTN_OCX: case FILEXTN_DLL: case FILEXTN_NONE: case FILEXTN_UNKNOWN:
// sniff machine type of PE
hr = IsCompatibleFile(lpSrcFileName, &dwMachineType);
if (hr == HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH)) {
// if its of worng CPU flavor fail and clean up the OCX
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_INCOMPATIBLE_BINARY, lpSrcFileName); break; }
if (hr == S_FALSE) { // not a PE file, no need to call LoadLibrary
// just copy and install the file
break; }
#ifdef WX86
if (g_fWx86Present && dwMachineType == IMAGE_FILE_MACHINE_I386) hr = RegisterWx86Dll(lpSrcFileName); else #endif
hr = RegisterPEDll(lpSrcFileName);
}
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::HandleUnSafeAbort
HRESULT CCodeDownload::HandleUnSafeAbort() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::HandleUnSafeAbort", "this=%#x", this )); HRESULT hr = S_FALSE; ICodeInstall* pCodeInstall = GetICodeInstall();
if(WaitingForEXE()) { // Did the setup start a self-registering EXE?
// we are waiting for an EXE to complete self-registering
// notify client of condition and maybe it wants to
// ask the user if (s)he wants to wait for the EXE or abort
// download
// we never kill the EXE though we just ignore it
if (pCodeInstall) { WCHAR szBuf[MAX_PATH];
szBuf[0] = '\0';
if (m_szWaitForEXE) { MultiByteToWideChar(CP_ACP, 0, m_szWaitForEXE, -1, szBuf, MAX_PATH); } hr = pCodeInstall->OnCodeInstallProblem( CIP_EXE_SELF_REGISTERATION_TIMEOUT, NULL, szBuf, 0); } else { hr = S_FALSE; // assume skip EXE and proceed
}
if (hr == S_OK) // continue to wait?
{ DEBUG_LEAVE(S_FALSE); return S_FALSE; // yes
} // if hr == S_FALSE/E_ABORT ignore this EXE and try to proceed with
// rest of installation
if (m_pi.hProcess != INVALID_HANDLE_VALUE) { CloseHandle(m_pi.hProcess); m_pi.hProcess = INVALID_HANDLE_VALUE; } if (m_pi.hThread != INVALID_HANDLE_VALUE) { CloseHandle(m_pi.hThread); m_pi.hThread = INVALID_HANDLE_VALUE; } SetNotWaitingForEXE();
m_hr = E_ABORT; CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP, this, 0);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
DEBUG_LEAVE(hr); return hr; }
if (pCodeInstall) { hr = pCodeInstall->OnCodeInstallProblem(CIP_UNSAFE_TO_ABORT, NULL, NULL, 0); } else { hr = E_ABORT; }
if (hr == S_OK) { hr = S_FALSE; } else { SetUserCancelled(); hr = E_ABORT; }
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SelfRegEXETimeout
HRESULT CCodeDownload::SelfRegEXETimeout() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SelfRegEXETimeout", "this=%#x", this )); HRESULT hr = S_OK;
if (!WaitingForEXE()) { DEBUG_LEAVE(hr); return S_FALSE; } Assert(m_pi.hProcess != INVALID_HANDLE_VALUE); DWORD dwResult = WaitForSingleObject(m_pi.hProcess, 0);
if (dwResult != WAIT_OBJECT_0) {
// the EXE has not yet completed.
// just wait for it till we get it or client calls
// IClientBinding::Abort()
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_WAIT_FOR_EXE, this,0);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
DEBUG_LEAVE(hr); return hr; }
if (!GetExitCodeProcess(m_pi.hProcess, &dwResult)) dwResult = GetLastError();
if (m_pi.hProcess != INVALID_HANDLE_VALUE) { CloseHandle(m_pi.hProcess); m_pi.hProcess = INVALID_HANDLE_VALUE; } if (m_pi.hThread != INVALID_HANDLE_VALUE) { CloseHandle(m_pi.hThread); m_pi.hThread = INVALID_HANDLE_VALUE; }
SetNotWaitingForEXE();
if (DeleteEXEWhenDone()) { DeleteFile(m_szWaitForEXE); ResetDeleteEXEWhenDone(); }
hr = HRESULT_FROM_WIN32(dwResult);
if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED) ) { SetRebootRequired(); hr = S_OK; }
m_hr = hr; CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP, this, 0);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
Assert(SUCCEEDED(hr));
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetManifest()
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::SetManifest(FILEXTN extn, LPCSTR szManifest) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetManifest", "this=%#x, %#x, %.80q", this, extn, szManifest )); HRESULT hr = S_OK;
LPSTR szFile = new char [lstrlen(szManifest)+1];
if (!szFile) { hr = E_OUTOFMEMORY; goto Exit; }
lstrcpy(szFile, szManifest);
if (extn == FILEXTN_INF) { SAFEDELETE(m_szInf); m_szInf = szFile; } else { SAFEDELETE(m_szOSD); m_szOSD = szFile; }
Exit:
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::VersionFromManifest
// ---------------------------------------------------------------------------
BOOL CCodeDownload::VersionFromManifest(LPSTR szVersionInManifest, int iLen) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::VersionFromManifest", "this=%#x, %.80q", this, szVersionInManifest ));
if (m_szVersionInManifest) {
StrNCpy(szVersionInManifest, m_szVersionInManifest, iLen);
DEBUG_LEAVE(TRUE); return TRUE; }
DEBUG_LEAVE(FALSE); return FALSE; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ProcessJavaManifest
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ProcessJavaManifest(IXMLElement *pJava, const char *szOSD, char *szOSDBaseName, CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ProcessJavaManifest", "this=%#x, %#x, %.80q, %.80q, %#x", this, pJava, szOSD, szOSDBaseName, pdl )); HRESULT hr = S_OK; IXMLElement *pPackage = NULL, *pElemTmp = NULL, *pConfig = NULL; CDownload *pdlCur = NULL; LPWSTR szPackageName = NULL; char szPackageVersion[MAX_PATH]; DWORD dwVersionMS = 0, dwVersionLS = 0, dwJavaFlags = 0; int nLastPackage, nLastConfig; CCodeBaseHold *pcbh = NULL; char szPackageURLA[INTERNET_MAX_URL_LENGTH]; char *pBaseFileName = NULL; LPWSTR pszNameSpace = NULL; CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL; BOOL bDestroyPCBHList = FALSE; int iCount = 0;
if (!pdl->HasJavaPermissions()) {
if (IsSilentMode()) { SetBitsInCache(); } else {
hr = TRUST_E_FAIL; goto Exit; } }
hr = GetTextContent(pJava, DU_TAG_NAMESPACE, &pszNameSpace);
if (FAILED(hr)) goto Exit;
// while more packages
nLastPackage = -1; while( (GetNextChildTag(pJava, DU_TAG_PACKAGE, &pPackage, nLastPackage)) == S_OK) {
SAFEDELETE(szPackageName);
// process package
hr = DupAttribute(pPackage, DU_ATTRIB_NAME, &szPackageName); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_JAVAPACKAGE_SYNTAX);
if (GetAttributeA(pPackage, DU_ATTRIB_VERSION, szPackageVersion, MAX_PATH) == S_OK) {
hr = GetVersionFromString(szPackageVersion, &dwVersionMS, &dwVersionLS); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_JAVAPACKAGE_SYNTAX); } else { hr = E_INVALIDARG; CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_JAVAPACKAGE_SYNTAX); }
if (GetFirstChildTag(pPackage, DU_TAG_SYSTEM, &pElemTmp) == S_OK) { m_dwSystemComponent = TRUE; SAFERELEASE(pElemTmp); }
// check if package of right version is already locally installed
// if so go to next package
hr = IsPackageLocallyInstalled(szPackageName, pszNameSpace, dwVersionMS, dwVersionLS);
if (FAILED(hr)) goto Exit;
if (hr == S_OK) {
// OK, so this package that is reqd by this dist unit
// is already present on machine
// we still need to create a NOSETUP JavaSetup obj just so
// it gets marked as belonging to/used by this dist unit.
// for a NOSETUP CJavaSetup it doesn't matter which pdl it gets
// added on to.
hr = pdl->AddJavaSetup(szPackageName, pszNameSpace, pPackage, dwVersionMS, dwVersionLS, CJS_FLAG_NOSETUP);
if (FAILED(hr)) goto Exit;
goto nextPackage; }
hr = S_OK; // reset
// else, make a CJavaSetup for each package that needs to be installed
// also make sure that the CABs in those packages are downloaded
nLastConfig = -1;
// OR all NEEDSTRUSTEDSOURCE & SYSTEM flags from all CONFIG's since there may be
// multiple CODEBASE's.
dwJavaFlags = CJS_FLAG_INIT;
if (m_dwSystemComponent) { dwJavaFlags |= CJS_FLAG_SYSTEM; }
if (GetFirstChildTag(pPackage, DU_TAG_NEEDSTRUSTEDSOURCE, &pElemTmp) == S_OK) { dwJavaFlags |= CJS_FLAG_NEEDSTRUSTEDSOURCE; SAFERELEASE(pElemTmp); }
// If no CODEBASE specified in CONFIG, add Setup of Java package to this download.
pdlCur = pdl;
while (GetNextChildTag(pPackage, DU_TAG_CONFIG, &pConfig, nLastConfig) == S_OK) {
// This is destroyed by destructor of DoDownload called
if (bDestroyPCBHList) { DestroyPCBHList(pcbhList); SAFEDELETE(pcbhList); } pcbhList = new CList<CCodeBaseHold *, CCodeBaseHold *>; if (pcbhList == NULL) { hr = E_OUTOFMEMORY; goto Exit; } bDestroyPCBHList = TRUE; pcbhList->RemoveAll();
if (ProcessImplementation(pConfig, pcbhList, m_lcid #ifdef WX86
, GetMultiArch() #endif
) == S_OK) {
iCount = pcbhList->GetCount(); if (iCount) { pcbh = pcbhList->GetHead(); pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED; } else { pcbh = NULL; }
if (pcbh && pcbh->wszCodeBase) {
WideCharToMultiByte(CP_ACP, 0, pcbh->wszCodeBase, -1, szPackageURLA, sizeof(szPackageURLA),NULL, NULL);
FILEXTN extn = ::GetExtnAndBaseFileName(szPackageURLA, &pBaseFileName);
if (extn != FILEXTN_CAB) { hr = E_INVALIDARG; goto Exit; }
if (pcbh->bHREF) { // CODEBASE HREF="..." download CAB with java package
hr = FindCABInDownloadList(pcbh->wszCodeBase, pdl, &pdlCur);
if (FAILED(hr)) goto Exit;
if (!pdlCur) {
// did not find CAB
// fresh CAB needs to get pulled down.
pdlCur = new CDownload(pcbh->wszCodeBase, extn, &hr); if (!pdlCur) { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) { SAFEDELETE(pdlCur); goto Exit; }
AddDownloadToList(pdlCur);
{ BOOL bSetOnStack = SetOnStack(); bDestroyPCBHList = FALSE; hr = pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE), pcbhList); if (bSetOnStack) ResetOnStack(); }
}
}
if (FAILED(hr)) { goto Exit; }
} else { // found a valid config but no CODEBASE
// assume that the pkg is in 'thiscab'
// goto add package
}
goto addPackage;
} // Got CONFIG tag successfully
SAFERELEASE(pConfig);
} // <CONFIG> tag loop
if (SUCCEEDED(hr)) { hr = HRESULT_FROM_WIN32(ERROR_APP_WRONG_OS); }
goto nextPackage;
addPackage: hr = pdlCur->AddJavaSetup(szPackageName, pszNameSpace, pPackage, dwVersionMS, dwVersionLS, dwJavaFlags);
nextPackage: SAFERELEASE(pPackage); SAFERELEASE(pConfig);
if (FAILED(hr)) break;
if (hr == S_FALSE) hr = S_OK; // reset
} // <PACKAGE> tag loop
Exit: SAFERELEASE(pConfig); SAFERELEASE(pPackage);
SAFEDELETE(szPackageName); SAFEDELETE(pszNameSpace);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ProcessDependency
// Processes <dependency> tag and spins off any dependency code downloads
// as appropriate.
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ProcessDependency(CDownload *pdl, IXMLElement *pDepend) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ProcessDependency", "this=%#x, %#x, %#x", this, pdl, pDepend )); HRESULT hr = S_OK; int nLast2, nLast3; BOOL fAssert = FALSE, fInstall = FALSE; IXMLElement *pSoftDist2 = NULL, *pLang = NULL, *pConfig = NULL; LPWSTR szDistUnit = NULL; LPWSTR pwszURL = NULL; LPSTR szLanguages = NULL; LPSTR pBaseFileName = NULL; WCHAR szCDLURL[2*INTERNET_MAX_URL_LENGTH]; WCHAR wszURLBuf[2*INTERNET_MAX_URL_LENGTH]; WCHAR szResult[INTERNET_MAX_URL_LENGTH]; DWORD dwSize = 0; DWORD dwVersionMS = 0, dwVersionLS = 0, dwStyle; CDownload *pdlCur = NULL; CLSID inclsid = CLSID_NULL; CCodeBaseHold *pcbh = NULL; CLocalComponentInfo lci; int i, iCount = 0, iLen = 0; LISTPOSITION lpos = 0; CCodeBaseHold *pcbhCur = NULL; LPWSTR pwszStr = NULL; CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL; BOOL bDestroyPCBHList = FALSE; LPWSTR pwszVersion = NULL;
union { char szAction[MAX_PATH]; char szVersion[MAX_PATH]; char szStyle[MAX_PATH]; char szPackageURLA[INTERNET_MAX_URL_LENGTH]; };
if (SUCCEEDED(GetAttributeA(pDepend, DU_ATTRIB_ACTION, szAction, MAX_PATH))) {
if (lstrcmpi(szAction, "ASSERT") == 0) fAssert = TRUE; else if (lstrcmpi(szAction, "INSTALL") == 0) fInstall = TRUE; else goto Exit; } else fAssert = TRUE;
nLast2 = -1; while (GetNextChildTag(pDepend, DU_TAG_SOFTDIST, &pSoftDist2, nLast2) == S_OK) {
if (FAILED(hr)) break;
// get NAME attribute
hr = DupAttribute(pSoftDist2, DU_ATTRIB_NAME, &szDistUnit); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DEPENDENCY_SYNTAX);
// get VERSION attribute
hr = GetAttributeA(pSoftDist2, DU_ATTRIB_VERSION, szVersion, MAX_PATH); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DEPENDENCY_SYNTAX);
// convert VERSION string
hr = GetVersionFromString(szVersion, &dwVersionMS, &dwVersionLS); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DEPENDENCY_SYNTAX);
// remember the version string in uni
hr = Ansi2Unicode(szVersion, &pwszVersion); if (FAILED(hr)) goto Exit;
// get STYLE attribute
if (SUCCEEDED(GetAttributeA(pSoftDist2, DU_ATTRIB_STYLE, szStyle, MAX_PATH))) { (void) GetStyleFromString(szStyle, &dwStyle); } else dwStyle = STYLE_MSICD;
// Check if distribution unit is currently installed
// NOTE: This assumes MSICD
inclsid = CLSID_NULL; CLSIDFromString((LPOLESTR)szDistUnit, &inclsid);
if ((hr = IsControlLocallyInstalled(NULL, (LPCLSID)&inclsid, szDistUnit, dwVersionMS, dwVersionLS, &lci, NULL)) != S_FALSE) {
// add distribution unit as a dependency
AddDistUnitList(szDistUnit);
goto nextDepend; }
// if Action=ASSERT and we don't have distribution unit, then skip this <softdist>.
if (fAssert) { hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); goto Exit; }
// minimal check for circular dependency
if (StrCmpIW(szDistUnit, m_szDistUnit)==0) { hr = HRESULT_FROM_WIN32(ERROR_CIRCULAR_DEPENDENCY); goto Exit; }
// process CONFIG tags
nLast3 = -1; pcbh = NULL; while (GetNextChildTag(pSoftDist2, DU_TAG_CONFIG, &pConfig, nLast3) == S_OK) { if (bDestroyPCBHList) { DestroyPCBHList(pcbhList); SAFEDELETE(pcbhList); } pcbhList = new CList<CCodeBaseHold *, CCodeBaseHold *>; if (pcbhList == NULL) { hr = E_OUTOFMEMORY; goto Exit; } bDestroyPCBHList = TRUE; pcbhList->RemoveAll();
pcbh = NULL; hr = ProcessImplementation(pConfig, pcbhList, m_lcid #ifdef WX86
, GetMultiArch() #endif
);
if (SUCCEEDED(hr)) { iCount = pcbhList->GetCount(); if (iCount) { pcbh = pcbhList->GetHead(); pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED; } else { pcbh = NULL; } } SAFERELEASE(pConfig);
if (hr == S_OK) {
szPackageURLA[0] = '\0';
//BUGBUG: If no CODEBASE how do we know extension? Assuming it is CAB
FILEXTN extn = FILEXTN_CAB;
if (pcbh && pcbh->wszCodeBase && pcbh->bHREF) {
WideCharToMultiByte(CP_ACP, 0, pcbh->wszCodeBase, -1, szPackageURLA, INTERNET_MAX_URL_LENGTH,NULL, NULL);
extn = ::GetExtnAndBaseFileName(szPackageURLA, &pBaseFileName);
}
// "cdl:[clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx];"
// we use: "cdl:distunit=xxxx[|codebase=xxxx]"
// BUGBUG: We could mess up CDLProtocol if any of these embedded fields are
// illformatted (contains '=' or '\\' or '//').
// cdl: protocol treats clsid as DistUnit name if not a valid CLSID.
StrCpyW(szCDLURL, L"cdl:distunit="); StrCatBuffW(szCDLURL, szDistUnit, 2*INTERNET_MAX_URL_LENGTH); StrCatBuffW(szCDLURL, L";version=", 2*INTERNET_MAX_URL_LENGTH); StrCatBuffW(szCDLURL, pwszVersion, 2*INTERNET_MAX_URL_LENGTH);
if (szPackageURLA[0]) { StrCatBuffW(szCDLURL, L";codebase=", 2*INTERNET_MAX_URL_LENGTH); if (SUCCEEDED(GetContextMoniker()->GetDisplayName(NULL, NULL, &pwszURL))) { dwSize = INTERNET_MAX_URL_LENGTH; if(FAILED(UrlCombineW(pwszURL, pcbh->wszCodeBase, szResult, &dwSize, 0))) { hr = E_UNEXPECTED; goto Exit; } StrCatBuffW(szCDLURL, szResult, 2*INTERNET_MAX_URL_LENGTH); SAFEDELETE(pwszURL); } else { // A context moniker should always exist if we
// are looking at a dependency.
hr = E_UNEXPECTED; goto Exit; } }
// Iterate over all codebases in the list, and covert them
// to CDL: protocols instead of HTTP:.
lpos = pcbhList->GetHeadPosition(); while (lpos) { pcbhCur = pcbhList->GetNext(lpos); if (pcbhCur != NULL) { StrCpyW(wszURLBuf, L"cdl:distunit="); StrCatBuffW(wszURLBuf, szDistUnit, 2*INTERNET_MAX_URL_LENGTH); StrCatBuffW(wszURLBuf, L";version=", 2*INTERNET_MAX_URL_LENGTH); StrCatBuffW(wszURLBuf, pwszVersion, 2*INTERNET_MAX_URL_LENGTH); StrCatBuffW(wszURLBuf, L";codebase=", 2*INTERNET_MAX_URL_LENGTH);
// Combine the context moniker's URL with the
// codebase supplied to handle relative dependency
// URLs. If the dependency URL is absolute,
// UrlCombineW will just return the absolute
// dependency URL.
if (SUCCEEDED(GetContextMoniker()->GetDisplayName(NULL, NULL, &pwszURL))) { dwSize = INTERNET_MAX_URL_LENGTH; if (FAILED(UrlCombineW(pwszURL, pcbhCur->wszCodeBase, szResult, &dwSize, 0))) { hr = E_UNEXPECTED; goto Exit; } iLen = lstrlenW(szResult) + lstrlenW(wszURLBuf) + 1; pwszStr = new WCHAR[iLen]; if (pwszStr == NULL) { SAFEDELETE(pwszURL); hr = E_OUTOFMEMORY; goto Exit; } StrCpyW(pwszStr, wszURLBuf); StrCatW(pwszStr, szResult); SAFEDELETE(pcbhCur->wszCodeBase); pcbhCur->wszCodeBase = pwszStr; SAFEDELETE(pwszURL); } else { hr = E_UNEXPECTED; goto Exit; } } }
// Because of way this is processed it should create URLMoniker, which in
// turn creates CCodeDownload and properly installs before we do our
// setup here. Thus we don't need to do anything else explicit here.
pdlCur = new CDownload(szCDLURL, extn, &hr); if (!pdlCur) { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) { SAFEDELETE(pdlCur); goto Exit; }
AddDownloadToList(pdlCur);
hr = pdlCur->SetUsingCdlProtocol(szDistUnit);
if (FAILED(hr)) goto Exit;
{ BOOL bSetOnStack = SetOnStack(); bDestroyPCBHList = FALSE; hr = pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE), pcbhList); if (bSetOnStack) ResetOnStack(); }
// this is an indication "cdl://" is not installed.
CHECK_ERROR_EXIT((hr != E_NOINTERFACE),ID_CDLDBG_CDL_HANDLER_MISSING);
if (FAILED(hr)) goto Exit;
goto nextDepend;
}
SAFEDELETE(pcbh); }
if (SUCCEEDED(hr)) hr = HRESULT_FROM_WIN32(ERROR_APP_WRONG_OS);
nextDepend: SAFERELEASE(pLang); SAFERELEASE(pSoftDist2); SAFEDELETE(szDistUnit); SAFEDELETE(szLanguages);
if (FAILED(hr)) break; }
Exit: SAFERELEASE(pLang); SAFERELEASE(pSoftDist2); SAFERELEASE(pConfig); SAFEDELETE(szDistUnit); SAFEDELETE(szLanguages); SAFEDELETE(pwszVersion);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ExtractInnerCAB
// We have a nested CAB, extract its contents into temporary directory (do not
// process any OSD, INF files for this). If duplicate files exist we ignore
// since this is a design error.
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ExtractInnerCAB(CDownload *pdl, LPSTR szCABFile) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ExtractInnerCAB", "this=%#x, %#x, %.80q", this, pdl, szCABFile )); HRESULT hr = S_OK; SESSION *psess; CHAR szTempCABFile[MAX_PATH];
psess = new SESSION; if (!psess) { hr = E_OUTOFMEMORY; goto Exit; }
psess->pFileList = NULL; psess->cFiles = 0; psess->cbCabSize = 0; psess->flags = SESSION_FLAG_ENUMERATE | SESSION_FLAG_EXTRACT_ALL; lstrcpy(psess->achLocation,pdl->GetSession()->achLocation); psess->pFilesToExtract = NULL;
if (!catDirAndFile(szTempCABFile, MAX_PATH, psess->achLocation, szCABFile)) { hr = E_UNEXPECTED; goto Exit; }
hr = ExtractFromCabinet(psess, szTempCABFile);
if (psess->pFileList && SUCCEEDED(hr)) {
// add extracted files to download list for cleanup purposes
PFNAME pfl = psess->pFileList; SESSION *psessdl = pdl->GetSession(); while (pfl->pNextName) { pfl=pfl->pNextName; } pfl->pNextName = psessdl->pFileList; psessdl->pFileList = psess->pFileList;
}
Exit: SAFEDELETE(psess);
DEBUG_LEAVE(hr); return hr; }
BOOL CCodeDownload::IsFileProtected(LPCSTR pFileName) { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "CCodeDownload::IsFileProtected", "this=%#x, %.100q", this, pFileName ));
LPWSTR wzFileName = NULL; BOOL bIsProtectedFile = FALSE; pfnSfcIsFileProtected pfn = NULL;
if (SUCCEEDED(::Ansi2Unicode(pFileName, &wzFileName))) { if (!m_hModSFC) { m_hModSFC = LoadLibrary("SFC.DLL"); }
if (m_hModSFC) { pfn = (pfnSfcIsFileProtected)GetProcAddress(m_hModSFC, "SfcIsFileProtected"); if (pfn) { bIsProtectedFile = (*pfn)(NULL,wzFileName); } }
SAFEDELETE(wzFileName); }
DEBUG_LEAVE(bIsProtectedFile); return bIsProtectedFile; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ProcessNativeCode
// Processes <nativecode> tag and spins off any dependency code downloads
// as appropriate.
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ProcessNativeCode(CDownload *pdl, IXMLElement *pNativeCode) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ProcessNativeCode", "this=%#x, %#x, %#x", this, pdl, pNativeCode )); HRESULT hr = S_OK; int iCount;
LPWSTR szName = NULL; union { char szCLSID[MAX_PATH]; char szVersion[MAX_PATH]; }; char szTempFile[INTERNET_MAX_URL_LENGTH]; LPSTR szCodeBase = NULL, szNativeName = NULL, pBaseFileName = NULL, szTempDir = NULL; CCodeBaseHold *pcbh = NULL; int nLast2, nLast3; DWORD dwVersionMS = 0, dwVersionLS = 0; CLSID clsid = CLSID_NULL; IXMLElement *pCode = NULL, *pElemTmp = NULL, *pConfig = NULL; BOOL fSetupInf = FALSE; CLocalComponentInfo lci; CSetup *pSetup = NULL; ICodeInstall* pCodeInstall = GetICodeInstall(); BOOL bSystem = FALSE; CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL; BOOL bDestroyPCBHList = FALSE;
if (!pdl->HasAllActiveXPermissions()) {
if (IsSilentMode()) { SetBitsInCache(); } else {
hr = TRUST_E_FAIL; goto Exit; } }
szTempDir = pdl->GetSession()->achLocation;
nLast2 = -1; while (GetNextChildTag(pNativeCode, DU_TAG_CODE, &pCode, nLast2) == S_OK) {
SAFEDELETE(szName); SAFEDELETE(szNativeName);
if (FAILED(hr)) break;
// get CLSID attribute
hr = GetAttributeA(pCode, DU_ATTRIB_CLSID, szCLSID, MAX_PATH); if (SUCCEEDED(hr)) { // convert CLSID attribute
hr = ConvertFriendlyANSItoCLSID(szCLSID, &clsid); CHECK_ERROR_EXIT(SUCCEEDED(hr),ID_CDLDBG_NATIVECODE_SYNTAX); } else { clsid = CLSID_NULL; szCLSID[0] = '\0'; }
// get NAME attribute
hr = DupAttribute(pCode, DU_ATTRIB_NAME, &szName); CHECK_ERROR_EXIT(SUCCEEDED(hr),ID_CDLDBG_NATIVECODE_SYNTAX);
// use "NAME" attribute as file name to OCX/INF/DLL
if (FAILED(hr = Unicode2Ansi(szName, &szNativeName))) break;
// get VERSION attribute
if (SUCCEEDED(GetAttributeA(pCode, DU_ATTRIB_VERSION, szVersion, MAX_PATH))) {
// convert VERSION string
hr = GetVersionFromString(szVersion, &dwVersionMS, &dwVersionLS); CHECK_ERROR_EXIT(SUCCEEDED(hr),ID_CDLDBG_NATIVECODE_SYNTAX);
} else {
dwVersionMS = 0; dwVersionLS = 0;
}
if (GetFirstChildTag(pCode, DU_TAG_SYSTEM, &pElemTmp) == S_OK) { bSystem = TRUE; SAFERELEASE(pElemTmp); } else { bSystem = FALSE; }
// Check if object CLSID unit is currently installed
// NOTE: This assumes MSICD
HRESULT hrExact; HRESULT hrAny;
hrAny = IsControlLocallyInstalled(szNativeName, (LPCLSID)&clsid, NULL, dwVersionMS, dwVersionLS, &lci, GetDestDirHint(), FALSE);
if (m_bExactVersion) { hrExact = IsControlLocallyInstalled(szNativeName, (LPCLSID)&clsid, NULL, dwVersionMS, dwVersionLS, &lci, GetDestDirHint(), TRUE); }
if (m_bExactVersion && hrExact == S_FALSE && hrAny == S_OK) {
// Newer version exists on the machine.
// Check if we are going to install outside of DPF
// and disallow if we are going to downgrade.
BOOL bIsDPFComponent = FALSE; CHAR szOCXCacheDirSFN[MAX_PATH]; CHAR szFNameSFN[MAX_PATH];
if (lci.szExistingFileName[0]) {
GetShortPathName(lci.szExistingFileName, szFNameSFN, MAX_PATH); GetShortPathName(g_szOCXCacheDir, szOCXCacheDirSFN, MAX_PATH);
if (StrStrI(szFNameSFN, szOCXCacheDirSFN)) { bIsDPFComponent = TRUE; } }
if (!bIsDPFComponent) { // Trying to downgrade a system component. Just pretend
// system component is OK.
if (!IsEqualGUID(clsid, GetClsid())) { if (lci.szExistingFileName[0]) { hr = QueueModuleUsage(lci.szExistingFileName, MU_CLIENT); }
} goto nextNativeCode; }
} // Else, we are a legacy case (non-sxs) or
// hrExact == S_OK (therefore, hrAny == S_OK) or
// hrAny == hrExact == S_FALSE (and we fall through).
else { if (hrAny != S_FALSE) { if (!IsEqualGUID(clsid, GetClsid())) {
if (lci.szExistingFileName[0]) { hr = QueueModuleUsage(lci.szExistingFileName, MU_CLIENT); }
} goto nextNativeCode; }
}
// Disallow replacement of SFC files for Win2K
if (g_bNT5OrGreater) { if (!FileProtectionCheckSucceeded(lci.szExistingFileName)) { hr = INET_E_CANNOT_REPLACE_SFP_FILE; goto Exit; } }
// process CONFIG tag.
nLast3 = -1; while (GetNextChildTag(pCode, DU_TAG_CONFIG, &pConfig, nLast3) == S_OK) { if (bDestroyPCBHList) { DestroyPCBHList(pcbhList); SAFEDELETE(pcbhList); } pcbhList = new CList<CCodeBaseHold *, CCodeBaseHold *>; if (pcbhList == NULL) { hr = E_OUTOFMEMORY; goto Exit; } bDestroyPCBHList = TRUE; pcbhList->RemoveAll();
hr = ProcessImplementation(pConfig, pcbhList, m_lcid #ifdef WX86
, GetMultiArch() #endif
);
SAFERELEASE(pConfig);
if (FAILED(hr)) break;
if (hr == S_OK) {
pBaseFileName = NULL;
iCount = pcbhList->GetCount(); if (iCount) { pcbh = pcbhList->GetHead(); pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED; } else { pcbh = NULL; }
if (pcbh) {
if (FAILED(hr = Unicode2Ansi(pcbh->wszCodeBase, &szCodeBase))) break;
if (!pcbh->bHREF) {
// CODEBASE FILENAME= has precedence over NAME="" for file name.
// If FILENAME is CAB, then extract contents
// with szNativeName=NAME, szCodeBase=thiscab
// otherwise
// szNativeName=FILENAME, szCodeBase=thiscab, ignore NAME
FILEXTN extn = ::GetExtnAndBaseFileName(szCodeBase, &pBaseFileName); if (extn == FILEXTN_CAB) {
ExtractInnerCAB(pdl, szCodeBase);
} else {
SAFEDELETE(szNativeName); if (FAILED(hr = Unicode2Ansi(pcbh->wszCodeBase, &szNativeName))) break;
} SAFEDELETE(szCodeBase);
szCodeBase = new char[lstrlenA(szTHISCAB)+1]; if (!szCodeBase) { hr = E_OUTOFMEMORY; break; } lstrcpyA(szCodeBase, szTHISCAB); }
} else {
// No FILENAME field, szNativeName=NAME & szCodeBase=thiscab
szCodeBase = new char[lstrlenA(szTHISCAB)+1]; if (!szCodeBase) { hr = E_OUTOFMEMORY; break; } lstrcpyA(szCodeBase,szTHISCAB);
}
FILEXTN extn = ::GetExtnAndBaseFileName(szNativeName, &pBaseFileName);
//BUGBUG: Should we limit ourselves to at most one INF file per OSD?
if ((!pcbh || !pcbh->bHREF) && extn == FILEXTN_INF) {
// File is in temporary directory somewhere, We extract Temp
if (!catDirAndFile(szTempFile, MAX_PATH, (char *)szTempDir, szNativeName)) { hr = E_FAIL; goto Exit; }
hr = SetupInf(szTempFile, pBaseFileName, pdl);
if (SUCCEEDED(hr)) { fSetupInf = TRUE; }
} else {
if (lci.IsPresent() && pCodeInstall) {
// a prev version exists. get permission to overwrite
// if ICodeInstall available
WCHAR szBuf[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, (lci.szExistingFileName[0])?lci.szExistingFileName:szNativeName, -1, szBuf, MAX_PATH);
hr = pCodeInstall->OnCodeInstallProblem( CIP_OLDER_VERSION_EXISTS, NULL, szBuf, 0);
if (FAILED(hr)) {
if (hr == E_ABORT) hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
break; } }
//BUGBUG: Need a way to do this stuff in OSD
DESTINATION_DIR dest = LDID_OCXCACHE;
//DWORD dwRegisterServer = CST_FLAG_REGISTERSERVER;
// we can't force a register server here as this will
// mean as if we have an override in the INF/OSD
// whereas there is no support for this in OSD.
// turning this off here means:
// for EXE we will run if pointed to in the OSD or
// directly by codebase, but we will run with /regsvr
// and leave installed only if marked oleself register
// for an OCX unless overrideen we will alwys register
// if the DLL is registerable (has dllregisterserver entrypt
DWORD dwRegisterServer = 0; DWORD dwCopyFlags = 0;
if (m_dwSystemComponent || bSystem) { m_dwSystemComponent = TRUE; dest = LDID_SYS; }
hr = StartDownload(szNativeName, pdl, szCodeBase, dest, lci.lpDestDir, dwRegisterServer, dwCopyFlags, pcbhList); bDestroyPCBHList = FALSE; }
SAFEDELETE(szCodeBase);
goto nextNativeCode; }
if (FAILED(hr)) break;
}
// here if anything in above loop failed or we never found an
// implmentation matching our config
if (SUCCEEDED(hr)) hr = HRESULT_FROM_WIN32(ERROR_APP_WRONG_OS);
nextNativeCode: SAFERELEASE(pCode); SAFERELEASE(pConfig);
}
Exit: SAFERELEASE(pCode); SAFERELEASE(pConfig); SAFEDELETE(szName); SAFEDELETE(szNativeName); SAFEDELETE(szCodeBase);
if (SUCCEEDED(hr) && fSetupInf) hr = S_FALSE;
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ParseOSD
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ParseOSD(const char *szOSD, char *szOSDBaseName, CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ParseOSD", "this=%#x, %.80q, %.80q, %#x", this, szOSD, szOSDBaseName, pdl ));
HRESULT hr = S_OK; IXMLElement *pSoftDist = NULL, *pDepend = NULL, *pJava = NULL, *pNativeCode = NULL, *pTitle = NULL, *pExpire = NULL, *pSystemTag = NULL, *pSXS = NULL; LPSTR pBaseFileName = NULL, lpTmpDir = NULL; DWORD len = 0; int nLast, nLast2, nLast3; BOOL bSetupInf = FALSE;
// create a CSetup OBJ and add it to the CDownload obj
CSetup *pSetup = new CSetup(szOSD, szOSDBaseName, FILEXTN_OSD, NULL, &hr); if(!pSetup) { hr = E_OUTOFMEMORY; } if (FAILED(hr)) goto Exit;
pdl->AddSetupToList(pSetup);
hr = SetManifest(FILEXTN_OSD, szOSD); if (FAILED(hr)) goto Exit;
hr = GetSoftDistFromOSD(szOSD, &pSoftDist); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_FAILED_OSD_OM);
hr = DupAttribute(pSoftDist, DU_ATTRIB_NAME, &m_szDistUnit); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DU_REQUIRED_ATTRIB_MISSING);
hr = DupAttributeA(pSoftDist, DU_ATTRIB_VERSION, &m_szVersionInManifest); CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DU_REQUIRED_ATTRIB_MISSING);
// process TITLE display name
if (GetFirstChildTag(pSoftDist, DU_TAG_TITLE, &pTitle) == S_OK) {
BSTR bstrTitle = NULL; hr = pTitle->get_text(&bstrTitle); if (FAILED(hr)) { goto Exit; }
if (FAILED(Unicode2Ansi(bstrTitle, &m_szDisplayName))) { hr = E_OUTOFMEMORY; SAFESYSFREESTRING(bstrTitle); goto Exit; } SAFESYSFREESTRING(bstrTitle); }
// See if there is a SYSTEM tag
if (GetFirstChildTag(pSoftDist, DU_TAG_SYSTEM, &pSystemTag) == S_OK) { SAFERELEASE(pSystemTag); m_dwSystemComponent = TRUE; }
// process expire date
if (GetFirstChildTag(pSoftDist, DU_TAG_EXPIRE, &pExpire) == S_OK) {
BSTR bstrExpire = NULL; hr = pExpire->get_text(&bstrExpire); if (SUCCEEDED(hr)) { OLECHAR *pch = bstrExpire;
m_dwExpire = 0;
for ( ; *pch && m_dwExpire <= MAX_EXPIRE_DAYS; pch++ ) { if ( (*pch >= TEXT('0') && *pch <= TEXT('9')) ) m_dwExpire = m_dwExpire * 10 + *pch - TEXT('0'); else break; }
if (m_dwExpire > MAX_EXPIRE_DAYS) m_dwExpire = MAX_EXPIRE_DAYS; } // else treat failure with a NOP
SAFESYSFREESTRING(bstrExpire); }
if (!m_bExactVersion) { // Exact Version necessarily means uninstall old. Don't bother
// looking it up.
if (GetFirstChildTag(pSoftDist, DU_TAG_UNINSTALL_OLD, &pSXS) == S_OK) { m_bUninstallOld = TRUE; } }
//REVIEW: optionally look for ABSTRACT
//REVIEW: CONFIG tags at highest level are ignored.
// process all DEPENDENCY tags (installing Distribution Units)
nLast = -1; while (GetNextChildTag(pSoftDist, DU_TAG_DEPENDENCY, &pDepend, nLast) == S_OK) {
hr = ProcessDependency(pdl, pDepend); SAFERELEASE(pDepend); if (FAILED(hr)) goto Exit;
}
// process only one NATIVECODE tags (Installing ActiveX/CLSID specified controls)
nLast = -1; if (GetNextChildTag(pSoftDist, DU_TAG_NATIVECODE, &pNativeCode, nLast) == S_OK) {
hr = ProcessNativeCode(pdl, pNativeCode); SAFERELEASE(pNativeCode); if (FAILED(hr)) goto Exit;
if (hr == S_FALSE) bSetupInf = TRUE; }
// process JAVA tags (Installing Java packages)
nLast = -1; while (GetNextChildTag(pSoftDist, DU_TAG_JAVA, &pJava, nLast) == S_OK) {
//BUGBUG: Parameters szOSD, szOSDBaseName are currently unused.
hr = ProcessJavaManifest(pJava, szOSD, szOSDBaseName, pdl); SAFERELEASE(pJava); if (FAILED(hr)) goto Exit; }
Exit:
if (!bSetupInf) {
if (SUCCEEDED(hr)) {
pdl->SetDLState(DLSTATE_READY_TO_SETUP);
} else {
// we encountered an error, go to done state.
pdl->SetDLState(DLSTATE_DONE); } }
SAFERELEASE(pJava); SAFERELEASE(pTitle); SAFERELEASE(pExpire); SAFERELEASE(pNativeCode); SAFERELEASE(pDepend); SAFERELEASE(pSoftDist); SAFERELEASE(pSXS);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::AddDistUnitList
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::AddDistUnitList(LPWSTR szDistUnit) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::AddDistUnitList", "this=%#x, %.80wq", this, szDistUnit )); HRESULT hr = E_FAIL; LPWSTR wszDistUnit = 0;
hr = CDLDupWStr(&wszDistUnit, szDistUnit); if (SUCCEEDED(hr) && wszDistUnit) {
m_pDependencies.AddHead(wszDistUnit);
}
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetupInf
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::SetupInf(const char *szInf, char *szInfBaseName, CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetupInf", "this=%#x, %.80q, %.80q, %#x", this, szInf, szInfBaseName, pdl )); HRESULT hr = S_OK; CSetup* pSetup = NULL; int nBuffSize = MAX_INF_SECTIONS_SIZE; char lpSections[MAX_INF_SECTIONS_SIZE]; const static char *szAddCodeSection = "Add.Code"; const static char *szHooksSection = "Setup Hooks"; const static char *szUninstallOld = "UninstallOld"; static char *szDefault = ""; DWORD len;
SetHaveInf();
if (!pdl->HasAllActiveXPermissions()) {
if (IsSilentMode()) { SetBitsInCache(); } else {
hr = TRUST_E_FAIL; goto Exit; } }
pdl->SetDLState(DLSTATE_INF_PROCESSING);
Assert(m_szInf == NULL);
m_szInf = new char [lstrlen(szInf)+1];
if (!m_szInf) { hr = E_OUTOFMEMORY; goto Exit; }
lstrcpy(m_szInf, szInf);
// Add a setup obj for this INF file
// We keep the INF file in the ocxcache dir
// to be able to nuke the OCX
// create a CSetup OBJ and add it to the CDownload obj
pSetup = new CSetup(szInf, szInfBaseName, FILEXTN_INF, NULL, &hr); if(!pSetup) { hr = E_OUTOFMEMORY; } if (FAILED(hr)) { SAFEDELETE(pSetup); goto Exit; }
pdl->AddSetupToList(pSetup);
len = GetPrivateProfileString(szAddCodeSection, NULL, szDefault, lpSections, nBuffSize, m_szInf);
if (!len) {
// no Internet Code Downloader known sections in INF may be a
// regular Win32 INF file format, make a hook if the
// INF came in a CAB, which will be to extract all files in the
// current CAB and then RunSetupCommand
// there's no [add.code]
// look to see if there's a [setup hooks]
// if not we then create a hook to process the default install section
// if there's a [setup hooks] we won't make a default hokk for you
// as you can make a hook yourself to process default install
// the idea is you either don't know about us (we need to help you)
// or you are code downloader aware (help yourself with our capabilty)
// this allows the user to have an INF with any or all of the following
// 1) [add.code]
// 2) [Setup hooks]
// 3) win32 inf : defaultinstall
len = GetPrivateProfileString(szHooksSection, NULL, szDefault, lpSections, nBuffSize, m_szInf); if (!len) {
// make a new hook and add it to this CAB
// post a message to trigger setup phase as nothing else is needed
hr = pdl->AddHook(NULL, szInfBaseName, NULL/* szInfSection */, RSC_FLAG_INF);
goto Exit; }
} else {
m_pCurCode = m_pAddCodeSection = new char [len + 1];
if (m_pAddCodeSection) { memcpy(m_pAddCodeSection, lpSections, len); m_pAddCodeSection[len] = '\0'; } }
if (!m_bExactVersion) { m_bUninstallOld=GetPrivateProfileInt(szAddCodeSection, szUninstallOld, 0, m_szInf); }
Exit:
if (SUCCEEDED(hr)) {
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_PROCESS_INF, this, (DWORD_PTR)pdl);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
}
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::IsSectionInINF
// Checks if a section is in the INF
// returns:
// S_OK: lpCurCode has the satellite binary name
// S_FALSE: ignore this code and use default resources in main dll
// E_XXX: any other error
BOOL CCodeDownload::IsSectionInINF( LPCSTR lpCurCode) { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "CCodeDownload::IsSectionInINF", "this=%#x, %.80q", this, lpCurCode )); const char *szDefault = ""; DWORD len; #define FAKE_BUF_SIZE 3
char szBuf[FAKE_BUF_SIZE];
len = GetPrivateProfileString(lpCurCode, NULL, szDefault, szBuf, FAKE_BUF_SIZE, m_szInf);
if (len == (FAKE_BUF_SIZE - 2)) { // returns Out Of Buffer Space?
// yes, section found
DEBUG_LEAVE(TRUE); return TRUE; } else {
DEBUG_LEAVE(FALSE); return FALSE; } }
void CCodeDownload::CodeDownloadDebugOut(int iOption, BOOL fOperationFailed, UINT iResId, ...) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::CodeDownloadDebugOut", "this=%#x, %d, %B, %#x, ...", this, iOption, fOperationFailed, iResId ));
// Temp solution to prevent buffer overruns in debug logging code.
// Long term, the printfs should be constrained. It will be a must
// if URLs become fully dynamic.
static char szDebugString[MAX_DEBUG_STRING_LENGTH*5]; static char szFormatString[MAX_DEBUG_FORMAT_STRING_LENGTH]; va_list args;
LoadString(g_hInst, iResId, szFormatString, MAX_DEBUG_FORMAT_STRING_LENGTH); va_start(args, iResId); vsprintf(szDebugString, szFormatString, args); va_end(args);
m_debuglog->DebugOutPreFormatted(iOption, fOperationFailed, szDebugString);
DEBUG_LEAVE(0); }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GetSatelliteName
// gets the lang specific satellite DLL name
// in the INF
// returns:
// S_OK: lpCurCode has the satellite binary name
// S_FALSE: ignore this code and use default resources in main dll
// E_XXX: any other error
HRESULT CCodeDownload::GetSatelliteName( LPSTR lpCurCode, int iLen) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::GetSatelliteName", "this=%#x, %.80q", this, lpCurCode )); HRESULT hr = S_OK; const char *szDefault = ""; DWORD len; #define FAKE_BUF_SIZE 3
char szBuf[FAKE_BUF_SIZE]; char szExtension[5]; int iReturn = 0;
Assert(lpCurCode);
szExtension[0] = *lpCurCode = '\0';
// get a quick out for code that does not have any vars in them
if ((StrChr(m_pCurCode, '%') == NULL) && IsSectionInINF(m_pCurCode)) {
// not a satellite
StrNCpy(lpCurCode, m_pCurCode, iLen); m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ITEM_PROCESSED, lpCurCode);
DEBUG_LEAVE(hr); return hr; }
// allow IE3 workarounds for %LANG%
// by looking for sections that have a %LANG% literally in them
// after looking for sections with the variable expanded
// BEGIN NOTE: add vars and values in matching order
// add a var by adding a new define VAR_NEW_VAR = NUM_VARS++
const char *szVars[] = {
#define VAR_LANG 0 // 3 letter lang extension
"%LANG%",
#define NUM_VARS 1
"" };
const char *szValues[NUM_VARS + 1]; szValues[VAR_LANG] = szExtension; szValues[NUM_VARS] = NULL; // END NOTE: add vars and values in matching order
UINT uLocaleTest=0; uLocaleTest = (LOWORD(m_lcid) & (~(~0 << 4) << 0)) >> 0;
// obtain the 3 character Lang abbreviation for the
// LCID we're running on.
// if it doesn't exist we'll get just the 2 charact Lang abbreviation
// and try again, failing that we default to English
iReturn = m_langinfo.GetLocaleStrings(m_lcid, szExtension, sizeof(szExtension));
if (!iReturn) { hr = HRESULT_FROM_WIN32(GetLastError()); m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_PRIMARY_LANGUAGE, hr, lpCurCode); goto Exit; }
// expand the variables names if any
hr = CSetupHook::ExpandCommandLine(m_pCurCode, lpCurCode, MAX_PATH, szVars, szValues);
if (FAILED(hr)) { // failed
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_NO_SECTION, m_pCurCode, szExtension); goto Exit; }
// vars are expanded correctly (S_OK) or
// no vars got expanded.(S_FALSE) maybe we could try the section as is
if ( IsSectionInINF(lpCurCode)) { // satellite found!
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_SATELLITE_FOUND, lpCurCode); hr = S_OK; goto Exit; }
// we couldn't find it with the entire LCID, try it with just the primary
// langid
LCID lcid; lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(m_lcid)), SUBLANG_DEFAULT), SORT_DEFAULT);
iReturn = m_langinfo.GetLocaleStrings(lcid, szExtension, sizeof(szExtension));
if (!iReturn) { hr = HRESULT_FROM_WIN32(GetLastError()); m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_PROCESSINF_FAILED, hr, lpCurCode); goto Exit; }
// expand the variables names with new value
hr = CSetupHook::ExpandCommandLine(m_pCurCode, lpCurCode, MAX_PATH, szVars, szValues);
if (FAILED(hr) || (hr == S_FALSE)) { // failed or no vars
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_NO_SECTION, m_pCurCode, szExtension); if (hr == S_FALSE) hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); goto Exit; }
// try the INF section again
if ( !IsSectionInINF(lpCurCode)) { m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_NO_SECTION, m_pCurCode, szExtension);
// no section for this language. This is OK skip the file
// browser will end up using default lang/resources
hr = S_FALSE;
} else {
// satellite found!
m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_SATELLITE_FOUND, lpCurCode);
}
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GetInfCodeLocation
// gets the platform specific or independent location URL of the code specified
// in the INF
// returns:
// S_OK: szURL has the location
// S_FALSE: ignore this code for the current platform
// E_XXX: any other error
HRESULT CCodeDownload::GetInfCodeLocation( LPCSTR lpCurCode, LPSTR szURL) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::GetInfCodeLocation", "this=%#x, %.80q, %.80q", this, lpCurCode, szURL )); const static char *szLoc = "File"; static char *szDefault = ""; HRESULT hr = S_OK;
Assert(m_szInf);
szURL[0] = '\0'; // init to empty string
// look for platform specific URL first
// this is needed to skip some files for some
// platforms
#ifdef WX86
char *szPreferredArch; char *szAlternateArch; HRESULT hrArch;
GetMultiArch()->SelectArchitecturePreferences( g_szPlatform, "file-win32-x86", &szPreferredArch, &szAlternateArch);
GetPrivateProfileString(lpCurCode, szPreferredArch, szDefault, szURL, INTERNET_MAX_URL_LENGTH, m_szInf); if (szURL[0] != '\0' && lstrcmpi(szURL, szIGNORE) != 0) { // There was a URL and it was not 'ignore' to indicate it is not
// applicable to this platform.
CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_WX86_REQUIRE_PRIMARY_ARCH, szURL); hrArch = GetMultiArch()->RequirePrimaryArch(); Assert(SUCCEEDED(hrArch)); } else if (szAlternateArch) { GetPrivateProfileString(lpCurCode, szAlternateArch, szDefault, szURL, INTERNET_MAX_URL_LENGTH, m_szInf); if (szURL[0]) { if (lstrcmpi(szURL, szIGNORE) != 0) { // The alternate architecture matched and the URL was not
// 'ignore' to indicate it is not applicable to this platform.
CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_WX86_REQUIRE_ALTERNATE_ARCH, szURL); hrArch = GetMultiArch()->RequireAlternateArch(); Assert(SUCCEEDED(hrArch)); } } } #else
GetPrivateProfileString(lpCurCode, g_szPlatform, szDefault, szURL, INTERNET_MAX_URL_LENGTH, m_szInf); #endif
if (szURL[0] == '\0') { GetPrivateProfileString(lpCurCode, szLoc, szDefault, szURL, INTERNET_MAX_URL_LENGTH, m_szInf); } else { // got a platform specific URL
// look for 'ignore' keyword to mean that this is
// not applicable for this platform
if (lstrcmpi(szURL, szIGNORE) == 0) { hr = S_FALSE; } }
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GetInfSectionInfo
HRESULT CCodeDownload::GetInfSectionInfo( LPSTR lpCurCode, int iLen, LPSTR szURL, LPCLSID *plpClsid, LPDWORD pdwFileVersionMS, LPDWORD pdwFileVersionLS, DESTINATION_DIR *pdest, LPDWORD pdwRegisterServer, LPDWORD pdwCopyFlags, BOOL *pbDestDir ) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::GetInfSectionInfo", "this=%#x, %.80q, %.80q, %#x, %#x, %#x, %#x, %#x, %#x, %#x", this, lpCurCode, szURL, plpClsid, pdwFileVersionMS, pdwFileVersionLS, pdest, pdwRegisterServer, pdwCopyFlags, pbDestDir )); const static char *szFileVersion = "FileVersion"; const static char *szDest = "DestDir"; const static char *szRegisterServerOverride = "RegisterServer"; const static char *szCopyFlags = "CopyFlags"; const static char *szForceDestDir = "ForceDestDir"; static char *szDefault = ""; DWORD len; HRESULT hr = S_OK; char szBuf[MAX_PATH];
hr = GetSatelliteName(lpCurCode, iLen);
if (hr != S_OK) goto Exit;
hr = GetInfCodeLocation( lpCurCode, szURL);
if (hr != S_OK) goto Exit;
// get RegisterServerOverride if any
if (GetPrivateProfileString(lpCurCode, szRegisterServerOverride, szDefault, szBuf, MAX_PATH, m_szInf)) {
*pdwRegisterServer = CST_FLAG_REGISTERSERVER_OVERRIDE;
if ((szBuf[0] == 'y') || (szBuf[0] == 'Y') || (szBuf[0] == '1') || (lstrcmpi(szBuf, "true") == 0)) { *pdwRegisterServer |= CST_FLAG_REGISTERSERVER; } }
// get CopyFlags if any
*pdwCopyFlags=GetPrivateProfileInt(lpCurCode, szCopyFlags, 0, m_szInf);
// get version string
if (!(len =GetPrivateProfileString(lpCurCode, szFileVersion, szDefault, szBuf, MAX_PATH, m_szInf))) { // if no version specified, local copy is always OK!
szBuf[0] = '\0'; }
if ( FAILED(GetVersionFromString(szBuf, pdwFileVersionMS, pdwFileVersionLS))){ hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
// get Destination dir if suggested
*pdest=(DESTINATION_DIR)GetPrivateProfileInt(lpCurCode, szDest, 0, m_szInf);
// get ForceDestDir flag
*pbDestDir=GetPrivateProfileInt(lpCurCode, szForceDestDir, 0, m_szInf);
// get clsid string
if (!(len = GetPrivateProfileString(lpCurCode, szCLSID, szDefault, szBuf, MAX_PATH, m_szInf))){ // if no clsid specified, not a control, just a plain dll?
*plpClsid = NULL; goto Exit; }
// Get CLSID from string
hr = ConvertANSItoCLSID(szBuf, *plpClsid);
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::StartDownload
HRESULT CCodeDownload::StartDownload( LPSTR szCurCode, CDownload *pdl, LPSTR szURL, DESTINATION_DIR dest, LPSTR szDestDir, DWORD dwRegisterServer, DWORD dwCopyFlags, CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::StartDownload", "this=%#x, %.80q, %#x, %.80q, %#x, %.80q, %#x, %#x, %#x", this, szCurCode, pdl, szURL, dest, szDestDir, dwRegisterServer, dwCopyFlags, pcbhList )); FILEXTN extn; char *pBaseFileName; HRESULT hr = NO_ERROR; WCHAR szBuf[INTERNET_MAX_URL_LENGTH]; CDownload *pdlCur = NULL; CSetup* pSetup = NULL; BOOL bDestroyList = TRUE;
extn = ::GetExtnAndBaseFileName(szURL, &pBaseFileName);
// if this INF came in a CAB then anything pointing to
// file=thiscab, means this szCurCode can be found in the CAB
// that this INF came in. This makes authoring the INFs easy
// because you don't have to know the name of the site that's going
// to distribute the OCX.
// Also, allows for web publisher to change the name of the
// CAB
if ((pdl->GetExtn() == FILEXTN_CAB) && (lstrcmpi(szTHISCAB, szURL) == 0)) { pdl->AddSetupToExistingCAB(szCurCode, szDestDir, dest, dwRegisterServer, dwCopyFlags); goto Exit; }
switch (extn) {
case FILEXTN_INF: case FILEXTN_OSD: hr = E_INVALIDARG; // don't supp multiple INFs (recursive downloads)
goto Exit;
case FILEXTN_CAB:
// check if URL is a cab that the inf came with (pdl->psess)
// else check if CAB has been submitted for download in some other
// CDownload that we just started when processing lines in INF
// above this one
// either case if you find a CAB then piggy back this code setup to
// that CDownload of the same CAB file
MultiByteToWideChar(CP_ACP, 0, szURL, -1, szBuf, INTERNET_MAX_URL_LENGTH);
hr = FindCABInDownloadList(szBuf, pdl, &pdlCur);
if (FAILED(hr)) goto Exit;
if (pdlCur) {
// matching CAB found that we can pile on this setup
pdlCur->AddSetupToExistingCAB(szCurCode, szDestDir, dest, dwRegisterServer, dwCopyFlags); goto Exit; }
// fresh CAB needs to get pulled down.
// download the CODE=URL (ie. CAB or INF file first)
pdlCur = new CDownload(szBuf, extn, &hr); if (!pdlCur) { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) { SAFEDELETE(pdlCur); goto Exit; }
AddDownloadToList(pdlCur);
{ BOOL bSetOnStack = SetOnStack(); hr = (pcbhList == NULL) ? (pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE))) : (pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE), pcbhList)); bDestroyList = FALSE;
if (bSetOnStack) ResetOnStack(); }
if (FAILED(hr)) { goto Exit; }
pdlCur->AddSetupToExistingCAB(szCurCode, szDestDir, dest, dwRegisterServer, dwCopyFlags);
break;
case FILEXTN_EXE: case FILEXTN_OCX: case FILEXTN_DLL: case FILEXTN_NONE: case FILEXTN_UNKNOWN:
MultiByteToWideChar(CP_ACP, 0, szURL, -1, szBuf, INTERNET_MAX_URL_LENGTH);
// download the CODE=URL (ie. CAB or INF file first)
pdlCur = new CDownload(szBuf, extn, &hr);
if (!pdlCur){ hr = E_OUTOFMEMORY; }
if (FAILED(hr)) goto Exit;
AddDownloadToList(pdlCur);
// create a CSetup OBJ and add it to the CDownload obj
pSetup = new CSetup(NULL, szCurCode, extn, szDestDir, &hr,dest);
if(!pSetup) { hr = E_OUTOFMEMORY; goto Exit; } else if (FAILED(hr)) { delete pSetup; goto Exit; }
pSetup->SetCopyFlags (dwCopyFlags);
if (dwRegisterServer) { pSetup->SetUserOverrideRegisterServer (dwRegisterServer&CST_FLAG_REGISTERSERVER); }
pdlCur->AddSetupToList(pSetup);
{ BOOL bSetOnStack = SetOnStack(); hr = (pcbhList == NULL) ? (pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE))) : (pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE), pcbhList)); bDestroyList = FALSE;
if (bSetOnStack) ResetOnStack(); }
if (FAILED(hr)) { goto Exit; }
}
Exit: if (bDestroyList && pcbhList) { DestroyPCBHList(pcbhList); SAFEDELETE(pcbhList); }
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ProcessInf
/*
*sample INF file: ;This is the INF file for CIRC3.OCX [Add.Code] circ3.ocx=circ3.ocx random.dll=random.dll mfc40.dll=mfc40.dll foo.ocx=foo.ocx
[circ3.ocx] file=http:\\ohserv\users\vatsanp\circ3.cab clsid={9DBAFCCF-592F-101B-85CE-00608CEC297B} FileVersion=1,0,0,143
[random.dll] file=http://ohserv/users/vatsanp/random.dll
FileVersion= ;DestDir = 10 or 11 ( LDID_WIN or LDID_SYS by INF convention) ; if none specified installed in ocxcache directory, which is the typical case. DestDir=10
[mfc40.dll] ; way of saying I need mfc40 (version 4,0,0,5) but, I can't provide it ; if absent on client fail load! file= FileVersion=4,0,0,5
[foo.ocx] ; way of saying I need foo (clsid, version 4,0,0,5) but, I can't provide it ; if absent on client fail load! file= clsid={DEADBEEF-592F-101B-85CE-00608CEC297B} FileVersion=1,0,0,143
*/
//
// We walk thru all the INF sections of code that needs to get installed.
// For each we get the CLSID, FileVersion (both optional) and URL to get from
// Depending on the extension of the URL we:
//
// CAB:
// if CAB is the one the INF came with
// extract file; create CSetup to install it (piggy back to pdl)
// else if some other CAB that has been set for download
// attach file to be extracted to pFilesToExtract
// attach a CSetup for this file
// else
// make a CDownload for this new CAB
// attach file to be extracted to pFilesToExtract
// attach a CSetup for this file
// start off download
// INF:
// Fail: don't support multiple INFs
//
// Anything else:
// Make a new CDownload for this
// start off download
// make CSetup
//
// ---------------------------------------------------------------------------
VOID CCodeDownload::ProcessInf(CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::ProcessInf", "this=%#x, %#x", this, pdl )); char szURL[INTERNET_MAX_URL_LENGTH]; static char *szDefault = ""; const static char *szHOOK = "Hook"; char szCurCode[MAX_PATH];
DWORD len = 0; FILEXTN extn; DESTINATION_DIR dest;
DWORD dwFileVersionMS = 0; DWORD dwFileVersionLS = 0; CLSID clsid; LPCLSID lpclsid = &clsid;
HRESULT hr = NO_ERROR; char * pFileName = NULL;
DWORD dwRegisterServer = 0; DWORD dwCopyFlags = 0; BOOL bForceDestDir = FALSE;
CLocalComponentInfo lci; ICodeInstall* pCodeInstall = GetICodeInstall();
if ( pdl->GetDLState() == DLSTATE_ABORT) { hr = E_ABORT; goto PI_Exit; // all done
}
if (!m_pCurCode || !(*m_pCurCode)) { goto PI_Exit; // all done
}
hr = GetInfSectionInfo( szCurCode, sizeof(szCurCode), szURL, &lpclsid, &dwFileVersionMS, &dwFileVersionLS, &dest, &dwRegisterServer, &dwCopyFlags, &bForceDestDir );
if (hr != S_OK) goto PI_Exit;
HRESULT hrExact; HRESULT hrAny;
if (m_bExactVersion) { hrExact = IsControlLocallyInstalled(szCurCode, lpclsid, NULL, dwFileVersionMS, dwFileVersionLS, &lci, GetDestDirHint(), TRUE); }
hrAny = IsControlLocallyInstalled(szCurCode, lpclsid, NULL, dwFileVersionMS, dwFileVersionLS, &lci, GetDestDirHint(), FALSE);
if (m_bExactVersion && hrExact == S_FALSE && hrAny == S_OK) {
// Newer version exists on the machine.
// Check if we are going to install outside of DPF
// and disallow if we are going to downgrade.
BOOL bIsDPFComponent = FALSE; CHAR szOCXCacheDirSFN[MAX_PATH]; CHAR szFNameSFN[MAX_PATH];
GetShortPathName(lci.szExistingFileName, szFNameSFN, MAX_PATH); GetShortPathName(g_szOCXCacheDir, szOCXCacheDirSFN, MAX_PATH);
if (StrStrI(szFNameSFN, szOCXCacheDirSFN)) { bIsDPFComponent = TRUE; }
if (!bIsDPFComponent) { // Trying to downgrade a system component. Just pretend
// system component is OK.
if (lpclsid && IsEqualGUID(clsid, GetClsid())) { goto PI_Exit; }
if (lci.szExistingFileName[0]) hr= QueueModuleUsage(lci.szExistingFileName, MU_CLIENT);
goto PI_Exit; }
} // Else, we are a legacy case (non-sxs) or
// hrExact == S_OK (therefore, hrAny == S_OK) or
// hrAny == hrExact == S_FALSE (and we fall through).
else { if (hrAny == S_OK) {
// make sure we have a ref count for the code downloader in
// shareddlls as well as mark us as a client in the usage section
// we need to do this only for a dependency, not for the main
// ocx. We can always get the main OCX back with CODEBASE. Its
// only if the dependency gets removed are we somewhat busted.
// Keep the registry small and simple.
if (lpclsid && IsEqualGUID(clsid, GetClsid())) { goto PI_Exit; }
if (lci.szExistingFileName[0]) hr= QueueModuleUsage(lci.szExistingFileName, MU_CLIENT);
goto PI_Exit; }
}
if (g_bNT5OrGreater && !(bForceDestDir && dest == LDID_OCXCACHE)) { if (!FileProtectionCheckSucceeded(lci.szExistingFileName)) { hr = INET_E_CANNOT_REPLACE_SFP_FILE; goto PI_Exit; } }
if (szURL[0] == '\0') {
// if not file/location is available then look to see if a
// hook is available to download/install this component.
if (GetPrivateProfileString(szCurCode, szHOOK, szDefault, szURL, MAX_PATH, m_szInf)) {
hr = ProcessHookSection(szURL /* hook section */, pdl); goto PI_Exit;
}
// this is a way someone can say I need this file (clsid, version)
// to run, if absent just fail the load!
hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); goto PI_Exit; }
if (lci.IsPresent() && pCodeInstall) {
// a prev ver exists. get permission to overwrite
// if ICodeInstall available
WCHAR szBuf[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, (lci.szExistingFileName[0])?lci.szExistingFileName:szCurCode, -1, szBuf, MAX_PATH);
hr = pCodeInstall->OnCodeInstallProblem( CIP_OLDER_VERSION_EXISTS, NULL, szBuf, 0);
// hr == E_ABORT: abort whole download
if (FAILED(hr)) {
if (hr == E_ABORT) hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
// else preserve error code of OnCodeInstallProblem
goto PI_Exit; }
}
hr = StartDownload( szCurCode, pdl, szURL, dest, ((bForceDestDir) ? (NULL) : (lci.lpDestDir)), dwRegisterServer, dwCopyFlags);
PI_Exit:
if (SUCCEEDED(hr)) {
if (m_pCurCode) len = lstrlen(m_pCurCode); else len = 0;
if (len) {
m_pCurCode += (len+1); // next
// skip side by side
while (!StrCmpI(m_pCurCode, INF_TAG_UNINSTALL_OLD)) { len = lstrlen(m_pCurCode); m_pCurCode += (len+1); }
if (*m_pCurCode) {
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_PROCESS_INF, this, (DWORD_PTR)pdl);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
if (SUCCEEDED(hr)) goto Exit; }
}
hr = ProcessHooks(pdl);
}
if (FAILED(hr)) { m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_PROCESSINF_FAILED, hr, (m_pCurCode && *m_pCurCode)?m_pCurCode:"Setup Hooks");
// done with this CDownload. Mark it ready for setup
pdl->SetDLState(DLSTATE_DONE);
} else {
// done with this CDownload. Mark it ready for setup
pdl->SetDLState(DLSTATE_READY_TO_SETUP); }
pdl->CompleteSignal(hr, S_OK, S_OK, NULL);
Exit:
DEBUG_LEAVE(0); return; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::QueueModuleUsage
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::QueueModuleUsage( LPCSTR szFileName, LONG muFlags) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::QueueModuleUsage", "this=%#x, %.80q, %#x", this, szFileName, muFlags )); HRESULT hr = S_OK;
CModuleUsage *pModuleUsage = new CModuleUsage(szFileName, muFlags, &hr);
if (!pModuleUsage) { hr = E_OUTOFMEMORY; goto Exit; } else if (FAILED(hr)) { delete pModuleUsage; goto Exit; }
m_ModuleUsage.AddTail(pModuleUsage);
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::UpdateModuleUsage
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::UpdateModuleUsage() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::UpdateModuleUsage", "this=%#x", this )); HRESULT hr = S_OK; char *lpClientName = NULL; LPOLESTR pwcsClsid = (LPOLESTR)GetMainDistUnit(); LISTPOSITION curpos; int i, iNumClients; CLSID myclsid;
Assert(pwcsClsid);
if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &lpClientName)))) { goto Exit; }
curpos = m_ModuleUsage.GetHeadPosition(); iNumClients = m_ModuleUsage.GetCount(); for (i=0; i < iNumClients; i++) {
(m_ModuleUsage.GetNext(curpos))->Update(lpClientName); }
Exit:
if (pwcsClsid && (pwcsClsid != GetMainDistUnit()) ) delete pwcsClsid;
if (lpClientName) delete lpClientName;
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ProcessHookSection
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ProcessHookSection(LPCSTR lpCurHook, CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ProcessHookSection", "this=%#x, %.80q, %#x", this, lpCurHook, pdl )); HRESULT hr = S_OK; char szURL[INTERNET_MAX_URL_LENGTH]; WCHAR szBuf[INTERNET_MAX_URL_LENGTH]; char szCmdLine[1024]; char szInfSection[MAX_PATH]; const static char *szINFNAME = "InfFile"; const static char *szINFSECTION = "InfSection"; const static char *szCMDLINE = "Run"; static char *szDefault = ""; DWORD flags = 0; CDownload *pdlCur = pdl; char *pBaseFileName = NULL;
// initialize szInfSection
szInfSection[0] = '\0';
// Get cmd line for hook if any
szCmdLine[0] = '\0'; GetPrivateProfileString(lpCurHook, szCMDLINE, szDefault, szCmdLine, MAX_PATH, m_szInf);
if (!szCmdLine[0]) { flags |= RSC_FLAG_INF;
// Get Inf filename if any
GetPrivateProfileString(lpCurHook, szINFNAME, szDefault, szCmdLine, MAX_PATH, m_szInf);
// Get Inf section name if any
GetPrivateProfileString(lpCurHook, szINFSECTION, szDefault, szInfSection, MAX_PATH, m_szInf); }
hr = GetInfCodeLocation(lpCurHook, szURL);
if (hr != S_OK) goto Exit;
if (szURL[0]) {
MultiByteToWideChar(CP_ACP, 0, szURL, -1, szBuf, INTERNET_MAX_URL_LENGTH);
pdlCur = NULL; hr = FindCABInDownloadList(szBuf, pdl, &pdlCur);
if (FAILED(hr)) goto Exit;
if (!pdlCur) {
// did not find CAB
// fresh CAB needs to get pulled down.
FILEXTN extn = ::GetExtnAndBaseFileName(szURL, &pBaseFileName);
if (extn != FILEXTN_CAB) { hr = E_INVALIDARG; goto Exit; }
pdlCur = new CDownload(szBuf, extn, &hr); if (!pdlCur) { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) goto Exit;
AddDownloadToList(pdlCur);
{ BOOL bSetOnStack = SetOnStack(); hr = pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE));
if (bSetOnStack) ResetOnStack(); }
if (FAILED(hr)) { goto Exit; }
} }
if ( !szCmdLine[0] ) ::GetExtnAndBaseFileName(m_szInf, &pBaseFileName);
Assert(pdlCur);
hr = pdlCur->AddHook(lpCurHook, (szCmdLine[0])?szCmdLine:pBaseFileName, (szInfSection[0])?szInfSection:NULL, flags);
Exit:
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ProcessHooks
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ProcessHooks(CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::ProcessHooks", "this=%#x, %#x", this, pdl )); HRESULT hr = S_OK; int nBuffSize = MAX_INF_SECTIONS_SIZE; char lpSections[MAX_INF_SECTIONS_SIZE]; const static char *szHooksSection = "Setup Hooks"; static char *szDefault = ""; char *lpCurHook = NULL; DWORD len;
len = GetPrivateProfileString(szHooksSection, NULL, szDefault, lpSections, nBuffSize, m_szInf);
if (len) {
for (lpCurHook =lpSections;*lpCurHook; lpCurHook+= (lstrlen(lpCurHook)+1)) {
hr = ProcessHookSection(lpCurHook, pdl);
if (FAILED(hr)) break; }
} else { hr = S_FALSE; // no hooks!
}
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::Complete
// CCodeDownload::Complete is called whenever a CDownload obj completes
// its download and initiates further downloads if necessary (eg. ProcessInf)
// It does nothing until all pending downloads are complete. Until then it
// just returns and we unwind back to BSC::OnStopBinding
//
// When all downloads completed, we then start processingall the Csetups
// We do this code download in two stages to
// keep capability to back out of entire code download for as late as we can
// until the setup stage calling CClBinding::Abort with IBinding returned by
// code downloader in client's BSC::OnStartBinding will cleanly abort and
// restore initial state.
// We don't honor Abort once in setup stage.
//
// To keep this stage as clean and failsafe as we can we check for
// disk space in the OCX cache as well as check for IN USE OCXes that we
// plan on updating. We abort on either of these two conditions.
//
// CCodeDownload::Complete than proceeds to walk thru all its download objs
// calling DoSetup which in turn causes CSetup::DoSetup() to get invoked
// for every CSetup.
//
// ---------------------------------------------------------------------------
VOID CCodeDownload::CompleteOne(CDownload *pdl, HRESULT hrOSB, HRESULT hrStatus, HRESULT hrResponseHdr, LPCWSTR szError) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::CompleteOne", "this=%#x, %#x, %#x, %#x, %#x, %.80wq", this, pdl, hrOSB, hrStatus, hrResponseHdr, szError )); CDownload *pdlCur = NULL; HRESULT hr = S_OK; HGLOBAL hPostData = NULL; WCHAR szURL[INTERNET_MAX_URL_LENGTH]; FILEXTN extn = FILEXTN_UNKNOWN; LPWSTR lpDownloadURL; CDownload *pdlNew; DWORD cbPostData = 0; BOOL fWaitForAbortCompletion = FALSE; LISTPOSITION curpos; int i = 0;
m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_COMPLETEONE_IN, hrStatus, hrOSB, hrResponseHdr, pdl->GetURL());
CUrlMkTls tls(hr); // hr passed by reference!
Assert(SUCCEEDED(hr));
if (pdl->GetDLState() != DLSTATE_READY_TO_SETUP) {
pdl->SetDLState(DLSTATE_DONE); }
if (FAILED(hr)) { goto Complete_failed; }
Assert(tls->pCDLPacketMgr);
// called each time a download object is done downloading
// and installing itself
// this is the master state analyser that will determine if the total
// code download is complete and clean up if reqd
Assert(m_pDownloads.GetCount()); // atleast one (this one)
// the three HRESULTS passed in are as follows
// hrOSB = hr of OnStopBinding, ie URLMON came back with good HR
// but we had some 'processing error with the data we got back
// in such cases just assume a bad install and fail the operation. ie.
// don't go into next component of CodeSearchPath to retify such errors
if (FAILED(hrOSB)) { hr = hrOSB; goto Complete_failed; }
// hrStatus = hr that URLMON came back with for the binding
// right now URLMON does a terrible job with errors. sometimes we get back
// an HTML response with a displayable error and URLMON say things
// succeeded, which is why we have our own hrResponseHdr which is the
// status as we fill in OnResponse.
// there are some URLMON errors that make sense to allow further search
// on CodeSearchPath and some others like E_ABORT, ie the
// client did an IBinding::Abort().
if (SUCCEEDED(hrResponseHdr) && SUCCEEDED(hrStatus)) { // here if the current download was completely successful
// if all downloads are done then call DoSetup()
if (WeAreReadyToSetup()) { // more processing left?
// no, enter setup phase
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP, this, 0);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) { goto Complete_failed; }
}
goto Exit;
}
if (hrStatus == E_ABORT) { // USER cancelled, abort entire code download
hr = hrStatus; goto Complete_failed; }
// here if the response header indicated a failure
// errors we know about now are if the response URL is absent and no
// suitable MIME tyoe was found or
// the resource we queried for is absent on this server
// try the next comp. on CodeSearchPath
Assert(m_pmkContext);
// if a top level req. failed wtih a HTTP error
// we need to go next on searchpath.
// we detect top level, either by the fact that it involed a POST
// or by the fact that the context moniker is the same
// moniker as the current download. By same moniker, we mean
// the same pointer (not pmk->IsEqual(), this will match for
// same URLs which is not necessarily top level)
// This check makes an assumption that we will not change the
// context moniker, excpet when redirecting a POST. if we do this is a
// BUGBUG: !!!
if (!(pdl->DoPost()) && (m_pmkContext != pdl->GetMoniker())) { if (FAILED(hrStatus)) hr = hrStatus; else hr = hrResponseHdr;
goto Complete_failed; }
// reset the context to zero, so we will set a fresh one to the next
// element on code searchpath
if (RelContextMk()) { SAFERELEASE(m_pmkContext); ResetNewContextMoniker(); DEBUG_PRINT(DOWNLOAD, INFO, ("this=%#x, Releasing m_pmkContext: %#x\n", this, m_pmkContext )); } else { m_pmkContext = NULL; DEBUG_PRINT(DOWNLOAD, INFO, ("this=%#x, Setting m_pmkContext to NULL: %#x\n", this, m_pmkContext )); }
// if the HTTP_ERROR was Not Modified, then this at the top level
// is not an error: ie use current version. But, we any way go past
// CODEBASE (that's the only one that can come back with Not Modified
// everything else on the searchpath is a POST) to check all
// servers on searchpath before we decide to use the current local version
hr = GetNextOnInternetSearchPath(GetClsid(), &hPostData, &cbPostData, szURL, INTERNET_MAX_URL_LENGTH, &lpDownloadURL, &extn);
if (FAILED(hr)) {
// OK all tries failed at the top level
// were we monkeying around for the very LATEST version
// when in fact there was a local version already?
if ( NeedLatestVersion() && m_plci->IsPresent()) {
Assert(WeAreReadyToSetup());
hr = S_OK; // no, fake a success
SetFakeSuccess(); CompleteAll(hr, NULL); // and instantiate the object
goto Exit;
} else { goto Complete_failed; } }
// download the CODE=URL (ie. CAB or INF file first)
pdlNew = new CDownload(lpDownloadURL, extn, &hr);
if (!pdlNew) { hr = E_OUTOFMEMORY; goto Complete_failed; } else if (FAILED(hr)) { delete pdlNew; goto Complete_failed; }
AddDownloadToList(pdlNew);
if (hPostData) {
pdlNew->SetPostData(hPostData, cbPostData); hPostData = NULL; // mark as delegated, destructor for pdl will free
}
{ BOOL bSetOnStack = SetOnStack(); hr = pdlNew->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE)); if (bSetOnStack) ResetOnStack(); }
if (SUCCEEDED(hr)) { // initiated a new download, return and wait for that to complete
goto Exit; }
// error initiating new download, abort
Complete_failed:
Assert(FAILED(hr));
if (SUCCEEDED(m_hr)) {
// first failure in a multi-piece download
// save away the real reason we failed. We pass this to
// CompleteAll
m_hr = hr; }
// problem with download
// abort all other downloads and then CompleteAll/cleanup
// to mark that atleast one real URLMON bindign was aborted
// in this case URLMON will post an OnStopBinding for that
// and we will end up aborting all other bindings and the whole
// code download. However if that's not the case then we were probably
// in some post binding processing such as verifytrust cab extraction etc
// and so we need to post a DoSetup() packet with UserCancelled flag set.
fWaitForAbortCompletion = FALSE;
curpos = m_pDownloads.GetHeadPosition(); for (i=0; !IsOnStack() && ( i < m_pDownloads.GetCount()); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if (!pdlCur->IsSignalled(this)) {
// packet processing pending for this state. we will check for
// DLSTATE_ABORT in each packet processing state and if true
// it will call CompleteOne(us), which marks each piece DLSTATE_DONE
BOOL bSetOnStack = SetOnStack(); pdlCur->Abort(this); if (bSetOnStack) ResetOnStack();
if (!pdlCur->IsSignalled(this)) { fWaitForAbortCompletion = TRUE; }
}
}
if (FAILED(m_hr)) { // fail with first real failure of a multipart code download
hr = m_hr; }
if (!fWaitForAbortCompletion && !IsOnStack()) // more processing left?
CompleteAll(hr, szError); // no, call complete all to cleanup
Exit:
DEBUG_LEAVE(0); return;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::WeAreReadyToSetup()
// ---------------------------------------------------------------------------
BOOL CCodeDownload::WeAreReadyToSetup() { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "CCodeDownload::WeAreReadyToSetup", "this=%#x", this )); BOOL fReady = TRUE; CDownload *pdlCur = NULL;
LISTPOSITION curpos = m_pDownloads.GetHeadPosition(); for (int i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if (! (( pdlCur->GetDLState() == DLSTATE_READY_TO_SETUP) || ( pdlCur->GetDLState() == DLSTATE_DONE)) ) {
fReady = FALSE; break; } }
DEBUG_LEAVE(fReady); return fReady;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::ResolveCacheDirNameConflicts()
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::ResolveCacheDirNameConflicts() { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "CCodeDownload::ResolveCacheDirNameConflicts", "this=%#x", this )); HRESULT hr = S_OK; char szDir[MAX_PATH]; static char *szCONFLICT = "CONFLICT"; CDownload *pdlCur = NULL; int n = 1;
if (m_szCacheDir) // the non-zeroness of this is also used by DoSetup
goto Exit; // to find it it's state machine has been init'ed
// ease the update of in-memory OCXes that have been released
// but still in memory as an optiization.
CoFreeUnusedLibraries();
// get a cache dir that has no name collisions for any of the
// Csetup objs for this CodeDownload
m_szCacheDir = g_szOCXCacheDir;
do {
LISTPOSITION curpos = m_pDownloads.GetHeadPosition(); for (int i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if ( (hr = pdlCur->CheckForNameCollision(m_szCacheDir)) != S_OK) break; }
if (hr == S_OK) {
if (m_szCacheDir == g_szOCXCacheDir) goto Exit; else goto Alloc_new; }
// current m_szCacheDir did not work, try next conflict.<n> dir
wnsprintf(szDir, sizeof(szDir)-1, "%s\\%s.%d", g_szOCXCacheDir, szCONFLICT, n++);
m_szCacheDir = szDir;
} while (GetFileAttributes(szDir) != -1); // while conflict dirs exist
// none of our existing conflict dirs solved the problem
// create a new conflict dir named conflict.<n>
if (!CreateDirectory(szDir, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
Alloc_new:
m_szCacheDir = new char [lstrlen(szDir)+1];
if (m_szCacheDir) { lstrcpy(m_szCacheDir, szDir); } else { hr = E_OUTOFMEMORY; }
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::DoSetup()
// Setup Phase:
// ---------------------------------------------------------------------------
VOID CCodeDownload::DoSetup() { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::DoSetup", "this=%#x", this )); HRESULT hr = S_OK; CDownload *pdlCur = NULL; int nSetupsPerCall = 0; HRESULT hr1 = S_OK; CUrlMkTls tls(hr1); // hr1 passed by reference!
Assert(SUCCEEDED(hr1)); Assert(tls->pCDLPacketMgr); int i; LISTPOSITION curpos;
if (FAILED(m_hr)) { // the self-registering EXE failed or user cancelled waiting
// for self-registering EXE
hr = m_hr; goto ErrorExit; }
if (UserCancelled()) { // user cancelled and CodeInstallProblem asked to abort
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); goto ErrorExit; }
if (IsSilentMode()) {
SetBitsInCache(); // flag that we have a new available version
hr = ERROR_IO_INCOMPLETE; goto ErrorExit; }
// ease the update of in-memory OCXes that have been released
// but still in memory as an optiization.
CoFreeUnusedLibraries();
if (m_bUninstallOld) { LPSTR pPluginFileName = NULL; CLSID myclsid = GetClsid(); CLocalComponentInfo lci;
if ((SUCCEEDED(GetClsidFromExtOrMime( GetClsid(), myclsid, GetMainExt(), GetMainType(), &pPluginFileName)))) {
if (IsControlLocallyInstalled(pPluginFileName, (pPluginFileName)?(LPCLSID)&GetClsid():&myclsid, GetMainDistUnit(), 0, 0, &lci, NULL) == S_OK) { HMODULE hMod; CHAR *szDU = NULL; REMOVECONTROLBYNAME pfn = NULL;
hMod = LoadLibrary("OCCACHE.DLL"); if (hMod) { pfn = (REMOVECONTROLBYNAME)GetProcAddress(hMod, "RemoveControlByName"); if (pfn) { if (SUCCEEDED(Unicode2Ansi(GetMainDistUnit(), &szDU))) { (*pfn)(lci.szExistingFileName, szDU, NULL, FALSE, TRUE); SAFEDELETE(szDU); } } FreeLibrary(hMod); } } } }
hr = ResolveCacheDirNameConflicts();
if (FAILED(hr)) { goto ErrorExit; }
// -------- UNSAFE TO ABORT BEGIN --------------
SetUnsafeToAbort();
// we can start processing CSetup
curpos = m_pDownloads.GetHeadPosition(); for (i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if ( (pdlCur->GetDLState() == DLSTATE_READY_TO_SETUP) || (pdlCur->GetDLState() == DLSTATE_SETUP)) {
// serialize all setups in this thread
hr = AcquireSetupCookie(); if (FAILED(hr)) { goto ErrorExit; } else if (hr == S_FALSE) {
goto Exit; // some other Code download on same thread
// is already in Setup phase. We will get a
// msg when its our turn
}
// acquired the setup cookie!
if (nSetupsPerCall++) { // here if we have already done 1 setup in one
// CDownload
// post a message to ourselves and we can do the next
// setup in that. This will give a chance for our client
// to process messages.
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP,this,S_OK);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) break;
goto Exit; }
if (m_bExactVersion) { pdlCur->SetExactVersion(TRUE); }
hr = pdlCur->DoSetup();
if (FAILED(hr)) break;
if(WaitingForEXE()) { // Did the setup start a self-registering EXE?
// if we are waiting for an EXE to complete self registeration,
// we can't proceed unless it completes. So kick off a
// packet for waiting for the EXE to complete.
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_WAIT_FOR_EXE, this,0);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) break;
goto Exit; }
if ( (pdlCur->GetDLState() == DLSTATE_READY_TO_SETUP) || (pdlCur->GetDLState() == DLSTATE_SETUP)) {
// more setup work left in pdlCur
// wait to get to this and other pieces in next msg
CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP,this,S_OK);
if (pPkt) { hr = pPkt->Post(); } else { hr = E_OUTOFMEMORY; }
if (FAILED(hr)) break;
goto Exit;
}
} /* if pdlCur needs setup */
} /* for each pdlCur */
ErrorExit:
hr1 = tls->pCDLPacketMgr->AbortPackets(GetDownloadHead());//aborts pdlCur, pdlCur->pcdl
Assert(SUCCEEDED(hr1)); if (FAILED(hr1)) { hr = hr1; }
// here when completed the setup phase
// give up the cookie and let someone else thru.
RelinquishSetupCookie();
CompleteAll(hr, NULL);
Exit:
DEBUG_LEAVE(0); return; // -------- NO ABORT TILL SETUP COMPLETES in COmpleteAll --------------
}
HRESULT CCodeDownload::UpdateJavaList(HKEY hkeyContains) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::UpdateJavaList", "this=%#x, %#x", this, hkeyContains )); HRESULT hr = S_OK; HKEY hkeyJava = 0; LPSTR lpVersion = ""; CDownload *pdlCur = NULL; int iNumJava = 0; int i; const static char *szJAVA = "Java"; LONG lResult = ERROR_SUCCESS;
// count total number of Java setups if any
LISTPOSITION curpos = m_pDownloads.GetHeadPosition(); for (i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
iNumJava += (pdlCur->GetJavaSetupList())->GetCount(); }
if (!iNumJava) goto Exit;
// open/create the Contains\Java key for this dist unit.
if (RegOpenKeyEx( hkeyContains, szJAVA, 0, KEY_ALL_ACCESS, &hkeyJava) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyContains, szJAVA, &hkeyJava)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
curpos = m_pDownloads.GetHeadPosition(); for (i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
LISTPOSITION curJavapos = (pdlCur->GetJavaSetupList())->GetHeadPosition(); iNumJava = (pdlCur->GetJavaSetupList())->GetCount();
for (int j=0; j < iNumJava; j++) {
CJavaSetup *pJavaSetup = (pdlCur->GetJavaSetupList())->GetNext(curJavapos); LPCWSTR szPkg = pJavaSetup->GetPackageName(); LPCWSTR szNameSpace = pJavaSetup->GetNameSpace(); char szPkgA[MAX_PATH]; if (szPkg) WideCharToMultiByte(CP_ACP, 0, szPkg, -1, szPkgA, MAX_PATH, NULL, NULL); char szNameSpaceA[MAX_PATH]; if (szNameSpace) WideCharToMultiByte(CP_ACP, 0, szNameSpace, -1, szNameSpaceA, MAX_PATH, NULL, NULL);
if (szNameSpace == NULL) { // global namespace if not specified
if ( (lResult = ::RegSetValueEx(hkeyJava, szPkgA, NULL, REG_SZ, (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; } } else {
// specific namespace provided. create a key under java
// for that namespace
HKEY hkeyNameSpace = 0; // open/create the Contains\Java\<namespace> key
if (RegOpenKeyEx( hkeyJava, szNameSpaceA, 0, KEY_ALL_ACCESS, &hkeyNameSpace) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyJava, szNameSpaceA, &hkeyNameSpace)) != ERROR_SUCCESS){ hr = HRESULT_FROM_WIN32(lResult); goto Exit; } } if ((lResult=RegSetValueEx(hkeyNameSpace, szPkgA, NULL, REG_SZ, (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
if (hkeyNameSpace) RegCloseKey(hkeyNameSpace);
}
}
}
Exit:
SAFEREGCLOSEKEY(hkeyJava);
DEBUG_LEAVE(hr); return hr;
}
HRESULT CCodeDownload::UpdateFileList(HKEY hkeyContains) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::UpdateFileList", "this=%#x, %#x", this, hkeyContains )); HRESULT hr = S_OK; HKEY hkeyFiles = 0; LPSTR lpVersion = ""; LONG lResult = ERROR_SUCCESS; const static char * szFILES = "Files"; int iNumFiles = m_ModuleUsage.GetCount(); int i; LISTPOSITION curpos = m_ModuleUsage.GetHeadPosition(); char szAnsiFileName[MAX_PATH];
// open/create the Contains\Files key for this dist unit.
if (RegOpenKeyEx( hkeyContains, szFILES, 0, KEY_ALL_ACCESS, &hkeyFiles) != ERROR_SUCCESS) { if (iNumFiles && (lResult = RegCreateKey( hkeyContains, szFILES, &hkeyFiles)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
if ( hkeyFiles) {
int iValue = 0; DWORD dwType = REG_SZ; DWORD dwValueSize = MAX_PATH; char szFileName[MAX_PATH];
while (RegEnumValue(hkeyFiles, iValue++, szFileName, &dwValueSize, 0, &dwType, NULL, NULL) == ERROR_SUCCESS) {
dwValueSize = MAX_PATH; // reset
if (GetFileAttributes(szFileName) == -1) {
// if file is not physically present then clear out our
// database. This is typically so, when you update
// on older version with a newer version, but deleted the
// old copy before installing the new one + changed the file
// names or location.
iValue = 0; RegDeleteValue(hkeyFiles, szFileName); } } }
for (i=0; i < iNumFiles; i++) {
LPCSTR szFileName = (m_ModuleUsage.GetNext(curpos))->GetFileName();
char szShortFileName[MAX_PATH]; #ifdef SHORTEN
if (!GetShortPathName(szFileName, szShortFileName, MAX_PATH)) { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; } #else
StrNCpy(szShortFileName, szFileName, MAX_PATH); #endif
// Under Win95 (and ONLY Win95), Setup API will convert characters
// from the OEM code page to the ANSI code page. The codebase we have
// is in the OEM codepage. After the Setup API installed the file,
// the installed file name is in ANSI. Therefore, in the enumeration,
// we need to look for the ANSI file name. Under other platforms,
// this just works, and converting to the ANSI code page should not
// be done. See IE5 RAID #34606 for more details.
if (g_bRunOnWin95) { OemToCharBuff(szShortFileName, szAnsiFileName, sizeof(szAnsiFileName) / sizeof(szAnsiFileName[0])); StrNCpy(szShortFileName, szAnsiFileName, MAX_PATH); }
if ( (lResult = ::RegSetValueEx(hkeyFiles, szShortFileName, NULL, REG_SZ, (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
}
Exit: SAFEREGCLOSEKEY(hkeyFiles);
DEBUG_LEAVE(hr); return hr;
}
HRESULT CCodeDownload::UpdateDependencyList(HKEY hkeyContains) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::UpdateDependencyList", "this=%#x, %#x", this, hkeyContains )); HRESULT hr = S_OK; HKEY hkeyDU = 0; LPSTR lpVersion = ""; LONG lResult = ERROR_SUCCESS; const static char * szDU = "Distribution Units"; int iNumFiles; int i; LISTPOSITION curpos; BOOL fFirstDependency = TRUE; LPWSTR wszDistUnit = NULL; LPSTR szDistUnit = NULL;
iNumFiles = m_pDownloads.GetCount(); curpos = m_pDownloads.GetHeadPosition();
RegDeleteKey(hkeyContains, szDU); // delete old version dependencies
for (i=0; i < iNumFiles; i++) {
CDownload *pdl = m_pDownloads.GetNext(curpos);
if (pdl->UsingCdlProtocol() && pdl->GetDLState() == DLSTATE_DONE) {
AddDistUnitList(pdl->GetDistUnitName());
}
}
iNumFiles = m_pDependencies.GetCount(); curpos = m_pDependencies.GetHeadPosition();
if (!iNumFiles) goto Exit;
for (i=0; i < iNumFiles; i++) {
wszDistUnit = m_pDependencies.GetNext(curpos);
if (wszDistUnit) {
SAFEDELETE(szDistUnit);
if (FAILED(Unicode2Ansi(wszDistUnit, &szDistUnit))) { hr = S_OK; goto Exit; }
if (fFirstDependency) {
if ((lResult = RegCreateKey( hkeyContains, szDU, &hkeyDU)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } fFirstDependency = FALSE; }
if ( (lResult = ::RegSetValueEx(hkeyDU, szDistUnit, NULL, REG_SZ, (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
}
}
Exit: SAFEREGCLOSEKEY(hkeyDU); SAFEDELETE(szDistUnit);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::UpdateLanguageCheck()
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::UpdateLanguageCheck(CLocalComponentInfo *plci) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::UpdateLanguageCheck", "this=%#x, %#x", this, plci )); HRESULT hr = S_OK; BOOL bNullClsid = IsEqualGUID(GetClsid() , CLSID_NULL); HKEY hkeyCheckPeriod = 0; HKEY hkeyClsid = 0; HKEY hkeyEmbedding = 0; LPOLESTR pwcsClsid = NULL; DWORD dwType; LONG lResult = ERROR_SUCCESS; LPSTR pszClsid = NULL; FILETIME ftnow; SYSTEMTIME st; const char *szCHECKPERIOD = "LanguageCheckPeriod"; const char *szLASTCHECKEDHI = "LastCheckedHi";
if (bNullClsid) goto Exit;
// return if we can't get a valid string representation of the CLSID
if (FAILED((hr=StringFromCLSID(GetClsid(), &pwcsClsid)))) goto Exit;
Assert(pwcsClsid != NULL);
// Open root HKEY_CLASSES_ROOT\CLSID key
lResult = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hkeyClsid);
if (lResult == ERROR_SUCCESS) { if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &pszClsid)))) { goto Exit; }
// Open the key for this embedding:
lResult = ::RegOpenKeyEx(hkeyClsid, pszClsid, 0, KEY_ALL_ACCESS, &hkeyEmbedding);
if (lResult == ERROR_SUCCESS) {
if ((lResult = RegOpenKeyEx( hkeyEmbedding, szCHECKPERIOD, 0, KEY_ALL_ACCESS, &hkeyCheckPeriod)) != ERROR_SUCCESS) {
if ((lResult = RegCreateKey( hkeyEmbedding, szCHECKPERIOD, &hkeyCheckPeriod)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
}
GetSystemTime(&st); SystemTimeToFileTime(&st, &ftnow);
RegSetValueEx(hkeyCheckPeriod, szLASTCHECKEDHI, NULL, REG_DWORD, (unsigned char *)&ftnow.dwHighDateTime, sizeof(DWORD)); } }
Exit: SAFEDELETE(pwcsClsid); SAFEDELETE (pszClsid);
SAFEREGCLOSEKEY (hkeyClsid); SAFEREGCLOSEKEY (hkeyEmbedding); SAFEREGCLOSEKEY (hkeyCheckPeriod);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::UpdateDistUnit()
// Add proper entries to the registry and register control to
// WebCheck so that control gets updated periodically.
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::UpdateDistUnit(CLocalComponentInfo *plci) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::UpdateDistUnit", "this=%#x, %#x", this, plci )); HRESULT hr = S_OK; LONG lResult = ERROR_SUCCESS; HKEY hkeyDist =0; HKEY hkeyThisDist = 0; HKEY hkeyDownloadInfo = 0; HKEY hkeyContains = 0; HKEY hkeyVersion = 0; const static char * szInstalledVersion = "InstalledVersion"; const static char * szAvailableVersion = "AvailableVersion"; const static char * szDownloadInfo = "DownloadInformation"; const static char * szCODEBASE = "CODEBASE"; const static char * szContains = "Contains"; const static char * szLOCALINF = "INF"; const static char * szLOCALOSD = "OSD"; const static char * szLASTMODIFIED = "LastModified"; const static char * szETAG = "Etag"; const static char * szINSTALLER = "Installer"; const static char * szExpire = "Expire"; const static char * szMSICD = "MSICD"; const static char * szPrecache = "Precache"; const static char * szSYSTEM = "SystemComponent"; LPSTR pszDist = NULL; LPSTR pszURL = NULL; LPWSTR pwszURL = NULL; char szVersionBuf[MAX_PATH]; DWORD dwExpire;
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_DIST_UNITS, 0, KEY_ALL_ACCESS, &hkeyDist)) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( HKEY_LOCAL_MACHINE, REGSTR_PATH_DIST_UNITS, &hkeyDist)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
if (FAILED((hr=::Unicode2Ansi(m_szDistUnit, &pszDist)))) { goto Exit; }
if(GetContextMoniker()) {
if (SUCCEEDED(hr = GetContextMoniker()->GetDisplayName(NULL, NULL, &pwszURL))) {
hr = Unicode2Ansi( pwszURL, &pszURL); }
if (FAILED(hr)) { goto Exit; } }
// open/create the dist unit key for this dist unit.
if (RegOpenKeyEx( hkeyDist, pszDist, 0, KEY_ALL_ACCESS, &hkeyThisDist) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyDist, pszDist, &hkeyThisDist)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
if (m_szDisplayName && ((lResult = ::RegSetValueEx(hkeyThisDist, NULL, NULL, REG_SZ, (unsigned char *)m_szDisplayName, lstrlen(m_szDisplayName)+1)) != ERROR_SUCCESS)){
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
lResult = ::RegSetValueEx(hkeyThisDist, szSYSTEM, NULL, REG_DWORD, (unsigned char *)&m_dwSystemComponent, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
lResult = ::RegSetValueEx(hkeyThisDist, szINSTALLER, NULL, REG_SZ, (unsigned char *)szMSICD, sizeof(szMSICD)+1);
if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
// if the OSD told us an expire interval, or the PE specifies it.
if ( m_dwExpire != 0xFFFFFFFF || (plci->szExistingFileName[0] && WantsAutoExpire( plci->szExistingFileName, &m_dwExpire )) ) {
lResult = ::RegSetValueEx(hkeyThisDist, szExpire, NULL, REG_DWORD, (unsigned char *)&m_dwExpire, sizeof(DWORD));
if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
// open/create the download info key for this dist unit.
if (RegOpenKeyEx( hkeyThisDist, szDownloadInfo, 0, KEY_ALL_ACCESS, &hkeyDownloadInfo) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyThisDist, szDownloadInfo, &hkeyDownloadInfo)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
// set download info params
if (pszURL && (lResult = ::RegSetValueEx(hkeyDownloadInfo, szCODEBASE, NULL, REG_SZ, (unsigned char *)pszURL, lstrlen(pszURL)+1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
if (!BitsInCache()) {
char szOldManifest[MAX_PATH]; DWORD Size = MAX_PATH; DWORD dwType; DWORD lResult = ::RegQueryValueEx(hkeyDownloadInfo, szLOCALINF, NULL, &dwType, (unsigned char *)szOldManifest, &Size);
if (lResult == ERROR_SUCCESS) {
if (!(GetMainInf() && (lstrcmpi(GetMainInf(), szOldManifest) == 0)) ) {
// there is an old entry, clean up the entry and also the file
// before upgrading to newer version
DeleteFile(szOldManifest); if (!GetMainInf()) RegDeleteValue(hkeyDownloadInfo, szLOCALINF); }
}
Size = MAX_PATH; lResult = ::RegQueryValueEx(hkeyDownloadInfo, szLOCALOSD, NULL, &dwType, (unsigned char *)szOldManifest, &Size);
if (lResult == ERROR_SUCCESS) {
if (!(GetOSD() && (lstrcmpi(GetOSD(), szOldManifest) == 0)) ) {
// there is an old entry, clean up the entry and also the file
// before upgrading to newer version
DeleteFile(szOldManifest); if (!GetOSD()) RegDeleteValue(hkeyDownloadInfo, szLOCALOSD); }
}
if (GetOSD() && (lResult = ::RegSetValueEx(hkeyDownloadInfo, szLOCALOSD, NULL, REG_SZ, (unsigned char *)GetOSD(), lstrlen(GetOSD())+1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
if (GetMainInf() && (lResult = ::RegSetValueEx(hkeyDownloadInfo, szLOCALINF, NULL, REG_SZ, (unsigned char *)GetMainInf(), lstrlen(GetMainInf())+1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
}
// end set download info params
if (!VersionFromManifest(szVersionBuf, sizeof(szVersionBuf))) {
if (!BitsInCache()) { if (!plci->IsPresent()) { // This used to be an E_UNEXPECTED case. Still unexpected,
// but we'll trace it and cope with it.
m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_DL_UPDATE_DU_NO_VERS, plci->szExistingFileName); plci->dwLocFVLS = 1; }
wsprintf(szVersionBuf, "%d,%d,%d,%d", (plci->dwLocFVMS & 0xffff0000)>>16, (plci->dwLocFVMS & 0xffff), (plci->dwLocFVLS & 0xffff0000)>>16, (plci->dwLocFVLS & 0xffff)); } else { // use the version number in the HTML or
// the one called by the code download delivery agent
// if present
if (m_dwFileVersionMS | m_dwFileVersionLS) {
wsprintf(szVersionBuf, "%d,%d,%d,%d", (m_dwFileVersionMS & 0xffff0000)>>16, (m_dwFileVersionMS & 0xffff), (m_dwFileVersionLS & 0xffff0000)>>16, (m_dwFileVersionLS & 0xffff));
} else { lstrcpy(szVersionBuf, "-1,-1,-1,-1"); } } }
if (BitsInCache()) {
if (RegOpenKeyEx( hkeyThisDist, szAvailableVersion, 0, KEY_ALL_ACCESS, &hkeyVersion) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyThisDist, szAvailableVersion, &hkeyVersion)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
// record result of caching bits.
HRESULT hrRecord = m_hr;
if (m_hr == TRUST_E_FAIL || m_hr == TRUST_E_SUBJECT_NOT_TRUSTED) { hrRecord = ERROR_IO_INCOMPLETE; }
lResult = ::RegSetValueEx(hkeyVersion, szPrecache, NULL, REG_DWORD, (unsigned char *)&hrRecord, sizeof(DWORD)); if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
} else {
if (RegOpenKeyEx( hkeyThisDist, szInstalledVersion, 0, KEY_ALL_ACCESS, &hkeyVersion) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyThisDist, szInstalledVersion, &hkeyVersion)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
// when we install a real version take out the
// AvailableVersion key if one exists
RegDeleteKey(hkeyThisDist, szAvailableVersion); }
lResult = ::RegSetValueEx(hkeyVersion, NULL, NULL, REG_SZ, (unsigned char *)szVersionBuf, lstrlen(szVersionBuf)+1);
if (lResult != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
if (BitsInCache()) { // in silent mode the control is not
// installed and so the below params to
// the dist unit are not relevant.
goto Exit; }
if (GetLastMod() && (lResult = ::RegSetValueEx(hkeyVersion, szLASTMODIFIED, NULL, REG_SZ, (unsigned char *)GetLastMod(), lstrlen(GetLastMod())+1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
if (GetEtag() && (lResult = ::RegSetValueEx(hkeyVersion, szETAG, NULL, REG_SZ, (unsigned char *)GetEtag(), lstrlen(GetEtag())+1)) != ERROR_SUCCESS) {
hr = HRESULT_FROM_WIN32(lResult); goto Exit; }
// store dist unit dependencies
// store the dist unit files, pkgs installed
// save away the manifest location/name
// open/create the Contains key for this dist unit.
if (RegOpenKeyEx( hkeyThisDist, szContains, 0, KEY_ALL_ACCESS, &hkeyContains) != ERROR_SUCCESS) { if ((lResult = RegCreateKey( hkeyThisDist, szContains, &hkeyContains)) != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(lResult); goto Exit; } }
hr = UpdateFileList(hkeyContains);
if (SUCCEEDED(hr)) hr = UpdateDependencyList(hkeyContains);
if (SUCCEEDED(hr)) hr = UpdateJavaList(hkeyContains);
Exit: SAFEDELETE(pszDist); SAFEDELETE(pszURL); SAFEDELETE(pwszURL);
SAFEREGCLOSEKEY(hkeyContains); SAFEREGCLOSEKEY(hkeyDownloadInfo); SAFEREGCLOSEKEY(hkeyVersion); SAFEREGCLOSEKEY(hkeyDist); SAFEREGCLOSEKEY(hkeyThisDist);
DEBUG_LEAVE(hr); return hr; }
typedef BOOL (WINAPI *SHRESTARTDIALOG)( HWND, LPTSTR, DWORD );
HRESULT DoReboot(HWND hWndParent) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "DoReboot", "%#x", hWndParent )); HRESULT hr = S_OK; HINSTANCE hShell32Lib;
#define SHRESTARTDIALOG_ORDINAL 59 // restart only exported by ordinal
SHRESTARTDIALOG pfSHRESTARTDIALOG = NULL;
if ( ( hShell32Lib = LoadLibrary( "shell32.dll" ) ) != NULL ) {
if ( !( pfSHRESTARTDIALOG = (SHRESTARTDIALOG) GetProcAddress( hShell32Lib, MAKEINTRESOURCE(SHRESTARTDIALOG_ORDINAL)) ) ) {
hr = HRESULT_FROM_WIN32(GetLastError()); } else { pfSHRESTARTDIALOG(hWndParent, NULL, EWX_REBOOT); }
} else { hr = HRESULT_FROM_WIN32(GetLastError()); }
if (hShell32Lib) FreeLibrary( hShell32Lib );
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::CompleteAll(HRESULT hr, LPCWSTR szError)
// All code is installed. If code install was succesful instantiate
// object if reqd, and report ClientBSC::OnStopBinding.
// ---------------------------------------------------------------------------
VOID CCodeDownload::CompleteAll(HRESULT hr, LPCWSTR szError) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::CompleteAll", "this=%#x, %#x, %.80wq", this, hr, szError )); char szCacheFileName[MAX_PATH]; HRESULT hrTls = S_OK; LISTPOSITION curpos; int iNumClients; int i; // TCHAR szBuffer[MAX_FORMAT_MESSAGE_BUFFER_LEN];
LPTSTR szBuffer = NULL; DWORD dwFMResult = 0; BOOL bForceWriteLog = FALSE; TCHAR szDll[MAX_PATH]; BOOL bLogGenOk = FALSE; OSVERSIONINFO osvi; WCHAR *pwszOSBErrMsg = NULL; char *pszExactErrMsg = NULL; char szDPFPath[MAX_PATH];
Assert(GetState() != CDL_Completed); SetState(CDL_Completed);
CUrlMkTls tls(hrTls); // hr passed by reference!
if (FAILED(hrTls)) { hr = hrTls; }
// get the installed version one more time
// to store in the dist unit db
CLocalComponentInfo lci;
LPSTR pPluginFileName = NULL; CLSID myclsid = GetClsid();
if ((SUCCEEDED(GetClsidFromExtOrMime( GetClsid(), myclsid, GetMainExt(), GetMainType(), &pPluginFileName)))) {
// get current version, pass 0, 1 to goose IsControl
// into filling in the version data, otherwise UpdateDistUnit
// will put a funny version in the registry ( which is better
// than bug 12081
//BUGBUG: make sure this call does the right things with zero impact
IsControlLocallyInstalled(pPluginFileName, (pPluginFileName)?(LPCLSID)&GetClsid():&myclsid, GetMainDistUnit(), 0, 1, &lci, NULL);
}
if ( m_plci->bForceLangGetLatest || (lci.bForceLangGetLatest && SUCCEEDED(hr)) ) { hr = UpdateLanguageCheck(&lci); }
if (SUCCEEDED(hr) && hr != ERROR_IO_INCOMPLETE) {
// update all the queued up ModuleUsage records
// we need to also remap to get the main clsid
// incase we didn't have one to begin with
UpdateModuleUsage();
}
if ( !FakeSuccess() && (SUCCEEDED(hr) || BitsInCache())) { UpdateDistUnit(&lci); }
if (NeedToReboot()) { HWND hWnd = GetClientBinding()->GetHWND();
// pass a notification to reboot
if (hWnd != INVALID_HANDLE_VALUE) { // g_RunSetupHook.DoReboot(hWnd, TRUE);
DoReboot(hWnd);
} else {
ICodeInstall* pCodeInstall = GetICodeInstall(); if (pCodeInstall) pCodeInstall->OnCodeInstallProblem( CIP_NEED_REBOOT, NULL, NULL, 0); } }
iNumClients = m_pClientbinding.GetCount();
// if called from CoGetClassFromURL we need to report
// ClientBSC::OnObjectAvailable with requested obj
if (SUCCEEDED(hr) && NeedObject() && hr != ERROR_IO_INCOMPLETE) {
curpos = m_pClientbinding.GetHeadPosition(); for (i=0; i < iNumClients; i++) {
hr = (m_pClientbinding.GetNext(curpos))->InstantiateObjectAndReport(this);
if(FAILED(hr)) { bLogGenOk = GenerateErrStrings(hr, &pszExactErrMsg, &pwszOSBErrMsg); if (!bLogGenOk) { pwszOSBErrMsg = NULL; pszExactErrMsg = NULL; } } }
} else { // call OnStopBinding for all BSCs (since we either do not need
// an instantiated object or we don't have one to give)
if(FAILED(hr)) { bLogGenOk = GenerateErrStrings(hr, &pszExactErrMsg, &pwszOSBErrMsg); if (!bLogGenOk) { pwszOSBErrMsg = NULL; pszExactErrMsg = NULL; } }
// call client's onstopbinding
curpos = m_pClientbinding.GetHeadPosition(); for (i=0; i < iNumClients; i++) { ((m_pClientbinding.GetNext(curpos))->GetAssBSC())-> OnStopBinding(hr, pwszOSBErrMsg); } SAFEDELETE(pwszOSBErrMsg);
m_debuglog->DebugOut(DEB_CODEDL, hr != S_OK, ID_CDLDBG_ONSTOPBINDING_CALLED, hr, (hr == S_OK)?TEXT(" (SUCCESS)"):TEXT(" (FAILED)"), (GetClsid()).Data1, GetMainURL(), GetMainType(), GetMainExt()); }
if (m_hKeySearchPath) { if (RegQueryValueEx(m_hKeySearchPath,"ForceCodeDownloadLog", NULL, NULL, NULL, NULL) == ERROR_SUCCESS) bForceWriteLog = TRUE; }
if (bForceWriteLog || (hr != S_OK && hr != ERROR_IO_INCOMPLETE)) { // BUGBUG: move these into .rc
if (!bLogGenOk && (HRESULT_FACILITY(hr) == FACILITY_CERT)) { DumpDebugLog(szCacheFileName, "Trust verification failed!!", hr); } else if (!bLogGenOk && (hr==HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH))) { DumpDebugLog(szCacheFileName, "Incompatible Binary for your platform", hr); } else if (bLogGenOk) { DumpDebugLog(szCacheFileName, pszExactErrMsg, hr); } else { DumpDebugLog(szCacheFileName, "Unknown Error!!", hr); }
}
// Refresh OCCACHE
// Only do this for NT for now. For some reason under Win95, sending
// this message here will cause a crash in SHELL32.DLL.
osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi);
if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && m_szCacheDir) { SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, m_szCacheDir, 0); }
// free all memory and clean up temp files
SAFEDELETE(pszExactErrMsg);
Release();
DEBUG_LEAVE(0); return; // -------- END OF UNSAFE TO ABORT --------------
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GenerateErrStrings()
// Parameters:
// ppszErrMsg: Saved error message or result of FormatMessage
// pwszError: Error message to pass back as szError in OSB
// hr: HRESULT of binding operation
// Returns:
// TRUE if successful
// ---------------------------------------------------------------------------
BOOL CCodeDownload::GenerateErrStrings(HRESULT hr, char **ppszErrMsg, WCHAR **ppwszError) { DEBUG_ENTER((DBG_DOWNLOAD, Bool, "CCodeDownload::GenerateErrStrings", "this=%#x, %#x, %#x, %#x", this, hr, ppszErrMsg, ppwszError )); DWORD dwFMResult; LPCTSTR pszSavedErrMsg = NULL; TCHAR *szBuf = NULL; char *szURL = NULL; char *pszErrorMessage = NULL; char szErrString[MAX_DEBUG_STRING_LENGTH]; char szDetails[MAX_DEBUG_STRING_LENGTH]; int iSize = 0;
if (!ppszErrMsg || !ppwszError) { dwFMResult = FALSE; goto Exit; }
// Get a saved error message if available
dwFMResult = FALSE; pszSavedErrMsg = CDLDebugLog::GetSavedMessage();
if (pszSavedErrMsg[0] != '\0') {
*ppszErrMsg = new char[lstrlen(pszSavedErrMsg) + 1]; if (!*ppszErrMsg) { dwFMResult = FALSE; goto Exit; }
lstrcpy(*ppszErrMsg, pszSavedErrMsg); dwFMResult = TRUE; }
if (!dwFMResult) {
// We don't have a saved message we can use. Try calling
// FormatMessage().
if (!dwFMResult) { dwFMResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, 0, (LPTSTR)&szBuf, 0, NULL); }
if (!dwFMResult) { dwFMResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, g_hInst, hr, 0, (LPTSTR)&szBuf, 0, NULL); }
if (dwFMResult) {
ASSERT(szBuf); ASSERT(lstrlen(szBuf));
*ppszErrMsg = new char[lstrlen(szBuf) + 1]; if (!*ppszErrMsg) { dwFMResult = FALSE; goto Exit; }
lstrcpy(*ppszErrMsg, szBuf); LocalFree(szBuf); } else { char szUnknown[MAX_DEBUG_FORMAT_STRING_LENGTH];
if (!dwFMResult && HRESULT_FACILITY(hr) == FACILITY_SETUPAPI) { LoadString(g_hInst, ID_CDLDBG_UNKNOWN_SETUP_ERROR, szUnknown, MAX_DEBUG_FORMAT_STRING_LENGTH); } else { LoadString(g_hInst, ID_CDLDBG_UNKNOWN_ERROR, szUnknown, MAX_DEBUG_FORMAT_STRING_LENGTH); }
*ppszErrMsg = new char[lstrlen(szUnknown) + 1]; if (!*ppszErrMsg) { dwFMResult = FALSE; goto Exit; }
lstrcpy(*ppszErrMsg, szUnknown); } }
// ppszErrMsg now holds saved error message or whatever came back from
// FormatMessage(). Construct a complete error message.
m_debuglog->MakeFile();
LoadString(g_hInst, ID_CDLDBG_ERROR_STRING, szErrString, MAX_DEBUG_STRING_LENGTH); LoadString(g_hInst, ID_CDLDBG_DETAILS_STRING, szDetails, MAX_DEBUG_STRING_LENGTH);
szURL = (char *)m_debuglog->GetUrlName(); ASSERT(szURL[0] != '\0');
iSize = lstrlen(*ppszErrMsg) + lstrlen(szErrString) + lstrlen(szDetails) + lstrlen(szURL) + 1;
pszErrorMessage = new char[iSize]; if (!pszErrorMessage) { dwFMResult = FALSE; goto Exit; }
wnsprintfA(pszErrorMessage, ID_CDLDBG_UNKNOWN_ERROR, "%s%s%s%s" , szErrString, *ppszErrMsg, szDetails, szURL);
if (FAILED(Ansi2Unicode(pszErrorMessage, ppwszError))) { dwFMResult = FALSE; goto Exit; }
Exit:
SAFEDELETE(pszErrorMessage);
DEBUG_LEAVE((dwFMResult != 0)); return (dwFMResult != 0); }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::DumpDebugLog()
// Output the debug error log. This log is written as a cache entry.
// ---------------------------------------------------------------------------
void CCodeDownload::DumpDebugLog(char *szCacheFileName, LPTSTR szErrorMsg, HRESULT hrError) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::DumpDebugLog", "this=%#x, %.80q, %#x, %#x", this, szCacheFileName, szErrorMsg, hrError )); m_debuglog->DumpDebugLog(szCacheFileName, MAX_PATH, szErrorMsg, hrError);
DEBUG_LEAVE(0); }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::AddRef
// ---------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CCodeDownload::AddRef() { DEBUG_ENTER((DBG_DOWNLOAD, Dword, "CCodeDownload::IUnknown::AddRef", "this=%#x", this )); ULONG ulRet = m_cRef++;
DEBUG_LEAVE(ulRet); return ulRet; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::Release
// Clean up all temp files and free all memory
// Caller of this function cannot rely on accessing any data
// other than locals on their stack.
// ---------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CCodeDownload::Release() { DEBUG_ENTER((DBG_DOWNLOAD, Dword, "CCodeDownload::IUnknown::Release", "this=%#x", this )); CDownload *pdlCur; HRESULT hr = S_OK;
Assert(m_cRef > 0);
if (--m_cRef != 0) {
DEBUG_LEAVE(m_cRef); return m_cRef; }
// release all CDownload objs
LISTPOSITION curpos = m_pDownloads.GetHeadPosition(); for (int i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
pdlCur->ReleaseParent(this); }
CUrlMkTls tls(hr); // hr passed by reference!
Assert(SUCCEEDED(hr));
// remove this CCodeDownload from the per-thread list
if (m_ListCookie) tls->pCodeDownloadList->RemoveAt(m_ListCookie);
delete this;
DEBUG_LEAVE(0); return 0; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::AcquireSetupCookie()
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::AcquireSetupCookie() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::AcquireSetupCookie", "this=%#x", this )); HRESULT hr = S_OK; CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) // if tls ctor failed above
goto Exit;
Assert(tls->pSetupCookie);
// need to serialize all Setup on this thread
// grab the Setup cookie
hr = tls->pSetupCookie->Acquire(this); if (hr != S_OK) {
Assert(!tls->pSetupCookie->IsFree()); Assert(!tls->pSetupCookie->IsOwner(this));
// wait till we get posted a message when the current owner
// relinquishes the cookie
goto Exit; }
// have the cookie
Assert(tls->pSetupCookie->IsOwner(this));
SetState(CDL_Setup);
Exit:
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::RelinquishSetupCookie()
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::RelinquishSetupCookie() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::RelinquishSetupCookie", "this=%#x", this )); HRESULT hr = S_OK; CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) // if tls ctor failed above
goto Exit;
if (tls->pSetupCookie->IsOwner(this)) {
tls->pSetupCookie->Relinquish(this);
Assert(!tls->pSetupCookie->IsOwner(this));
}
Exit:
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::AddDownloadToList
// ---------------------------------------------------------------------------
#ifndef unix
inline VOID #else
VOID #endif /* !unix */
CCodeDownload::AddDownloadToList(CDownload *pdl) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::AddDownloadToList", "this=%#x, %#x", this, pdl )); pdl->AddParent(this);
m_pDownloads.AddHead(pdl);
DEBUG_LEAVE(0); }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload:: FindCABInDownloadList(szURL, pdlHint)
// Find a download (typically a CAB) in download list
// pdlHint is the first thing we look at (for perf.) as most usually
// is a case of primary OCX in a CAB that the INF came in
// Returns:
// hr = ERROR (some error occurred, ignore *pdlMatch
// hr = S_OK
// if (*pdlMatch) match found, match is *pdlMatch
// else
// no match, or dups in other code downloads, download your own
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::FindCABInDownloadList(LPCWSTR szURL, CDownload* pdlHint, CDownload **ppdlMatch) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::FindCABInDownloadList", "this=%#x, %.80wq, %#x, %#x", this, szURL, pdlHint, ppdlMatch )); CDownload *pdlCur = NULL; HRESULT hr = S_OK; IMoniker* pmk = NULL; int i; LISTPOSITION curpos;
*ppdlMatch = pdlCur;
// create a moniker for the URL passed in and then we can pmk->IsEqual
// with every other CDownload's moniker.
IBindHost *pBH = GetClientBinding()->GetIBindHost(); if (pBH) { hr = pBH->CreateMoniker((LPWSTR)szURL, pdlHint->GetBindCtx(), &pmk, 0); } else { hr = CreateURLMoniker(m_pmkContext, szURL, &pmk); }
if (FAILED(hr)) goto Exit;
pdlCur = pdlHint; // assume hit
hr = pmk->IsEqual(pdlHint->GetMoniker());
if (hr != S_FALSE) goto Exit;
if (pdlHint->DoPost()) {
hr = pmk->IsEqual(m_pmkContext);
if (hr != S_FALSE) goto Exit; }
// hint failed, try the whole list
curpos = m_pDownloads.GetHeadPosition(); for (i=0; i < m_pDownloads.GetCount(); i++) {
pdlCur = m_pDownloads.GetNext(curpos);
if (pdlCur == pdlHint) // already tried the pdlHint, don't retry
continue;
hr = pmk->IsEqual(pdlCur->GetMoniker());
if (hr != S_FALSE) goto Exit;
}
pdlCur = NULL;
// now look across downloads
hr = FindDupCABInThread(pmk, &pdlCur);
Exit:
if (pmk) pmk->Release();
*ppdlMatch = pdlCur;
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::FindDupCABInThread(IMoniker *pmk, CDownload **ppdlMatch)
// Find a download (typically a CAB) across all code downloads in thread
// Returns:
// hr = ERROR
// hr = S_OK pdlCur?(match found):(no match found, do your own download)
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::FindDupCABInThread(IMoniker *pmk, CDownload **ppdlMatch) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::FindDupCABInThread", "this=%#x, %#x, %#x", this, pmk, ppdlMatch )); CDownload *pdlCur = NULL; HRESULT hr = S_OK; LISTPOSITION curposCDL, curposDL; CCodeDownload *pcdl; int iNumCDL; int i,j;
CUrlMkTls tls(hr); // hr passed by reference!
if (FAILED(hr)) goto Exit;
iNumCDL = tls->pCodeDownloadList->GetCount(); curposCDL = tls->pCodeDownloadList->GetHeadPosition();
// walk thru all the code downloads in the thread and check for DUPs
for (i=0; i < iNumCDL; i++) {
pcdl = tls->pCodeDownloadList->GetNext(curposCDL);
if (pcdl == this) continue;
// look into this CCodeDownload tree for dup
curposDL = pcdl->m_pDownloads.GetHeadPosition(); for (j=0; j < pcdl->m_pDownloads.GetCount(); j++) {
pdlCur = pcdl->m_pDownloads.GetNext(curposDL);
hr = pmk->IsEqual(pdlCur->GetMoniker());
if (hr != S_FALSE) goto Exit;
} pdlCur = NULL; }
hr = S_OK;
Exit:
if (pdlCur) {
// found a match in another Code Download
// add this pdl to our download list as well.
if (pdlCur->GetDLState() > DLSTATE_SETUP) { pdlCur = NULL; // too late to piggy back
} else {
m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_FOUND_DUP, pdlCur->GetURL(), GetClsid().Data1, GetMainURL(), m_dwFileVersionMS, m_dwFileVersionLS);
AddDownloadToList(pdlCur); }
}
*ppdlMatch = pdlCur;
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::InitLastModifiedFromDistUnit
// ---------------------------------------------------------------------------
VOID CCodeDownload::InitLastModifiedFromDistUnit() { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::InitLastModifiedFromDistUnit", "this=%#x", this ));
WIN32_FIND_DATA fd; HANDLE hf;
IsDistUnitLocallyInstalled( m_szDistUnit, 0, 0, m_plci, NULL, NULL, 0);
if (!m_plci->GetLastModifiedTime() ) {
if ((hf = FindFirstFile(m_plci->szExistingFileName, &fd)) != INVALID_HANDLE_VALUE) { memcpy(&(m_plci->ftLastModified), &(fd.ftLastWriteTime), sizeof(FILETIME)); FindClose(hf); } }
DEBUG_LEAVE(0); }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::DoCodeDownload
// Main action entry point for CCodeDownload
//
// This triggers creation of the first CDownload object for the CODE url
// if a local check for CLSID,FileVersion returns update_needed.
// (note : it is interesting to note here that if a control needs to just
// update a dependent DLL file it still needs to update the FileVersion
// of the primary control file (with CLSID implementation) for triggering
// any download at all!
//
// Once DoCodeDownload determines that an update is in order it creates
// a CClBinding for its client to call client BSC::OnstartBinding with.
//
// It then adds this CDownload obj to its list of downloads.
//
// If the m_url is a CAB or INF we need to download it before we know
// what we need to do next. Otherwise we create a CSetup obj for the
// download and add it to CDownload's list of pending Setup processing for
// stage 2 (setup and registeration). CSetup details later.
//
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::DoCodeDownload( CLocalComponentInfo *plci, DWORD flags) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::DoCodeDownload", "this=%#x, %#x, %#x", this, plci, flags )); CDownload *pdl = NULL; HRESULT hr = NOERROR; FILEXTN extn = FILEXTN_UNKNOWN; WCHAR szURL[INTERNET_MAX_URL_LENGTH]; LPWSTR lpDownloadURL; HGLOBAL hPostData = NULL; DWORD cbPostData = 0; ICodeInstall* pCodeInstall = GetICodeInstall();
// set if we need to instantiate the object or just download/install it
SetNeedObject(flags);
// set if we should ignore the internet search path
SetUseCodebaseOnly(flags);
m_plci = plci; Assert(plci);
// get lcid from the bind context
BIND_OPTS2 bopts; bopts.cbStruct = sizeof(BIND_OPTS2);
if (SUCCEEDED(GetClientBC()->GetBindOptions(&bopts)) && (bopts.cbStruct == sizeof(BIND_OPTS2)) ) {
m_lcid = bopts.locale; // else user default lcid is already in
DEBUG_PRINT(DOWNLOAD, INFO, ("CCodeDownload::DoCodeDownload::this=%#x, m_lcid: %d (%#x)\n", this, m_lcid, m_lcid )); }
if (m_plci->IsPresent() && pCodeInstall) {
// a prev ver exists. get permission to overwrite
// if ICodeInstall available
WCHAR szBuf[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, m_plci->szExistingFileName, -1, szBuf, MAX_PATH); hr = pCodeInstall->OnCodeInstallProblem( CIP_OLDER_VERSION_EXISTS, NULL, szBuf, 0);
// hr == E_ABORT: abort whole download
if (FAILED(hr)) {
if (hr == E_ABORT) hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
// else preserve error code of OnCodeInstallProblem
goto CD_Exit; }
}
// we need local version modified time only when doing GetLatest and
// only for the top most file
if (NeedLatestVersion() && m_plci->szExistingFileName[0] && !m_plci->GetLastModifiedTime() ) {
InitLastModifiedFromDistUnit();
}
if ((!m_url) || !(*m_url)) // if no CODE= <url>, mark that the option is
SetUsedCodeURL(); // already exhausted
// get the first site to try downloading from
hr = GetNextOnInternetSearchPath(GetClsid(), &hPostData, &cbPostData, szURL, INTERNET_MAX_URL_LENGTH, &lpDownloadURL, &extn);
if ( FAILED(hr)) goto CD_Exit;
// download the CODE=URL (ie. CAB or INF file first)
pdl = new CDownload(lpDownloadURL, extn, &hr);
if (!pdl) { hr = E_OUTOFMEMORY; goto CD_Exit; } else if (FAILED(hr)) { delete pdl; goto CD_Exit; }
AddDownloadToList(pdl);
if (hPostData) {
pdl->SetPostData(hPostData, cbPostData); hPostData = NULL; // mark as delegated, destructor for pdl will free
}
// don't need to set on stack for this case as we have addref'ed the
// pcdl. The reason we don't use the same addref technique on other
// situations is because while addref controls the life of the object
// the onstack is a dictate to not issue the OnStopBinding
// setting onstack from here will prevent the client from getting
// the OnStopBinding a must if an OnStartBinding has been issued.
hr = pdl->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE));
if (hr == MK_S_ASYNCHRONOUS) { SetState(CDL_Downloading); }
CD_Exit:
if (FAILED(hr)) {
if (hPostData) GlobalFree(hPostData);
}
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetupCODEUrl
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::SetupCODEUrl(LPWSTR *ppDownloadURL, FILEXTN *pextn) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetupCODEUrl", "this=%#x, %#x, %#x", this, ppDownloadURL, pextn )); char *pBaseFileName = NULL; char szBuf[INTERNET_MAX_URL_LENGTH];
WideCharToMultiByte(CP_ACP, 0, m_url, -1, szBuf, INTERNET_MAX_URL_LENGTH, 0,0); *pextn = GetExtnAndBaseFileName( szBuf, &pBaseFileName);
*ppDownloadURL = m_url; SetUsedCodeURL();
DEBUG_LEAVE(S_OK); return S_OK; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GetNextComponent
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::GetNextComponent( LPSTR szURL, LPSTR *ppCur ) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::GetNextComponent", "this=%#x, %.80q, %#x", this, szURL, ppCur )); HRESULT hr = S_OK; LPSTR pch = *ppCur; LPSTR pchOut = szURL; int cbBuffer = 0;
#define BEGIN_ANGLE_BRKT '<'
#define END_ANGLE_BRKT '>'
#define COMP_DELIMITER ';'
if (!pch || *pch == '\0') { hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); goto Exit; }
if (*pch == BEGIN_ANGLE_BRKT) {
pch++; // skip BEGIN_ANGLE_BRKT
for (; *pch && (*pch != END_ANGLE_BRKT);) { *pchOut++ = *pch++; if (cbBuffer++ >= INTERNET_MAX_URL_LENGTH) { hr = E_INVALIDARG; goto Exit; } }
if (*pch) pch++; // skip the END_ANGLE_BRKT
} else {
// assume its CODEBASE, just copy the string till we reach the
// next COMP_DELIMITER
for (; *pch && (*pch != COMP_DELIMITER);) { *pchOut++ = *pch++; if (cbBuffer++ >= INTERNET_MAX_URL_LENGTH) { hr = E_INVALIDARG; goto Exit; } } }
*pchOut = '\0';
if (*pch) *ppCur = pch+1; // skip the COMP_DELIMITER
else *ppCur = pch;
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GetNextOnInternetSearchPath
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::GetNextOnInternetSearchPath( REFCLSID rclsid, HGLOBAL *phPostData, DWORD *pcbPostData, LPWSTR szURL, DWORD dwSize, LPWSTR *ppDownloadURL, FILEXTN *pextn ) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::GetNextOnInternetSearchPath", "this=%#x, %#x, %#x, %#x, %.80wq, %#x, %#x, %#x", this, &rclsid, phPostData, pcbPostData, szURL, dwSize, ppDownloadURL, pextn ));
LONG lResult; HRESULT hr = S_OK; DWORD Size; DWORD dwType; char szBuf[INTERNET_MAX_URL_LENGTH]; DWORD cb; static char *szISP = "CodeBaseSearchPath";
char szClsid[MAX_PATH]; char szID[MAX_PATH]; char szHackMimeType[MAX_PATH]; HGLOBAL hPostData = NULL; char szNeedVersion[100]; // enough to hold four shorts as a,b,c,d + nulterm
BOOL bMimeType = FALSE;
// Ignore Internet Search path if set.
if (UseCodebaseOnly()) { SetupCODEUrl(ppDownloadURL,pextn); goto Exit; }
if (!m_hKeySearchPath) {
lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0, KEY_READ, &m_hKeySearchPath);
if (lResult == ERROR_SUCCESS) {
// get size reqd to store away entire searchpath
lResult = ::SHQueryValueEx(m_hKeySearchPath, szISP, NULL, &dwType, /* get size */ NULL, &Size);
if ( lResult == ERROR_SUCCESS) {
if (Size == 0) { // we don't check the CODE url in the case where there is a
// searchpath specified in the registry, but UseCodeURL is
// not one of the elements in the searchpath.
// This gives the client a choice to completely ignore the
// CODE URL if needed, but without specifying any other
// HTTP-POST url either
hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); goto Exit; }
// alloc memory
Size++; m_pSearchPath = new char [Size]; if (m_pSearchPath) { lResult = ::SHQueryValueEx(m_hKeySearchPath, szISP, NULL, &dwType, (unsigned char *)m_pSearchPath, &Size); Assert(lResult == ERROR_SUCCESS); m_pSearchPathNextComp = m_pSearchPath; } else { lResult = E_OUTOFMEMORY; } } }
if (lResult != ERROR_SUCCESS) {
if (UsedCodeURL()) { // no searchpath, already used CODE url?
hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); goto Exit; }
// no searchpath, use CODE=<url> in OBJECT tag
SetupCODEUrl(ppDownloadURL,pextn); goto Exit; } }
do {
hr = GetNextComponent(szBuf, &m_pSearchPathNextComp); if (FAILED(hr)) goto Exit;
if (lstrcmpi(szBuf, sz_USE_CODE_URL) == 0) {
if (UsedCodeURL()) { // already used CODE url?
continue; }
// use code=<url> in OBJECT tag
SetupCODEUrl(ppDownloadURL,pextn); goto Exit;
} else { break; }
} while (TRUE);
// here if HTTP-POST url
MultiByteToWideChar(CP_ACP, 0, szBuf, -1, szURL, dwSize);
*ppDownloadURL = szURL;
// do POST: form the post data
if (GetMainDistUnit()) {
WideCharToMultiByte(CP_ACP, 0, GetMainDistUnit(), -1, szClsid, MAX_PATH, 0,0); wnsprintf(szID, sizeof(szID)-1, "CLSID=%s", szClsid);
} else {
// no clsid, dispatch the mime type or ext
if (GetMainType()) {
// type available
WideCharToMultiByte(CP_ACP, 0, GetMainType(), -1, szClsid, MAX_PATH, 0,0); wnsprintf(szID, sizeof(szID)-1, "MIMETYPE=%s", szClsid); bMimeType = TRUE;
} else {
// ext
Assert(GetMainExt());
WideCharToMultiByte(CP_ACP, 0, GetMainExt(), -1, szClsid, MAX_PATH, 0,0); wnsprintf(szID, sizeof(szID)-1, "EXTENSION=%s", szClsid); }
}
cb = lstrlen(szID);
// compute increased size if Version is specified.
if (m_dwFileVersionMS || m_dwFileVersionLS) {
wsprintf(szNeedVersion, "&%s=%d,%d,%d,%d",szVersion, (m_dwFileVersionMS & 0xffff0000)>>16, (m_dwFileVersionMS & 0xffff), (m_dwFileVersionLS & 0xffff0000)>>16, (m_dwFileVersionLS & 0xffff));
cb += lstrlen(szNeedVersion); }
if (bMimeType) {
// hack the OBJECT index
// it doesn't support query by mime type
// so send out post data with the mime type in the CLSID=
// we also need to escape the '/' if any in the mime type
ComposeHackClsidFromMime(szHackMimeType, sizeof(szHackMimeType), szClsid); cb += lstrlen(szHackMimeType); }
hPostData = GlobalAlloc(GPTR, cb+1 ); // + 1 for null term
if (!hPostData) { hr = HRESULT_FROM_WIN32(GetLastError()); // typically, E_OUTOFMEMORY
goto ReleaseAndExit; }
lstrcpy((char *)hPostData, szID);
if (m_dwFileVersionMS || m_dwFileVersionLS) lstrcat( (char *)hPostData, szNeedVersion);
if (bMimeType) lstrcat( (char *)hPostData, szHackMimeType);
Assert(cb == (DWORD)lstrlen((char *)hPostData));
*pcbPostData = cb;
ReleaseAndExit:
Exit:
*phPostData = hPostData;
DEBUG_LEAVE(hr); return hr;
}
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::IsPackageLocallyInstalled
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::IsPackageLocallyInstalled(LPCWSTR szPackageName, LPCWSTR szNameSpace, DWORD dwVersionMS, DWORD dwVersionLS) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::IsPackageLocallyInstalled", "this=%#x, %.80wq, %.80wq, %#x, %#x", this, szPackageName, szNameSpace, dwVersionMS, dwVersionLS )); HRESULT hr = ::IsPackageLocallyInstalled(&m_pPackageManager, szPackageName, szNameSpace, dwVersionMS, dwVersionLS);
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::DestroyPCBHList
// ---------------------------------------------------------------------------
void CCodeDownload::DestroyPCBHList(CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CCodeDownload::DestroyPCBHList", "this=%#x, %#x", this, pcbhList )); LISTPOSITION lpos = 0; CCodeBaseHold *pcbh = NULL;
if (pcbhList) { lpos = pcbhList->GetHeadPosition(); while (lpos) { pcbh = pcbhList->GetNext(lpos); delete pcbh; } pcbhList->RemoveAll(); }
DEBUG_LEAVE(0); }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetCatalogFile
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::SetCatalogFile(LPSTR szCatalogFile) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetCatalogFile", "this=%#x, %.80q", this, szCatalogFile )); HRESULT hr = S_OK;
SAFEDELETE(m_szCatalogFile); m_szCatalogFile = new char[lstrlen(szCatalogFile) + 1]; if (m_szCatalogFile == NULL) { hr = E_OUTOFMEMORY; } else { lstrcpy(m_szCatalogFile, szCatalogFile); }
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::GetCatalogFile
// ---------------------------------------------------------------------------
LPSTR CCodeDownload::GetCatalogFile() { DEBUG_ENTER((DBG_DOWNLOAD, String, "CCodeDownload::GetCatalogFile", "this=%#x", this )); HRESULT hr = S_OK; LPSTR szCatalogFile = NULL; CClBinding *pBinding = NULL; IBindStatusCallback *pBSC = NULL; IServiceProvider *pServProv = NULL; LPCATALOGFILEINFO pcfi = NULL;
if (m_szCatalogFile) { szCatalogFile = m_szCatalogFile; } else { pBinding = m_pClientbinding.GetHead(); if (pBinding) { pBSC = pBinding->GetAssBSC(); if (pBSC) { hr = pBSC->QueryInterface(IID_ICatalogFileInfo, (void **)&pcfi); if (SUCCEEDED(hr)) { pcfi->GetCatalogFile(&szCatalogFile); m_szCatalogFile = szCatalogFile; SAFERELEASE(pcfi); } else { hr = pBSC->QueryInterface(IID_IServiceProvider, (void **)&pServProv); if (SUCCEEDED(hr)) { hr = pServProv->QueryService(IID_ICatalogFileInfo, IID_ICatalogFileInfo, (void **)&pcfi); if (SUCCEEDED(hr)) { pcfi->GetCatalogFile(&szCatalogFile); m_szCatalogFile = szCatalogFile; } SAFERELEASE(pServProv); SAFERELEASE(pcfi); } }
} } }
DEBUG_LEAVE(szCatalogFile); return szCatalogFile; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetMainCABJavaTrustPermissions
// ---------------------------------------------------------------------------
HRESULT CCodeDownload::SetMainCABJavaTrustPermissions(PJAVA_TRUST pbJavaTrust) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CCodeDownload::SetMainCABJavaTrustPermissions", "this=%#x, %#x", this, pbJavaTrust )); DWORD dwLen = 0; HRESULT hr = S_OK;
if (pbJavaTrust && m_pbJavaTrust == NULL) { // only do this once
// Clone the JAVA_TRUST object
if (pbJavaTrust->cbSize) { m_pbJavaTrust = (PJAVA_TRUST)new BYTE[pbJavaTrust->cbSize]; if (m_pbJavaTrust == NULL) { hr = E_OUTOFMEMORY; goto Exit; } } else { m_pbJavaTrust = NULL; goto Exit; }
memset(m_pbJavaTrust, 0, sizeof(JAVA_TRUST));
m_pbJavaTrust->cbJavaPermissions = pbJavaTrust->cbJavaPermissions; if (pbJavaTrust->cbJavaPermissions) { m_pbJavaTrust->pbJavaPermissions = new BYTE[m_pbJavaTrust->cbJavaPermissions]; if (m_pbJavaTrust->pbJavaPermissions == NULL) { hr = E_OUTOFMEMORY; goto Exit; } memcpy(m_pbJavaTrust->pbJavaPermissions, pbJavaTrust->pbJavaPermissions, m_pbJavaTrust->cbJavaPermissions); } else { m_pbJavaTrust->pbJavaPermissions = NULL; }
m_pbJavaTrust->cbSigner = pbJavaTrust->cbSigner; if (pbJavaTrust->cbSigner) { m_pbJavaTrust->pbSigner = new BYTE[m_pbJavaTrust->cbSigner]; if (m_pbJavaTrust->pbSigner == NULL) { hr = E_OUTOFMEMORY; goto Exit; } memcpy(m_pbJavaTrust->pbSigner, pbJavaTrust->pbSigner, m_pbJavaTrust->cbSigner); } else { m_pbJavaTrust->pbSigner = NULL; }
// pbJavaTrust in IE4 had a bug where this zone URL is not NULL
// terminated. Besides, we don't really require cloning the zone as we
// don't use it to install. So, we are not cloning the zone url
m_pbJavaTrust->pwszZone = NULL;
m_pbJavaTrust->cbSize = pbJavaTrust->cbSize; m_pbJavaTrust->flag = pbJavaTrust->flag; m_pbJavaTrust->fAllActiveXPermissions = pbJavaTrust->fAllActiveXPermissions; m_pbJavaTrust->fAllPermissions = pbJavaTrust->fAllPermissions; m_pbJavaTrust->dwEncodingType = pbJavaTrust->dwEncodingType; m_pbJavaTrust->guidZone = pbJavaTrust->guidZone; m_pbJavaTrust->hVerify = pbJavaTrust->hVerify; }
Exit:
DEBUG_LEAVE(hr); return hr; }
// ---------------------------------------------------------------------------
// %%Function: CCodeDownload::SetMainCABJavaTrustPermissions
// ---------------------------------------------------------------------------
PJAVA_TRUST CCodeDownload::GetJavaTrust() { DEBUG_ENTER((DBG_DOWNLOAD, Pointer, "CCodeDownload::GetJavaTrust", "this=%#x", this ));
DEBUG_LEAVE(m_pbJavaTrust); return m_pbJavaTrust; }
HRESULT ProcessImplementation(IXMLElement *pConfig, CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList, LCID lcidOverride, #ifdef WX86
CMultiArch *MultiArch, #endif
LPWSTR szBaseURL) { #ifdef WX86
DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "ProcessImplementation", "%#x, %#x, %#x, %#x, %.80wq", pConfig, pcbhList, lcidOverride, MultiArch, szBaseURL )); #else
DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "ProcessImplementation", "%#x, %#x, %#x, %.80wq", pConfig, pcbhList, lcidOverride, szBaseURL )); #endif
int nLastChildTag = -1; int nLastCodeBase = -1; int nLastOS = -1; int nLastProc = -1; OSVERSIONINFO osvi; BOOL fFoundAnyConfig = FALSE; BOOL fFoundAnyOS = FALSE, fFoundMatchingOS = FALSE; BOOL fFoundAnyProc = FALSE, fFoundMatchingProc = FALSE; IXMLElement *pCodeBase = NULL, *pLang = NULL, *pOS = NULL; IXMLElement *pOSVersion = NULL, *pProcessor = NULL; HRESULT hr = S_FALSE; // default: failed configuration match
BOOL bSetMainCodeBase = FALSE; #ifdef WX86
char *szPreferredArch; char *szAlternateArch; HRESULT hrArch; #endif
union { char szLang[MAX_PATH]; char szOS[MAX_PATH]; char szOSVersion[MAX_PATH]; char szProcessor[MAX_PATH]; };
if (pcbhList == NULL) { DEBUG_LEAVE(hr); return E_INVALIDARG; } pcbhList->RemoveAll();
osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi);
// process LANGUAGES tag.
if (GetFirstChildTag(pConfig, DU_TAG_LANG, &pLang) == S_OK) {
if (SUCCEEDED(GetAttributeA(pLang, DU_ATTRIB_VALUE, szLang, MAX_PATH))) {
if (FAILED(CheckLanguage(lcidOverride, szLang))) {
if ((lcidOverride == g_lcidBrowser) || (FAILED(CheckLanguage(g_lcidBrowser, szLang)))) { hr = S_FALSE; goto Exit;
} }
} else { // improperly formatted, skip it.
hr = S_FALSE; goto Exit; }
} // languages
// process OS tag
nLastOS = -1; fFoundAnyOS = FALSE; fFoundMatchingOS = FALSE; while (GetNextChildTag(pConfig, DU_TAG_OS, &pOS, nLastOS) == S_OK) { fFoundAnyOS = TRUE;
if (SUCCEEDED(GetAttributeA(pOS, DU_ATTRIB_VALUE, szOS, MAX_PATH))) {
if (lstrcmpi(szOS, (const char *) ((g_fRunningOnNT) ? szWinNT : szWin95)) == 0) {
if (GetFirstChildTag(pOS, DU_TAG_OSVERSION, &pOSVersion) == S_OK) {
if (SUCCEEDED(GetAttributeA(pOSVersion, DU_ATTRIB_VALUE, szOSVersion, MAX_PATH))) {
DWORD dwVersionMS = 0, dwVersionLS = 0;
if (SUCCEEDED(GetVersionFromString(szOSVersion, &dwVersionMS, &dwVersionLS))) { if (!((osvi.dwMajorVersion < (dwVersionMS>>16)) || (osvi.dwMajorVersion == (dwVersionMS>>16) && (osvi.dwMinorVersion < (dwVersionMS & 0xFFFF))) )) { fFoundMatchingOS = TRUE; break; }
} else { hr = HRESULT_FROM_WIN32(GetLastError()); goto Exit; }
} } else { // OS with no version
fFoundMatchingOS = TRUE; break; } } }
SAFERELEASE(pOS); SAFERELEASE(pOSVersion); }
if (fFoundAnyOS && !fFoundMatchingOS) { hr = S_FALSE; goto Exit; }
// check PROCESSOR tag
nLastProc = -1; fFoundAnyProc = FALSE; fFoundMatchingProc = FALSE; #ifdef WX86
MultiArch->SelectArchitecturePreferences( g_szProcessorTypes[g_CPUType], g_szProcessorTypes[PROCESSOR_ARCHITECTURE_INTEL], &szPreferredArch, &szAlternateArch); #endif
while (GetNextChildTag(pConfig, DU_TAG_PROCESSOR, &pProcessor, nLastProc) == S_OK) {
fFoundAnyProc = TRUE; if (SUCCEEDED(GetAttributeA(pProcessor, DU_ATTRIB_VALUE, szProcessor, MAX_PATH))) {
#ifdef WX86
if (lstrcmpi(szPreferredArch, szProcessor) == 0) { hrArch = MultiArch->RequirePrimaryArch(); Assert(SUCCEEDED(hrArch)); fFoundMatchingProc = TRUE; break; } else if (szAlternateArch) { if (lstrcmpi(szAlternateArch, szProcessor) == 0) { hrArch = MultiArch->RequireAlternateArch(); Assert(SUCCEEDED(hrArch)); fFoundMatchingProc = TRUE; break; } } #else
if (lstrcmpi(g_szProcessorTypes[g_CPUType],szProcessor) == 0) { fFoundMatchingProc = TRUE; break; } #endif
}
SAFERELEASE(pProcessor); }
if (fFoundAnyProc && !fFoundMatchingProc) { hr = S_FALSE; goto Exit; }
// process CODEBASE tag.
nLastCodeBase = -1; bSetMainCodeBase = FALSE; while (GetNextChildTag(pConfig, DU_TAG_CODEBASE, &pCodeBase, nLastCodeBase) == S_OK) {
hr = ProcessCodeBaseList(pCodeBase, pcbhList, szBaseURL); if (!bSetMainCodeBase) { CCodeBaseHold *pcbhMain;
pcbhMain = pcbhList->GetHead(); if (pcbhMain) { pcbhMain->dwFlags |= CBH_FLAGS_MAIN_CODEBASE; bSetMainCodeBase = TRUE; } }
SAFERELEASE(pCodeBase);
}
//REVIEW: We could also extract ABSTRACT, TITLE here
// NEEDSTRUSTEDSOURCE & SYSTEM only apply to Java applets so they can be checked in
// addition to this by ProcessJavaManifest.
// we passed all configuration filter criteria
hr = S_OK;
Exit: SAFERELEASE(pCodeBase); SAFERELEASE(pLang); SAFERELEASE(pOS); SAFERELEASE(pOSVersion); SAFERELEASE(pProcessor);
DEBUG_LEAVE(hr); return hr; }
HRESULT ProcessCodeBaseList(IXMLElement *pCodeBase, CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList, LPWSTR szBaseURL) { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "ProcessCodeBaseList", "%#x, %#x, %.80wq", pCodeBase, pcbhList, szBaseURL )); HRESULT hr = S_OK; DWORD dwSize = 0; CCodeBaseHold *pcbh = NULL; CCodeBaseHold *pcbhCur = NULL; LISTPOSITION lpos = 0; LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo = NULL; LPSTR szCodeBase = NULL; BOOL bRandom = FALSE; int iIndex = 0; int iCount = 0; int i; int iLastIndexInCache; char achBuffer[MAX_CACHE_ENTRY_INFO_SIZE]; char szRandom[MAX_PATH]; WCHAR szResult[INTERNET_MAX_URL_LENGTH];
union { char szSize[MAX_PATH]; char szStyle[MAX_PATH]; };
if (!pcbhList) { hr = E_INVALIDARG; goto Exit; }
pcbh = new CCodeBaseHold();
if (!pcbh) { hr = E_OUTOFMEMORY; goto Exit; }
if (SUCCEEDED(hr = DupAttribute(pCodeBase, DU_ATTRIB_HREF, &pcbh->wszCodeBase))) { pcbh->bHREF = TRUE; if (szBaseURL) { dwSize = INTERNET_MAX_PATH_LENGTH; UrlCombineW(szBaseURL, pcbh->wszCodeBase, szResult, &dwSize, 0); delete pcbh->wszCodeBase; pcbh->wszCodeBase = new WCHAR[dwSize + 1]; if (pcbh->wszCodeBase == NULL) { hr = E_OUTOFMEMORY; SAFEDELETE(pcbh); goto Exit; } StrCpyW(pcbh->wszCodeBase, szResult); }
} else if (SUCCEEDED(hr = DupAttribute(pCodeBase, DU_ATTRIB_FILENAME, &pcbh->wszCodeBase))) { pcbh->bHREF = FALSE; } else { SAFEDELETE(pcbh); goto Exit; }
bRandom = FALSE; if (SUCCEEDED(GetAttributeA(pCodeBase, DU_ATTRIB_RANDOM, szRandom, MAX_PATH))) { if (szRandom[0] == 'y' || szRandom[0] == 'Y') { bRandom = TRUE; } }
pcbh->wszDLGroup = NULL; pcbh->dwFlags &= ~CBH_FLAGS_DOWNLOADED; DupAttribute(pCodeBase, DU_ATTRIB_DL_GROUP, &pcbh->wszDLGroup);
if (SUCCEEDED(GetAttributeA(pCodeBase, DU_ATTRIB_SIZE, szSize, MAX_PATH))) { pcbh->dwSize = StrToIntA(szSize); } else { pcbh->dwSize = -1; }
pcbh->dwFlags &= ~CBH_FLAGS_MAIN_CODEBASE;
// If the cache entry for this URL exists, put this at the head of the
// list.
lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO)achBuffer; dwSize = MAX_CACHE_ENTRY_INFO_SIZE; if (SUCCEEDED(hr = Unicode2Ansi(pcbh->wszCodeBase, &szCodeBase))) { if (GetUrlCacheEntryInfo(szCodeBase, lpCacheEntryInfo, &dwSize)) { pcbhList->AddHead(pcbh); goto Exit; } SAFEDELETE(szCodeBase); } else { goto Exit; }
if (bRandom) {
// Set iLastIndexInCache to the last index in the linked list that
// contains a cache entry. The goal is to ensure all cache entries
// appear FIRST in the linked list.
iLastIndexInCache = -1; lpos = pcbhList->GetHeadPosition(); i = 0; while (lpos) { pcbhCur = pcbhList->GetNext(lpos); lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO)achBuffer; dwSize = MAX_CACHE_ENTRY_INFO_SIZE;
if (pcbhCur != NULL) { if (SUCCEEDED(Unicode2Ansi(pcbhCur->wszCodeBase, &szCodeBase))) { if (GetUrlCacheEntryInfo(szCodeBase, lpCacheEntryInfo, &dwSize)) { iLastIndexInCache = i; } SAFEDELETE(szCodeBase); } } i++; }
// Place codebase in list in a random order so that redundant codebases
// can traverse list in order yet still achieve randomness
iCount = pcbhList->GetCount(); if (iCount) { // Generate random insertion index, x, in the range:
// (iLastIndexInCache + 1) <= x < iCount
if (iCount - iLastIndexInCache == 1) { // must add at tail, since last list entry == last cache entry
pcbhList->AddTail(pcbh); } else { iIndex = (iLastIndexInCache + 1) + (randnum() % (iCount - iLastIndexInCache)); if (iIndex == iCount) { pcbhList->AddTail(pcbh); } else { lpos = pcbhList->FindIndex(iIndex); pcbhList->InsertBefore(lpos, pcbh); } } } else { pcbhList->AddTail(pcbh); } } else { // Not random, just ad as tail
pcbhList->AddTail(pcbh); }
Exit: SAFEDELETE(szCodeBase);
DEBUG_LEAVE(hr); return hr; }
#ifdef WX86
// ---------------------------------------------------------------------------
// %%Function: CMultiArch::RequirePrimaryArch
// ---------------------------------------------------------------------------
HRESULT CMultiArch::RequirePrimaryArch() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CMultiArch::RequirePrimaryArch", "this=%#x", this )); if (m_RequiredArch != PROCESSOR_ARCHITECTURE_UNKNOWN && m_RequiredArch != (DWORD)g_CPUType) { //
// The required arch has already been set for this download.
// The download to change the required arch in the middle or
// else a control and its support pieces may end up getting
// different architectures.
//
DEBUG_LEAVE(E_FAIL); return E_FAIL; } m_RequiredArch = (DWORD)g_CPUType;
DEBUG_LEAVE(S_OK); return S_OK; }
// ---------------------------------------------------------------------------
// %%Function: CMultiArch::RequireAlternateArch
// ---------------------------------------------------------------------------
HRESULT CMultiArch::RequireAlternateArch() { DEBUG_ENTER((DBG_DOWNLOAD, Hresult, "CMultiArch::RequireAlternateArch", "this=%#x", this )); if (m_RequiredArch != PROCESSOR_ARCHITECTURE_UNKNOWN && m_RequiredArch != PROCESSOR_ARCHITECTURE_INTEL) { //
// The required arch has already been set for this download.
// The download to change the required arch in the middle or
// else a control and its support pieces may end up getting
// different architectures.
//
DEBUG_LEAVE(E_FAIL); return E_FAIL; } m_RequiredArch = PROCESSOR_ARCHITECTURE_INTEL;
DEBUG_LEAVE(S_OK); return S_OK; }
// ---------------------------------------------------------------------------
// %%Function: CMultiArch::SelectArchitecturePreferences
// ---------------------------------------------------------------------------
VOID CMultiArch::SelectArchitecturePreferences( char *szNativeArch, char *szIntelArch, char **pszPreferredArch, char **pszAlternateArch ) { DEBUG_ENTER((DBG_DOWNLOAD, None, "CMultiArch::SelectArchitecturePreferences", "this=%#x, %.80q, %.80q, %#x, %#x", this, szNativeArch, szIntelArch, pszPreferredArch, pszAlternateArch )); if (g_fWx86Present) { switch (m_RequiredArch) { case PROCESSOR_ARCHITECTURE_INTEL: // An i386 binary has already been downloaded. Only download
// i386 binaries now.
*pszPreferredArch = szIntelArch; *pszAlternateArch = NULL; break;
case PROCESSOR_ARCHITECTURE_UNKNOWN: // No binaries downloaded so far. Prefer native and fallback
// to i386
*pszPreferredArch = szNativeArch; *pszAlternateArch = szIntelArch; break;
default: // A native binary has already been downloaded. Only download
// native binaries now.
*pszPreferredArch = szNativeArch; *pszAlternateArch = NULL; } } else { // No Wx86
*pszPreferredArch = szNativeArch; *pszAlternateArch = NULL; }
DEBUG_LEAVE(0); } #endif
|