// =========================================================================== // File: CDL.CXX // The main code downloader file. // #include #include #include #include #include #include #include #include #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 *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; 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); } // 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 } // tag loop Exit: SAFERELEASE(pConfig); SAFERELEASE(pPackage); SAFEDELETE(szPackageName); SAFEDELETE(pszNameSpace); DEBUG_LEAVE(hr); return hr; } // --------------------------------------------------------------------------- // %%Function: CCodeDownload::ProcessDependency // Processes 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 *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 . 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; 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 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 *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; 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 *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. 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. 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\ 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= , 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= 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= 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 *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 *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 *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