Windows2003-3790/inetcore/urlmon/download/cdl.cxx
2020-09-30 16:53:55 +02:00

7739 lines
230 KiB
C++

// ===========================================================================
// 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