Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7738 lines
230 KiB

  1. // ===========================================================================
  2. // File: CDL.CXX
  3. // The main code downloader file.
  4. //
  5. #include <cdlpch.h>
  6. #include <stdio.h>
  7. #include <shlwapi.h>
  8. #include <regstr.h>
  9. #include <initguid.h>
  10. #include <pkgguid.h>
  11. #include <winineti.h>
  12. #include <shlwapip.h>
  13. #include "advpub.h"
  14. #include "advpkp.h"
  15. #include "shlobj.h"
  16. #include "helpers.hxx"
  17. typedef HRESULT (WINAPI *REMOVECONTROLBYNAME)(
  18. LPCTSTR lpszFile,
  19. LPCTSTR lpszCLSID,
  20. LPCTSTR lpszTypeLibID,
  21. BOOL bForceRemove /*= FALSE*/,
  22. DWORD dwIsDistUnit /*= FALSE*/
  23. );
  24. typedef BOOL (*pfnSfcIsFileProtected)(HANDLE RpcHandle,LPCWSTR ProtFileName);
  25. extern LCID g_lcidBrowser; // default to english
  26. extern char g_szOCXCacheDir[];
  27. extern char g_szPlatform[]; // platform specific string for location of file
  28. extern HINSTANCE g_hInst;
  29. const static char *sz_USE_CODE_URL = "CODEBASE";
  30. const static char szCLSID[] = "CLSID";
  31. const static char szVersion[] = "Version";
  32. const static char *szTHISCAB = "thiscab";
  33. const static char *szIGNORE = "ignore";
  34. extern LPCSTR szWinNT;
  35. extern LPCSTR szWin95;
  36. extern LPCSTR szPlatform;
  37. extern char *g_szProcessorTypes[];
  38. extern CRunSetupHook g_RunSetupHook;
  39. extern int g_CPUType;
  40. extern BOOL g_bRunOnWin95;
  41. #define RANDNUM_MAX 0x7fff
  42. #define MAX_ATOM_SIZE 255
  43. LONG InitializeRandomSeed()
  44. {
  45. DEBUG_ENTER((DBG_DOWNLOAD,
  46. Dword,
  47. "InitializeRandomSeed",
  48. NULL
  49. ));
  50. SYSTEMTIME st;
  51. GetSystemTime(&st);
  52. DEBUG_LEAVE((LONG)st.wMilliseconds);
  53. return (LONG)st.wMilliseconds;
  54. }
  55. //+-------------------------------------------------------------------------
  56. //
  57. // Function: randnum
  58. //
  59. // Synopsys: Generate random number based on seed. (copied from crt)
  60. //
  61. //+-------------------------------------------------------------------------
  62. int randnum (void)
  63. {
  64. DEBUG_ENTER((DBG_DOWNLOAD,
  65. Int,
  66. "randnum",
  67. NULL
  68. ));
  69. static long holdrand = InitializeRandomSeed();
  70. holdrand = ((holdrand * 214013L + 2531011L) >> 16) & RANDNUM_MAX;
  71. DEBUG_LEAVE(holdrand);
  72. return(holdrand);
  73. }
  74. // Disabled by adding a DWORD value "DisableImprovedZoneCheck" with non=zero value under SETTINGS key
  75. BOOL CanUseImprovedZoneCheck()
  76. {
  77. DEBUG_ENTER((DBG_APP,
  78. Bool,
  79. "CanUseImprovedZoneCheck",
  80. NULL
  81. ));
  82. DWORD dwErr = ERROR_SUCCESS;
  83. BOOL fRet = TRUE;
  84. HKEY hKeyClient;
  85. DWORD dwDisable = 0;
  86. DWORD dwSize = sizeof(DWORD);
  87. DWORD dwType;
  88. dwErr = RegOpenKeyEx(
  89. HKEY_LOCAL_MACHINE,
  90. REGSTR_PATH_IE_SETTINGS,
  91. 0,
  92. KEY_QUERY_VALUE,
  93. &hKeyClient
  94. );
  95. if( dwErr == ERROR_SUCCESS )
  96. {
  97. dwErr = RegQueryValueEx(
  98. hKeyClient,
  99. "DisableImprovedZoneCheck",
  100. 0,
  101. &dwType,
  102. (LPBYTE)&dwDisable,
  103. &dwSize
  104. );
  105. if((dwErr == ERROR_SUCCESS) && dwDisable)
  106. {
  107. fRet = FALSE;
  108. }
  109. RegCloseKey(hKeyClient);
  110. }
  111. DEBUG_LEAVE(fRet);
  112. return fRet;
  113. }
  114. BOOL CCodeDownload::FileProtectionCheckSucceeded(LPCSTR pszExistingFileName)
  115. {
  116. DEBUG_ENTER((DBG_DOWNLOAD,
  117. Bool,
  118. "CCodeDownload::FileProtectionCheckSucceeded",
  119. "this=%#x, %.200q",
  120. this, (pszExistingFileName ? pszExistingFileName : "NULL")
  121. ));
  122. BOOL bRetval = FALSE;
  123. if (IsFileProtected(pszExistingFileName))
  124. {
  125. LPSTR pszCatalogFile = GetCatalogFile();
  126. LPSTR pszAtomStr;
  127. if (IsCatalogInstalled())
  128. {
  129. bRetval = TRUE;
  130. goto Exit;
  131. }
  132. if (pszCatalogFile && pszCatalogFile[0])
  133. {
  134. int cbLen = lstrlen(pszCatalogFile);
  135. if (cbLen >= MAX_ATOM_SIZE)
  136. {
  137. pszAtomStr = pszCatalogFile+cbLen+1-MAX_ATOM_SIZE;
  138. }
  139. else
  140. {
  141. pszAtomStr = pszCatalogFile;
  142. }
  143. ATOM atom = FindAtom(pszAtomStr);
  144. if (!atom)
  145. {
  146. DEBUG_PRINT(DOWNLOAD,
  147. INFO,
  148. ("No atom %d for catalog file atom-str: %.200q\n",
  149. atom, pszAtomStr
  150. ));
  151. HRESULT hr = m_wvt.InstallCatalogFile(pszCatalogFile);
  152. if (SUCCEEDED(hr))
  153. {
  154. SetCatalogInstalled();
  155. atom = AddAtom(pszAtomStr);
  156. SetAtom(atom);
  157. bRetval = TRUE;
  158. }
  159. }
  160. else
  161. {
  162. DEBUG_PRINT(DOWNLOAD,
  163. INFO,
  164. ("Found atom! %d for catalog file atom-str: %.200q\n",
  165. atom, pszAtomStr
  166. ));
  167. SetCatalogInstalled();
  168. bRetval = TRUE;
  169. }
  170. }
  171. }
  172. else
  173. {
  174. bRetval = TRUE;
  175. }
  176. Exit:
  177. DEBUG_LEAVE(bRetval);
  178. return bRetval;
  179. }
  180. HRESULT ExtractFromCabinet(PSESSION ps, LPCSTR lpCabFileName)
  181. {
  182. LPSTR lpFileName = NULL;
  183. if (ps && ps->pFilesToExtract)
  184. lpFileName = ps->pFilesToExtract->pszFilename;
  185. DEBUG_ENTER((DBG_DOWNLOAD,
  186. None,
  187. "ExtractFromCabinet",
  188. "%#x, %.80q, %.80q",
  189. ps, lpCabFileName, (lpFileName ? lpFileName : "NULL")
  190. ));
  191. #ifdef DBG
  192. PFNAME pfName = ps->pFilesToExtract;
  193. while(pfName)
  194. {
  195. lpFileName = pfName->pszFilename;
  196. DEBUG_PRINT(DOWNLOAD,
  197. INFO,
  198. ("ExtractFromCabinet filename: %.80q \n",
  199. (lpFileName ? lpFileName : "NULL")
  200. ));
  201. pfName = pfName->pNextName;
  202. }
  203. #endif
  204. HRESULT hr = ::Extract(ps, lpCabFileName);
  205. #ifdef DBG
  206. if (ps->flags & SESSION_FLAG_EXTRACT_ALL)
  207. {
  208. pfName = ps->pFileList;
  209. while(pfName)
  210. {
  211. lpFileName = pfName->pszFilename;
  212. DEBUG_PRINT(DOWNLOAD,
  213. INFO,
  214. ("ExtractFromCabinet ALL: filename: %.80q \n",
  215. (lpFileName ? lpFileName : "NULL")
  216. ));
  217. pfName = pfName->pNextName;
  218. }
  219. }
  220. #endif
  221. DEBUG_LEAVE(hr);
  222. return hr;
  223. }
  224. // ---------------------------------------------------------------------------
  225. // %%Function: CCodeDownload::CCodeDownload
  226. // CCodeDownload (main class tracking as a whole)
  227. // It has the client's BSC and creates a CClBinding for client.
  228. // ---------------------------------------------------------------------------
  229. CCodeDownload::CCodeDownload(
  230. LPCWSTR szDistUnit,
  231. LPCWSTR szURL,
  232. LPCWSTR szType,
  233. LPCWSTR szExt,
  234. DWORD dwFileVersionMS,
  235. DWORD dwFileVersionLS,
  236. HRESULT *phr)
  237. {
  238. DEBUG_ENTER((DBG_DOWNLOAD,
  239. None,
  240. "CCodeDownload::CCodeDownload",
  241. "this=%#x, %.80wq, %.80wq, %.80wq, %.80wq, %#x, %#x, %#x",
  242. this, szDistUnit, szURL, szType, szExt, dwFileVersionMS, dwFileVersionLS, phr
  243. ));
  244. DllAddRef();
  245. m_szLastMod[0] = '\0';
  246. m_plci = NULL;
  247. m_cRef = 1;
  248. m_hr = S_OK; // assume success
  249. m_url = 0;
  250. m_szDistUnit = NULL;
  251. m_pmkContext = NULL;
  252. m_dwFileVersionMS = dwFileVersionMS;
  253. m_dwFileVersionLS = dwFileVersionLS;
  254. m_lcid = GetThreadLocale();
  255. DEBUG_PRINT(DOWNLOAD,
  256. INFO,
  257. ("CCodeDownload::CCodeDownload::this=%#x, m_lcid: %d (%#x)\n",
  258. this, m_lcid, m_lcid
  259. ));
  260. m_flags = CD_FLAGS_INIT;
  261. m_szInf = NULL;
  262. m_szOSD = NULL;
  263. m_szDisplayName = NULL;
  264. m_szCacheDir = NULL; // set to default of g_szOCXCacheDir by DoSetup
  265. // the non-zeroness of this is also used by DoSetup
  266. // to find it it's state machine has been init'ed
  267. m_szWaitForEXE = NULL;
  268. m_state = CDL_NoOperation;
  269. m_hKeySearchPath = NULL;
  270. m_pSearchPath = NULL;
  271. m_pSearchPathNextComp = NULL;
  272. m_pDownloads.RemoveAll(); // init to NULL
  273. m_pClientbinding.RemoveAll(); // init to NULL
  274. m_ModuleUsage.RemoveAll(); // init to NULL
  275. m_pDependencies.RemoveAll(); // init to NULL
  276. m_dwSystemComponent = FALSE;
  277. m_pCurCode = m_pAddCodeSection = NULL;
  278. if (szURL) {
  279. DWORD len = lstrlenW(szURL) +1;
  280. if (len <= INTERNET_MAX_URL_LENGTH) {
  281. m_url = new WCHAR [len]; // make private copy
  282. if (m_url)
  283. StrCpyW(m_url, szURL);
  284. else
  285. *phr = E_OUTOFMEMORY;
  286. } else {
  287. // we make assumptions all over that URL size is less than
  288. // INTERNET_MAX_URL_LENGTH
  289. *phr = E_INVALIDARG;
  290. }
  291. }
  292. if (szDistUnit) {
  293. DWORD len = lstrlenW(szDistUnit) +1;
  294. m_szDistUnit = new WCHAR [len]; // make private copy
  295. if (m_szDistUnit)
  296. StrCpyW(m_szDistUnit, szDistUnit);
  297. else
  298. *phr = E_OUTOFMEMORY;
  299. }
  300. m_pi.hProcess = INVALID_HANDLE_VALUE;
  301. m_pi.hThread = INVALID_HANDLE_VALUE;
  302. if (szExt) {
  303. DWORD len = lstrlenW(szExt) +1;
  304. m_szExt = new WCHAR [len]; // make private copy
  305. if (m_szExt)
  306. StrCpyW(m_szExt, szExt);
  307. else
  308. *phr = E_OUTOFMEMORY;
  309. }
  310. if (szType) {
  311. DWORD len = lstrlenW(szType) +1;
  312. m_szType = new WCHAR [len]; // make private copy
  313. if (m_szType)
  314. StrCpyW(m_szType, szType);
  315. else
  316. *phr = E_OUTOFMEMORY;
  317. }
  318. m_szVersionInManifest = NULL;
  319. m_szCatalogFile = NULL;
  320. m_dwExpire = 0xFFFFFFFF;
  321. m_pbEtag = NULL;
  322. m_pbJavaTrust = NULL;
  323. m_debuglog = CDLDebugLog::MakeDebugLog();
  324. if(! m_debuglog)
  325. *phr = E_OUTOFMEMORY;
  326. else
  327. m_debuglog->Init(this);
  328. m_bUninstallOld = FALSE;
  329. m_bExactVersion = FALSE;
  330. m_hModSFC = 0;
  331. m_bCatalogInstalled = FALSE;
  332. m_atom = NULL;
  333. DEBUG_LEAVE(0);
  334. } // CCodeDownload
  335. // ---------------------------------------------------------------------------
  336. // %%Function: CCodeDownload::~CCodeDownload
  337. // ---------------------------------------------------------------------------
  338. CCodeDownload::~CCodeDownload()
  339. {
  340. DEBUG_ENTER((DBG_DOWNLOAD,
  341. None,
  342. "CCodeDownload::~CCodeDownload",
  343. "this=%#x",
  344. this
  345. ));
  346. Assert(m_cRef == 0);
  347. if (RelContextMk())
  348. SAFERELEASE(m_pmkContext);
  349. LISTPOSITION pos = m_pClientbinding.GetHeadPosition();
  350. int iNum = m_pClientbinding.GetCount();
  351. for (int i=0; i < iNum; i++) {
  352. CClBinding *pbinding = m_pClientbinding.GetNext(pos); // pass ref!
  353. pbinding->ReleaseClient();
  354. pbinding->Release();
  355. }
  356. m_pClientbinding.RemoveAll();
  357. pos = m_ModuleUsage.GetHeadPosition();
  358. iNum = m_ModuleUsage.GetCount();
  359. for (i=0; i < iNum; i++) {
  360. CModuleUsage *pModuleUsage = m_ModuleUsage.GetNext(pos); // pass ref!
  361. delete pModuleUsage;
  362. }
  363. m_ModuleUsage.RemoveAll(); // init to NULL
  364. m_pDownloads.RemoveAll(); // init to NULL
  365. pos = m_pDependencies.GetHeadPosition();
  366. iNum = m_pDependencies.GetCount();
  367. for (i=0; i < iNum; i++) {
  368. LPWSTR szDistUnit = m_pDependencies.GetNext(pos);
  369. delete szDistUnit;
  370. }
  371. if (m_szCacheDir != g_szOCXCacheDir)
  372. SAFEDELETE(m_szCacheDir);
  373. if (m_hKeySearchPath)
  374. ::RegCloseKey(m_hKeySearchPath);
  375. SAFEDELETE(m_szDistUnit);
  376. SAFEDELETE(m_url);
  377. SAFEDELETE(m_szType);
  378. SAFEDELETE(m_szExt);
  379. SAFEDELETE(m_szVersionInManifest);
  380. SAFEDELETE(m_szWaitForEXE);
  381. SAFEDELETE(m_pSearchPath);
  382. SAFEDELETE(m_szOSD);
  383. SAFEDELETE(m_szInf);
  384. SAFEDELETE(m_szDisplayName);
  385. SAFEDELETE(m_pAddCodeSection);
  386. SAFEDELETE(m_plci);
  387. SAFEDELETE(m_pbEtag);
  388. SAFERELEASE(m_pPackageManager);
  389. SAFEDELETE(m_szCatalogFile);
  390. DllRelease();
  391. if (m_pbJavaTrust) {
  392. if (m_pbJavaTrust->pwszZone) {
  393. delete (LPWSTR)m_pbJavaTrust->pwszZone;
  394. }
  395. SAFEDELETE(m_pbJavaTrust->pbSigner);
  396. SAFEDELETE(m_pbJavaTrust->pbJavaPermissions);
  397. delete m_pbJavaTrust;
  398. }
  399. if(m_debuglog)
  400. {
  401. m_debuglog->Release();
  402. m_debuglog = NULL;
  403. }
  404. if (m_hModSFC) {
  405. FreeLibrary(m_hModSFC);
  406. }
  407. if(m_atom)
  408. DeleteAtom(m_atom);
  409. DEBUG_LEAVE(0);
  410. } // ~CCodeDownload
  411. // ---------------------------------------------------------------------------
  412. // %%Function: CCodeDownload::SetDebugLog()
  413. // Remove the old log and set a new one
  414. // If debuglog is NULL, starts a new log
  415. // ---------------------------------------------------------------------------
  416. void CCodeDownload::SetDebugLog(CDLDebugLog * debuglog)
  417. {
  418. DEBUG_ENTER((DBG_DOWNLOAD,
  419. None,
  420. "CCodeDownload::SetDebugLog",
  421. "this=%#x, %#x",
  422. this, debuglog
  423. ));
  424. CDLDebugLog * pdlNew = NULL;
  425. if(debuglog)
  426. pdlNew = debuglog;
  427. else
  428. {
  429. pdlNew = CDLDebugLog::MakeDebugLog();
  430. if(!pdlNew)
  431. {
  432. DEBUG_LEAVE(0);
  433. // Out of Memory
  434. return;
  435. }
  436. pdlNew->Init(this);
  437. }
  438. if(pdlNew)
  439. {
  440. m_debuglog->Release();
  441. pdlNew->AddRef();
  442. m_debuglog = pdlNew;
  443. }
  444. DEBUG_LEAVE(0);
  445. }
  446. HRESULT
  447. CCodeDownload::CreateClientBinding(
  448. CClBinding **ppClientBinding,
  449. IBindCtx* pClientBC,
  450. IBindStatusCallback* pClientbsc,
  451. REFCLSID rclsid,
  452. DWORD dwClsContext,
  453. LPVOID pvReserved,
  454. REFIID riid,
  455. BOOL fAddHead,
  456. IInternetHostSecurityManager *pHostSecurityManager)
  457. {
  458. DEBUG_ENTER((DBG_DOWNLOAD,
  459. Hresult,
  460. "CCodeDownload::CreateClientBinding",
  461. "this=%#x, %#x, %#x, %#x, %#x, %#x, %#x, %#x, %B, %#x",
  462. this, ppClientBinding, pClientBC, pClientbsc, &rclsid, dwClsContext, pvReserved, &riid, fAddHead, pHostSecurityManager
  463. ));
  464. HRESULT hr = S_OK;
  465. Assert(ppClientBinding);
  466. *ppClientBinding = NULL;
  467. // make an IBinding for the client
  468. // this gets passed on the OnstartBinding of first download
  469. // as parameter for clientbsc::OnstartBinding
  470. CClBinding *pClientbinding= new
  471. CClBinding(this, pClientbsc, pClientBC,
  472. rclsid, dwClsContext, pvReserved, riid, pHostSecurityManager);
  473. if (pClientbinding) {
  474. if (fAddHead) {
  475. m_pClientbinding.AddHead(pClientbinding);
  476. } else {
  477. m_pClientbinding.AddTail(pClientbinding);
  478. }
  479. } else {
  480. hr = E_OUTOFMEMORY;
  481. }
  482. *ppClientBinding = pClientbinding;
  483. DEBUG_LEAVE(hr);
  484. return hr;
  485. }
  486. HRESULT
  487. CCodeDownload::AbortBinding( CClBinding *pbinding)
  488. {
  489. DEBUG_ENTER((DBG_DOWNLOAD,
  490. Hresult,
  491. "CCodeDownload::AbortBinding",
  492. "this=%#x, %#x",
  493. this, pbinding
  494. ));
  495. IBindStatusCallback* pbsc;
  496. int iNumBindings = m_pClientbinding.GetCount();
  497. ICodeInstall *pCodeInstall;
  498. HRESULT hr = S_OK;
  499. LISTPOSITION curpos;
  500. Assert(iNumBindings > 1);
  501. if (GetState() == CDL_Completed) {
  502. goto Exit;
  503. }
  504. curpos = m_pClientbinding.Find(pbinding);
  505. Assert(pbinding == m_pClientbinding.GetAt(curpos));
  506. if (pbinding != m_pClientbinding.GetAt(curpos)) {
  507. hr = HRESULT_FROM_WIN32(ERROR_INTERNAL_DB_CORRUPTION);
  508. goto Exit;
  509. }
  510. // now that we know the position of the binding,
  511. // pull out the binding and its related BSC from the list
  512. m_pClientbinding.RemoveAt(curpos);
  513. pbsc = pbinding->GetAssBSC();
  514. // report completion for this binding
  515. // note: if we are called to abort on a thread other than the one that
  516. // initiated the code download, then we report this onstopbinding on the
  517. // aborting thread (this one).
  518. pbsc->OnStopBinding(HRESULT_FROM_WIN32(ERROR_CANCELLED), NULL);
  519. // since we removed this binding from the list
  520. // we have to release this now. This will release the client BSC, BC
  521. pbinding->ReleaseClient();
  522. pbinding->Release();
  523. Exit:
  524. DEBUG_LEAVE(hr);
  525. return hr;
  526. }
  527. // ---------------------------------------------------------------------------
  528. // %%Function: CCodeDownload::PiggybackDupRequest
  529. // piggy backs DUP request on to this exitsing CCodeDownload
  530. // with matching szURL or rclsid
  531. // Returns:
  532. // S_OK: piggyback successful
  533. // Any other error: fatal error: fail
  534. HRESULT
  535. CCodeDownload::PiggybackDupRequest(
  536. IBindStatusCallback *pDupClientBSC,
  537. IBindCtx *pbc,
  538. REFCLSID rclsid,
  539. DWORD dwClsContext,
  540. LPVOID pvReserved,
  541. REFIID riid)
  542. {
  543. DEBUG_ENTER((DBG_DOWNLOAD,
  544. Hresult,
  545. "CCodeDownload::PiggybackDupRequest",
  546. "this=%#x, %#x, %#x, %#x, %#x, %#x, %#x",
  547. this, pDupClientBSC, pbc, &rclsid, dwClsContext, pvReserved, &riid
  548. ));
  549. HRESULT hr = S_OK;
  550. CClBinding *pClientBinding = NULL;
  551. Assert(m_pClientbinding.GetCount() > 0);
  552. if (m_pClientbinding.GetCount() <= 0) {
  553. hr = E_UNEXPECTED;
  554. goto Exit;
  555. }
  556. hr = CreateClientBinding( &pClientBinding, pbc, pDupClientBSC,
  557. rclsid, dwClsContext, pvReserved, riid,
  558. FALSE /* fAddHead */, NULL);
  559. if (SUCCEEDED(hr)) {
  560. Assert(pClientBinding);
  561. pClientBinding->SetState(CDL_Downloading);
  562. pDupClientBSC->OnStartBinding(0, pClientBinding);
  563. }
  564. Exit:
  565. DEBUG_LEAVE(hr);
  566. return hr;
  567. }
  568. // ---------------------------------------------------------------------------
  569. // %%Function: CCodeDownload::AnyCodeDownloadsInThread
  570. // checks if any code downloads are in progress in this thread
  571. // Returns:
  572. // S_OK: yes, downloads in progress
  573. // S_FALSE: none in progress
  574. // Any other error: fatal error: fail
  575. HRESULT
  576. CCodeDownload::AnyCodeDownloadsInThread()
  577. {
  578. DEBUG_ENTER((DBG_DOWNLOAD,
  579. Hresult,
  580. "CCodeDownload::AnyCodeDownloadsInThread",
  581. NULL
  582. ));
  583. HRESULT hr = S_OK;
  584. CUrlMkTls tls(hr); // hr passed by reference!
  585. if (FAILED(hr))
  586. {
  587. DEBUG_LEAVE(hr);
  588. return hr;
  589. }
  590. int iNumCDL = tls->pCodeDownloadList->GetCount();
  591. if (!iNumCDL)
  592. hr = S_FALSE;
  593. DEBUG_LEAVE(hr);
  594. return hr;
  595. }
  596. // ---------------------------------------------------------------------------
  597. // %%Function: CCodeDownload::IsDuplicateJavaSetup
  598. // Returns:
  599. // S_OK: Yes its a DUP
  600. HRESULT
  601. CCodeDownload::IsDuplicateJavaSetup(
  602. LPCWSTR szPackage)
  603. {
  604. DEBUG_ENTER((DBG_DOWNLOAD,
  605. Hresult,
  606. "CCodeDownload::IsDuplicateJavaSetup",
  607. "this=%#x, %.80wq",
  608. this, szPackage
  609. ));
  610. HRESULT hr = S_FALSE; // assume not found
  611. CDownload *pdlCur = NULL;
  612. LISTPOSITION curpos = m_pDownloads.GetHeadPosition();
  613. for (int i=0; i < m_pDownloads.GetCount(); i++) {
  614. pdlCur = m_pDownloads.GetNext(curpos);
  615. if (pdlCur->FindJavaSetup(szPackage) != NULL) {
  616. hr = S_OK;
  617. break;
  618. }
  619. }
  620. DEBUG_LEAVE(hr);
  621. return hr;
  622. }
  623. // ---------------------------------------------------------------------------
  624. // %%Function: CCodeDownload::IsDuplicateHook
  625. // Returns:
  626. // S_OK: Yes its a DUP
  627. HRESULT
  628. CCodeDownload::IsDuplicateHook(
  629. LPCSTR szHook)
  630. {
  631. DEBUG_ENTER((DBG_DOWNLOAD,
  632. Hresult,
  633. "CCodeDownload::IsDuplicateHook",
  634. "this=%#x, %.80q",
  635. this, szHook
  636. ));
  637. HRESULT hr = S_FALSE; // assume not found
  638. CDownload *pdlCur = NULL;
  639. LISTPOSITION curpos = m_pDownloads.GetHeadPosition();
  640. for (int i=0; i < m_pDownloads.GetCount(); i++) {
  641. pdlCur = m_pDownloads.GetNext(curpos);
  642. if (pdlCur->FindHook(szHook) != NULL) {
  643. hr = S_OK;
  644. break;
  645. }
  646. }
  647. DEBUG_LEAVE(hr);
  648. return hr;
  649. }
  650. HRESULT
  651. SetComponentDeclined(
  652. LPCWSTR pwszDistUnit,
  653. LPSTR pszSecId)
  654. {
  655. DEBUG_ENTER((DBG_DOWNLOAD,
  656. Hresult,
  657. "SetComponentDeclined",
  658. "%.80wq, %.80q",
  659. pwszDistUnit, pszSecId
  660. ));
  661. HRESULT hr = S_FALSE; // assume need to fault in
  662. LPSTR pszDistUnit = NULL;
  663. LONG lResult = ERROR_SUCCESS;
  664. HKEY hkeyDec = NULL;
  665. DWORD dwSize;
  666. DWORD dwValue;
  667. LPSTR szNull = "";
  668. char szKey[MAX_PATH*2];
  669. if (FAILED((hr=::Unicode2Ansi(pwszDistUnit, &pszDistUnit))))
  670. {
  671. goto Exit;
  672. }
  673. lstrcpyn(szKey, REGKEY_DECLINED_COMPONENTS, MAX_PATH*2);
  674. #ifndef ENABLE_PERSIST_DECLINED_COMPONNETS
  675. if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_WRITE, &hkeyDec) != ERROR_SUCCESS) {
  676. hr = S_OK;
  677. goto Exit;
  678. } else {
  679. if (hkeyDec) {
  680. RegCloseKey(hkeyDec);
  681. hkeyDec = 0;
  682. }
  683. }
  684. #endif
  685. StrCatBuff(szKey, "\\", MAX_PATH*2);
  686. StrCatBuff(szKey, pszDistUnit, MAX_PATH*2);
  687. if (RegOpenKeyEx(HKEY_CURRENT_USER, szKey, 0, KEY_WRITE, &hkeyDec) != ERROR_SUCCESS)
  688. {
  689. if ((lResult = RegCreateKey( HKEY_CURRENT_USER,
  690. szKey, &hkeyDec)) != ERROR_SUCCESS) {
  691. hr = HRESULT_FROM_WIN32(lResult);
  692. goto Exit;
  693. }
  694. }
  695. if (((lResult = RegSetValueEx (hkeyDec, pszSecId, 0, REG_SZ,
  696. (unsigned char *)szNull, 1))) != ERROR_SUCCESS) {
  697. hr = HRESULT_FROM_WIN32(lResult);
  698. }
  699. Exit:
  700. if (hkeyDec)
  701. RegCloseKey(hkeyDec);
  702. SAFEDELETE(pszDistUnit);
  703. DEBUG_LEAVE(hr);
  704. return hr;
  705. }
  706. // ---------------------------------------------------------------------------
  707. // %%Function: CCodeDownload::SetUserDeclined
  708. HRESULT
  709. CCodeDownload::SetUserDeclined()
  710. {
  711. DEBUG_ENTER((DBG_DOWNLOAD,
  712. Hresult,
  713. "CCodeDownload::SetUserDeclined",
  714. "this=%#x",
  715. this
  716. ));
  717. HRESULT hr = S_OK;
  718. LISTPOSITION pos = m_pClientbinding.GetHeadPosition();
  719. int iNum = m_pClientbinding.GetCount();
  720. int i;
  721. BYTE pbSecIdDocBase[INTERNET_MAX_URL_LENGTH];
  722. DWORD dwSecIdDocBase = INTERNET_MAX_URL_LENGTH;
  723. IInternetHostSecurityManager *pHostSecurityManager = GetClientBinding()->GetHostSecurityManager();
  724. if (!pHostSecurityManager) {
  725. // called by a host without sec mgr, don't record that you have
  726. // declined this component
  727. goto Exit;
  728. }
  729. hr = pHostSecurityManager->GetSecurityId(pbSecIdDocBase, &dwSecIdDocBase, 0);
  730. Assert(hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  731. if (FAILED(hr))
  732. goto Exit;
  733. // Hack!
  734. // Assumes internal knowledge of security id
  735. // the security has the zone id as the last dword, the rest of the stuff is
  736. // just the protocol followed by the site
  737. if (dwSecIdDocBase - sizeof(DWORD)) {
  738. pbSecIdDocBase[dwSecIdDocBase - sizeof(DWORD)] = '\0';
  739. }
  740. if (GetMainDistUnit()) {
  741. hr = SetComponentDeclined(GetMainDistUnit(), (char *)pbSecIdDocBase);
  742. if (FAILED(hr))
  743. goto Exit;
  744. }
  745. if (GetMainType()) {
  746. hr = SetComponentDeclined(GetMainType(), (char *)pbSecIdDocBase);
  747. if (FAILED(hr))
  748. goto Exit;
  749. }
  750. if (GetMainExt()) {
  751. hr = SetComponentDeclined(GetMainExt(), (char *)pbSecIdDocBase);
  752. if (FAILED(hr))
  753. goto Exit;
  754. }
  755. for (i=0; i < iNum; i++) {
  756. CClBinding *pbinding = m_pClientbinding.GetNext(pos); // pass ref!
  757. LPOLESTR pwszClsid;
  758. pwszClsid = NULL;
  759. if (!IsEqualGUID(pbinding->GetClsid() , CLSID_NULL)) {
  760. hr=StringFromCLSID(pbinding->GetClsid(), &pwszClsid);
  761. if (FAILED(hr))
  762. goto Exit;
  763. hr = SetComponentDeclined(pwszClsid, (char *)pbSecIdDocBase);
  764. SAFEDELETE(pwszClsid);
  765. if (FAILED(hr))
  766. goto Exit;
  767. }
  768. }
  769. Exit:
  770. DEBUG_LEAVE(hr);
  771. return hr;
  772. }
  773. BOOL IsDeclined(
  774. LPCWSTR pwszDistUnit,
  775. IInternetHostSecurityManager *pHostSecurityManager)
  776. {
  777. DEBUG_ENTER((DBG_DOWNLOAD,
  778. Bool,
  779. "IsDeclined",
  780. "%.80wq, %#x",
  781. pwszDistUnit, pHostSecurityManager
  782. ));
  783. BOOL bDeclined = FALSE;
  784. LPSTR pszDistUnit = NULL;
  785. BYTE pbSecIdDocBase[INTERNET_MAX_URL_LENGTH];
  786. DWORD dwSecIdDocBase = INTERNET_MAX_URL_LENGTH;
  787. HRESULT hr = S_OK;
  788. char szKey[MAX_PATH*2];
  789. Assert(pHostSecurityManager);
  790. hr = pHostSecurityManager->GetSecurityId(pbSecIdDocBase, &dwSecIdDocBase, 0);
  791. Assert(hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
  792. if (FAILED(hr))
  793. goto Exit;
  794. // Hack!
  795. // Assumes internal knowledge of security id
  796. // the security has the zone id as the last dword, the rest of the stuff is
  797. // just the protocol followed by the site
  798. if (dwSecIdDocBase - sizeof(DWORD)) {
  799. pbSecIdDocBase[dwSecIdDocBase - sizeof(DWORD)] = '\0';
  800. }
  801. lstrcpyn(szKey, REGKEY_DECLINED_COMPONENTS, MAX_PATH*2);
  802. if (SUCCEEDED(::Unicode2Ansi(pwszDistUnit, &pszDistUnit)))
  803. {
  804. StrCatBuff(szKey, "\\", MAX_PATH*2);
  805. StrCatBuff(szKey, pszDistUnit, MAX_PATH*2);
  806. SAFEDELETE(pszDistUnit);
  807. if (SHRegGetUSValue( szKey, (char *)pbSecIdDocBase, NULL, NULL, NULL, 0,NULL,0) == ERROR_SUCCESS)
  808. {
  809. bDeclined = TRUE;
  810. }
  811. }
  812. Exit:
  813. DEBUG_LEAVE(bDeclined);
  814. return bDeclined;
  815. }
  816. // ---------------------------------------------------------------------------
  817. // %%Function: CCodeDownload::HasUserDeclined
  818. HRESULT
  819. CCodeDownload::HasUserDeclined(
  820. LPCWSTR szDistUnit,
  821. LPCWSTR szType,
  822. LPCWSTR szExt,
  823. IBindStatusCallback *pClientBSC,
  824. IInternetHostSecurityManager *pHostSecurityManager)
  825. {
  826. DEBUG_ENTER((DBG_DOWNLOAD,
  827. Hresult,
  828. "CCodeDownload::HasUserDeclined",
  829. "%.80wq, %.80wq, %.80wq, %#x, %#x",
  830. szDistUnit, szType, szExt, pClientBSC, pHostSecurityManager
  831. ));
  832. HRESULT hr = S_OK;
  833. DWORD grfBINDF = 0;
  834. BINDINFO bindInfo;
  835. memset(&bindInfo, 0, sizeof(BINDINFO));
  836. bindInfo.cbSize = sizeof(BINDINFO);
  837. if (pHostSecurityManager) {
  838. pClientBSC->GetBindInfo(&grfBINDF, &bindInfo);
  839. ReleaseBindInfo(&bindInfo);
  840. if (!(grfBINDF & BINDF_RESYNCHRONIZE)) { // User has hit refresh
  841. if ((szDistUnit && IsDeclined(szDistUnit,pHostSecurityManager)) ||
  842. (szType && IsDeclined(szType,pHostSecurityManager)) ||
  843. (szExt && IsDeclined(szExt,pHostSecurityManager))) {
  844. hr = INET_E_CODE_DOWNLOAD_DECLINED;
  845. }
  846. }
  847. }
  848. DEBUG_LEAVE(hr);
  849. return hr;
  850. }
  851. // ---------------------------------------------------------------------------
  852. // %%Function: CCodeDownload::HandleDuplicateCodeDownloads
  853. // handles duplicates by piggy backing them on to exitsing CCodeDownloads
  854. // with matching szURL or rclsid
  855. // Returns:
  856. // S_OK: no dups found, do separate code download
  857. // MK_S_ASYNCHRONOUS: dup piggybacked
  858. // Any other error: fatal error: fail
  859. HRESULT
  860. CCodeDownload::HandleDuplicateCodeDownloads(
  861. LPCWSTR szURL,
  862. LPCWSTR szType,
  863. LPCWSTR szExt,
  864. REFCLSID rclsid,
  865. LPCWSTR szDistUnit,
  866. DWORD dwClsContext,
  867. LPVOID pvReserved,
  868. REFIID riid,
  869. IBindCtx* pbc,
  870. IBindStatusCallback *pDupClientBSC,
  871. DWORD dwFlags,
  872. IInternetHostSecurityManager *pHostSecurityManager)
  873. {
  874. DEBUG_ENTER((DBG_DOWNLOAD,
  875. Hresult,
  876. "CCodeDownload::HandleDuplicateCodeDownloads",
  877. "%.80wq, %.80wq, %.80wq, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x, %#x, %#x",
  878. szURL, szType, szExt, &rclsid, szDistUnit, dwClsContext,
  879. pvReserved, &riid, pbc, pDupClientBSC, dwFlags, pHostSecurityManager
  880. ));
  881. HRESULT hr = S_OK;
  882. LISTPOSITION curpos;
  883. CCodeDownload *pcdl;
  884. int iNumCDL;
  885. int i;
  886. CUrlMkTls tls(hr); // hr passed by reference!
  887. if (FAILED(hr))
  888. goto Exit;
  889. // first check to make sure that
  890. // this object has not been cancelled before by user
  891. // we will skip this check only when the user hits refresh on a page
  892. if (!(dwFlags & CD_FLAGS_SKIP_DECLINED_LIST_CHECK)) {
  893. hr = HasUserDeclined(szDistUnit, szType, szExt,pDupClientBSC,pHostSecurityManager);
  894. if (FAILED(hr))
  895. goto Exit;
  896. }
  897. iNumCDL = tls->pCodeDownloadList->GetCount();
  898. curpos = tls->pCodeDownloadList->GetHeadPosition();
  899. // walk thru all the code downloads in the thread and check for DUPs
  900. for (i=0; i < iNumCDL; i++) {
  901. pcdl = tls->pCodeDownloadList->GetNext(curpos);
  902. BOOL bNullClsid = IsEqualGUID(rclsid , CLSID_NULL);
  903. if (bNullClsid) {
  904. // handle dups based on TYPE and Ext
  905. if (! ( ( szDistUnit && pcdl->GetMainDistUnit() &&
  906. (StrCmpIW(szDistUnit, pcdl->GetMainDistUnit()) == 0)) ||
  907. ( szType && pcdl->GetMainType() &&
  908. (StrCmpIW(szType, pcdl->GetMainType()) == 0)) ||
  909. ( szExt && pcdl->GetMainExt() &&
  910. (StrCmpIW(szExt, pcdl->GetMainExt()) == 0))
  911. ) ) {
  912. // no match by type or ext
  913. continue;
  914. }
  915. // found match, fall thru to piggyback
  916. } else if (IsEqualGUID(rclsid , pcdl->GetClsid())) {
  917. if (szURL) {
  918. if(StrCmpIW(szURL, pcdl->GetMainURL()) != 0) {
  919. pcdl->m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_OBJ_TAG_MIXED_USAGE,
  920. (pcdl->GetClsid()).Data1,szURL, pcdl->GetMainURL());
  921. }
  922. } else {
  923. if(pcdl->GetMainURL() != NULL) {
  924. pcdl->m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_OBJ_TAG_MIXED_USAGE,
  925. (pcdl->GetClsid()).Data1, pcdl->GetMainURL(), NULL);
  926. }
  927. }
  928. // found matching GUID, fall thru to piggyback
  929. } else if (szURL && (pcdl->GetMainURL() != NULL)) {
  930. if (StrCmpIW(szURL, pcdl->GetMainURL()) != 0) {
  931. continue;
  932. }
  933. // found matching CODEBASE, fall thru to piggyback
  934. } else {
  935. continue;
  936. }
  937. // found DUP!
  938. if (pcdl->GetState() != CDL_Completed) {
  939. hr = pcdl->PiggybackDupRequest(pDupClientBSC, pbc,
  940. rclsid, dwClsContext, pvReserved, riid);
  941. if (hr == S_OK) {
  942. // piggy back was successful
  943. hr = MK_S_ASYNCHRONOUS;
  944. }
  945. }
  946. break;
  947. } /* for */
  948. Exit:
  949. DEBUG_LEAVE(hr);
  950. return hr;
  951. }
  952. // ---------------------------------------------------------------------------
  953. // %%Function: CCodeDownload::SetWaitingForEXE
  954. // set that we are waiting for an EXE
  955. // either a self-registering localserver32 or a setup program
  956. HRESULT
  957. CCodeDownload::SetWaitingForEXE(
  958. LPCSTR szEXE,
  959. BOOL bDeleteEXEWhenDone)
  960. {
  961. DEBUG_ENTER((DBG_DOWNLOAD,
  962. Hresult,
  963. "CCodeDownload::SetWaitingForEXE",
  964. "this=%#x, %.80q, %B",
  965. this, szEXE, bDeleteEXEWhenDone
  966. ));
  967. m_flags |= CD_FLAGS_WAITING_FOR_EXE;
  968. SAFEDELETE(m_szWaitForEXE);
  969. int len = 0;
  970. if (szEXE)
  971. len = lstrlen(szEXE);
  972. if (len) {
  973. m_szWaitForEXE = new CHAR [len + 1];
  974. } else {
  975. DEBUG_LEAVE(E_INVALIDARG);
  976. return E_INVALIDARG;
  977. }
  978. if (!m_szWaitForEXE) {
  979. DEBUG_LEAVE(E_OUTOFMEMORY);
  980. return E_OUTOFMEMORY;
  981. }
  982. lstrcpy(m_szWaitForEXE, szEXE);
  983. if (bDeleteEXEWhenDone)
  984. SetDeleteEXEWhenDone();
  985. DEBUG_LEAVE(S_OK);
  986. return S_OK;
  987. }
  988. typedef HRESULT (STDAPICALLTYPE *LPFNREGSVR)();
  989. // ---------------------------------------------------------------------------
  990. // %%Function: CCodeDownload::RegisterPEDll
  991. // Self-register's the PE OCX.
  992. HRESULT
  993. CCodeDownload::RegisterPEDll(
  994. LPCSTR lpSrcFileName)
  995. {
  996. DEBUG_ENTER((DBG_DOWNLOAD,
  997. Hresult,
  998. "CCodeDownload::RegisterPEDll",
  999. "this=%#x, %.80q",
  1000. this, lpSrcFileName
  1001. ));
  1002. HMODULE hMod;
  1003. LPFNREGSVR lpRegSvrFn;
  1004. HRESULT hr = S_OK;
  1005. IActiveXSafetyProvider *pProvider;
  1006. if ((hr = IsRegisterableDLL(lpSrcFileName)) != S_OK) {
  1007. // no DllRegisterServer entry point, don't LoadLibarary it.
  1008. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_MISSING_DLLREGISTERSERVER, lpSrcFileName);
  1009. goto Exit;
  1010. }
  1011. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DLL_REGISTERED, lpSrcFileName);
  1012. // assuming oleinitialze
  1013. hr = GetActiveXSafetyProvider(&pProvider);
  1014. if (hr != S_OK) {
  1015. goto Exit;
  1016. }
  1017. if (pProvider) {
  1018. hr = pProvider->SafeDllRegisterServerA(lpSrcFileName);
  1019. pProvider->Release();
  1020. } else {
  1021. if ((hMod = LoadLibraryEx(lpSrcFileName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) {
  1022. hr = HRESULT_FROM_WIN32(GetLastError());
  1023. goto Exit;
  1024. }
  1025. lpRegSvrFn = (LPFNREGSVR) GetProcAddress(hMod, "DllRegisterServer");
  1026. if (lpRegSvrFn == NULL) {
  1027. hr = HRESULT_FROM_WIN32(GetLastError());
  1028. }
  1029. if (lpRegSvrFn)
  1030. hr = (*lpRegSvrFn)();
  1031. FreeLibrary(hMod);
  1032. }
  1033. Exit:
  1034. DEBUG_LEAVE(hr);
  1035. return hr;
  1036. }
  1037. #ifdef WX86
  1038. // ---------------------------------------------------------------------------
  1039. // %%Function: CCodeDownload::RegisterWx86Dll
  1040. // Self-register's the PE OCX.
  1041. HRESULT
  1042. CCodeDownload::RegisterWx86Dll(
  1043. LPCSTR lpSrcFileName)
  1044. {
  1045. DEBUG_ENTER((DBG_DOWNLOAD,
  1046. Hresult,
  1047. "CCodeDownload::RegisterWx86Dll",
  1048. "this=%#x, %.80q",
  1049. this, lpSrcFileName
  1050. ));
  1051. HMODULE hModWx86;
  1052. HMODULE hMod;
  1053. FARPROC lpfnDllRegisterServerX86;
  1054. FARPROC lpfnDllRegisterServer;
  1055. HRESULT hr = S_OK;
  1056. LPWSTR lpwSrcFileName;
  1057. typedef HMODULE (*pfnLoadFn)(LPCWSTR name, DWORD dwFlags);
  1058. typedef PVOID (*pfnThunkFn)(PVOID pvAddress, PVOID pvCbDispatch, BOOLEAN fNativeToX86);
  1059. typedef BOOL (*pfnUnloadFn)(HMODULE hMod);
  1060. pfnLoadFn pfnLoad;
  1061. pfnThunkFn pfnThunk;
  1062. pfnUnloadFn pfnUnload;
  1063. if ((hr = IsRegisterableDLL(lpSrcFileName)) != S_OK) {
  1064. // no DllRegisterServer entry point, don't LoadLibarary it.
  1065. CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_MISSING_DLLREGISTERSERVER, lpSrcFileName);
  1066. goto Exit;
  1067. }
  1068. // Load Wx86 and get pointers to some useful exports
  1069. hModWx86 = LoadLibrary("wx86.dll");
  1070. if (!hModWx86) {
  1071. hr = HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH);
  1072. CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_INCOMPATIBLE_BINARY, lpSrcFileName);
  1073. goto Exit;
  1074. }
  1075. pfnLoad = (pfnLoadFn)GetProcAddress(hModWx86, "Wx86LoadX86Dll");
  1076. pfnThunk = (pfnThunkFn)GetProcAddress(hModWx86, "Wx86ThunkProc");
  1077. pfnUnload = (pfnUnloadFn)GetProcAddress(hModWx86, "Wx86FreeX86Dll");
  1078. if (!pfnLoad || !pfnThunk || !pfnUnload) {
  1079. hr = HRESULT_FROM_WIN32(GetLastError());
  1080. goto Exit1;
  1081. }
  1082. CodeDownloadDebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_DLL_REGISTERED, lpSrcFileName);
  1083. // assuming oleinitialze
  1084. if (FAILED((hr=::Ansi2Unicode(lpSrcFileName, &lpwSrcFileName)))) {
  1085. goto Exit1;
  1086. }
  1087. if ((hMod = (*pfnLoad)(lpwSrcFileName, LOAD_WITH_ALTERED_SEARCH_PATH)) == NULL) {
  1088. hr = HRESULT_FROM_WIN32(GetLastError());
  1089. goto Exit1;
  1090. }
  1091. delete lpwSrcFileName;
  1092. if ( (lpfnDllRegisterServerX86 = GetProcAddress( hMod,
  1093. "DllRegisterServer")) == NULL) {
  1094. hr = HRESULT_FROM_WIN32(GetLastError());
  1095. }
  1096. if (lpfnDllRegisterServerX86) {
  1097. //
  1098. // lpfnDllRegisterServerX86 is a pointer to an x86 function which
  1099. // takes no parameters. Create a native-to-x86 thunk for it.
  1100. //
  1101. lpfnDllRegisterServer = (FARPROC)(*pfnThunk)(lpfnDllRegisterServerX86,
  1102. (PVOID)0,
  1103. TRUE
  1104. );
  1105. if (lpfnDllRegisterServer == (FARPROC)-1) {
  1106. //
  1107. // Something went wrong. Possibly out-of-memory.
  1108. //
  1109. hr = E_UNEXPECTED;
  1110. goto Exit1;
  1111. }
  1112. hr = (*lpfnDllRegisterServer)();
  1113. }
  1114. (*pfnUnload)(hMod);
  1115. Exit1:
  1116. FreeLibrary(hModWx86);
  1117. Exit:
  1118. DEBUG_LEAVE(hr);
  1119. return hr;
  1120. }
  1121. #endif //WX86
  1122. // ---------------------------------------------------------------------------
  1123. // %%Function: CCodeDownload::DelayRegisterOCX
  1124. // Self-register's the OCX.
  1125. HRESULT
  1126. CCodeDownload::DelayRegisterOCX(
  1127. LPCSTR pszSrcFileName,
  1128. FILEXTN extn)
  1129. {
  1130. DEBUG_ENTER((DBG_DOWNLOAD,
  1131. Hresult,
  1132. "CCodeDownload::DelayRegisterOCX",
  1133. "this=%#x, %.80q, %#x",
  1134. this, pszSrcFileName, extn
  1135. ));
  1136. HRESULT hr = S_OK;
  1137. HKEY hKeyRunOnce = NULL;
  1138. int line = 0;
  1139. char szPath[MAX_PATH];
  1140. char lpszCmdLine[2*MAX_PATH];
  1141. char lpSrcFileName[MAX_PATH];
  1142. char szTgtFileName[MAX_PATH];
  1143. DWORD dwTmp;
  1144. const char *szICDRUNONCE = "ICDRegOCX%d";
  1145. const char *szICDRUNDLL="rundll32.exe advpack.dll,RegisterOCX %s";
  1146. // See comment in UpdateFileList to see why this is necessary
  1147. // The reason we do this here is the same, except we need to use
  1148. // the ANSI code page for regsvr32 this time.
  1149. //pszSrcFileName restricted to MAX_PATH in context of use (See CSetup::DoSetup)
  1150. if (g_bRunOnWin95) {
  1151. OemToCharBuff(pszSrcFileName, lpSrcFileName, sizeof(lpSrcFileName) / sizeof(lpSrcFileName[0]));
  1152. lstrcpy(szTgtFileName, lpSrcFileName);
  1153. }
  1154. else {
  1155. lstrcpy(szTgtFileName, pszSrcFileName);
  1156. }
  1157. if ( RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, (ULONG)0, NULL,
  1158. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyRunOnce, &dwTmp ) != ERROR_SUCCESS ) {
  1159. hr = HRESULT_FROM_WIN32(GetLastError());
  1160. goto Exit;
  1161. }
  1162. // Check if key already exists -- if so, go with next number.
  1163. //
  1164. for (;;)
  1165. {
  1166. wsprintf( szPath, szICDRUNONCE, line++ );
  1167. if ( RegQueryValueEx( hKeyRunOnce, szPath, 0, NULL, NULL, &dwTmp )
  1168. != ERROR_SUCCESS )
  1169. {
  1170. break;
  1171. }
  1172. }
  1173. #ifdef WX86
  1174. if (GetMultiArch()->GetRequiredArch() == PROCESSOR_ARCHITECTURE_INTEL) {
  1175. char szSysDirX86[MAX_PATH];
  1176. // An x86 control is downloading. Tell GetSystemDirectory
  1177. // to return the sys32x86 dir instead of system32
  1178. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = TRUE;
  1179. GetSystemDirectory(szSysDirX86, MAX_PATH);
  1180. // Run the RISC rundll32.exe but specify the fully-qualified name of
  1181. // the x86 advpack.dll installed in %windir%\sys32x86. RISC rundll32
  1182. // is Wx86-aware and will load and run the x86 DLL.
  1183. wnsprintf( lpszCmdLine, sizeof(lpszCmdLine)-1, "rundll32.exe %s\advpack.dll,RegisterOCX %s", szSysDirX86, szTgtFileName );
  1184. } else {
  1185. wnsprintf( lpszCmdLine, sizeof(lpszCmdLine)-1, szICDRUNDLL, szTgtFileName );
  1186. }
  1187. #else
  1188. wnsprintf( lpszCmdLine, sizeof(lpszCmdLine)-1, szICDRUNDLL, szTgtFileName );
  1189. #endif
  1190. if ( RegSetValueEx( hKeyRunOnce, szPath, 0, REG_SZ, (CONST UCHAR *) lpszCmdLine, lstrlen(lpszCmdLine)+1 )
  1191. != ERROR_SUCCESS ) {
  1192. hr = HRESULT_FROM_WIN32(GetLastError());
  1193. goto Exit;
  1194. }
  1195. Exit:
  1196. if ( hKeyRunOnce != NULL ) {
  1197. RegCloseKey( hKeyRunOnce );
  1198. }
  1199. DEBUG_LEAVE(hr);
  1200. return hr;
  1201. }
  1202. // ---------------------------------------------------------------------------
  1203. // %%Function: CCodeDownload::InstallOCX
  1204. // Self-register's the OCX.
  1205. HRESULT
  1206. CCodeDownload::InstallOCX(
  1207. LPCSTR lpSrcFileName,
  1208. FILEXTN extn,
  1209. BOOL bLocalServer)
  1210. {
  1211. DEBUG_ENTER((DBG_DOWNLOAD,
  1212. Hresult,
  1213. "CCodeDownload::InstallOCX",
  1214. "this=%#x, %.80q, %#x, %B",
  1215. this, lpSrcFileName, extn, bLocalServer
  1216. ));
  1217. HMODULE hMod;
  1218. FARPROC lpfnDllRegisterServer;
  1219. HRESULT hr = S_OK;
  1220. const static char *szREGSVR = " /RegServer";
  1221. char szCmdLine[MAX_PATH+sizeof(szREGSVR)];
  1222. STARTUPINFO si;
  1223. DWORD dwResult;
  1224. DWORD dwMachineType = 0;
  1225. switch (extn) {
  1226. case FILEXTN_CAB:
  1227. case FILEXTN_INF:
  1228. // can't install cab or INF
  1229. hr = E_INVALIDARG;
  1230. break;
  1231. case FILEXTN_EXE:
  1232. //lpSrcFileName constrained to MAX_PATH in context of use (See CSetup::DoSetup)
  1233. lstrcpy(szCmdLine, lpSrcFileName);
  1234. if (bLocalServer)
  1235. lstrcat(szCmdLine, szREGSVR);
  1236. memset(&si, 0, sizeof(si));
  1237. si.cb = sizeof(si);
  1238. if (!CreateProcess(NULL,
  1239. szCmdLine,
  1240. 0, // security
  1241. 0, // security
  1242. FALSE, // Don't inherit my handles!
  1243. 0, // Creation flags
  1244. NULL, // env = inherit
  1245. NULL, // cur dir. = inherit
  1246. &si, // no startup info
  1247. &m_pi))
  1248. {
  1249. hr = HRESULT_FROM_WIN32(GetLastError());
  1250. } else {
  1251. hr = SetWaitingForEXE(lpSrcFileName, !bLocalServer);
  1252. }
  1253. goto Exit;
  1254. case FILEXTN_OCX:
  1255. case FILEXTN_DLL:
  1256. case FILEXTN_NONE:
  1257. case FILEXTN_UNKNOWN:
  1258. // sniff machine type of PE
  1259. hr = IsCompatibleFile(lpSrcFileName, &dwMachineType);
  1260. if (hr == HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH)) {
  1261. // if its of worng CPU flavor fail and clean up the OCX
  1262. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_INCOMPATIBLE_BINARY, lpSrcFileName);
  1263. break;
  1264. }
  1265. if (hr == S_FALSE) {
  1266. // not a PE file, no need to call LoadLibrary
  1267. // just copy and install the file
  1268. break;
  1269. }
  1270. #ifdef WX86
  1271. if (g_fWx86Present && dwMachineType == IMAGE_FILE_MACHINE_I386)
  1272. hr = RegisterWx86Dll(lpSrcFileName);
  1273. else
  1274. #endif
  1275. hr = RegisterPEDll(lpSrcFileName);
  1276. }
  1277. Exit:
  1278. DEBUG_LEAVE(hr);
  1279. return hr;
  1280. }
  1281. // ---------------------------------------------------------------------------
  1282. // %%Function: CCodeDownload::HandleUnSafeAbort
  1283. HRESULT
  1284. CCodeDownload::HandleUnSafeAbort()
  1285. {
  1286. DEBUG_ENTER((DBG_DOWNLOAD,
  1287. Hresult,
  1288. "CCodeDownload::HandleUnSafeAbort",
  1289. "this=%#x",
  1290. this
  1291. ));
  1292. HRESULT hr = S_FALSE;
  1293. ICodeInstall* pCodeInstall = GetICodeInstall();
  1294. if(WaitingForEXE()) { // Did the setup start a self-registering EXE?
  1295. // we are waiting for an EXE to complete self-registering
  1296. // notify client of condition and maybe it wants to
  1297. // ask the user if (s)he wants to wait for the EXE or abort
  1298. // download
  1299. // we never kill the EXE though we just ignore it
  1300. if (pCodeInstall) {
  1301. WCHAR szBuf[MAX_PATH];
  1302. szBuf[0] = '\0';
  1303. if (m_szWaitForEXE) {
  1304. MultiByteToWideChar(CP_ACP, 0, m_szWaitForEXE, -1, szBuf, MAX_PATH);
  1305. }
  1306. hr = pCodeInstall->OnCodeInstallProblem(
  1307. CIP_EXE_SELF_REGISTERATION_TIMEOUT,
  1308. NULL, szBuf, 0);
  1309. } else {
  1310. hr = S_FALSE; // assume skip EXE and proceed
  1311. }
  1312. if (hr == S_OK) // continue to wait?
  1313. {
  1314. DEBUG_LEAVE(S_FALSE);
  1315. return S_FALSE; // yes
  1316. }
  1317. // if hr == S_FALSE/E_ABORT ignore this EXE and try to proceed with
  1318. // rest of installation
  1319. if (m_pi.hProcess != INVALID_HANDLE_VALUE) {
  1320. CloseHandle(m_pi.hProcess);
  1321. m_pi.hProcess = INVALID_HANDLE_VALUE;
  1322. }
  1323. if (m_pi.hThread != INVALID_HANDLE_VALUE) {
  1324. CloseHandle(m_pi.hThread);
  1325. m_pi.hThread = INVALID_HANDLE_VALUE;
  1326. }
  1327. SetNotWaitingForEXE();
  1328. m_hr = E_ABORT;
  1329. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP, this, 0);
  1330. if (pPkt) {
  1331. hr = pPkt->Post();
  1332. } else {
  1333. hr = E_OUTOFMEMORY;
  1334. }
  1335. DEBUG_LEAVE(hr);
  1336. return hr;
  1337. }
  1338. if (pCodeInstall) {
  1339. hr = pCodeInstall->OnCodeInstallProblem(CIP_UNSAFE_TO_ABORT,
  1340. NULL, NULL, 0);
  1341. } else {
  1342. hr = E_ABORT;
  1343. }
  1344. if (hr == S_OK) {
  1345. hr = S_FALSE;
  1346. } else {
  1347. SetUserCancelled();
  1348. hr = E_ABORT;
  1349. }
  1350. DEBUG_LEAVE(hr);
  1351. return hr;
  1352. }
  1353. // ---------------------------------------------------------------------------
  1354. // %%Function: CCodeDownload::SelfRegEXETimeout
  1355. HRESULT
  1356. CCodeDownload::SelfRegEXETimeout()
  1357. {
  1358. DEBUG_ENTER((DBG_DOWNLOAD,
  1359. Hresult,
  1360. "CCodeDownload::SelfRegEXETimeout",
  1361. "this=%#x",
  1362. this
  1363. ));
  1364. HRESULT hr = S_OK;
  1365. if (!WaitingForEXE())
  1366. {
  1367. DEBUG_LEAVE(hr);
  1368. return S_FALSE;
  1369. }
  1370. Assert(m_pi.hProcess != INVALID_HANDLE_VALUE);
  1371. DWORD dwResult = WaitForSingleObject(m_pi.hProcess, 0);
  1372. if (dwResult != WAIT_OBJECT_0) {
  1373. // the EXE has not yet completed.
  1374. // just wait for it till we get it or client calls
  1375. // IClientBinding::Abort()
  1376. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_WAIT_FOR_EXE,
  1377. this,0);
  1378. if (pPkt) {
  1379. hr = pPkt->Post();
  1380. } else {
  1381. hr = E_OUTOFMEMORY;
  1382. }
  1383. DEBUG_LEAVE(hr);
  1384. return hr;
  1385. }
  1386. if (!GetExitCodeProcess(m_pi.hProcess, &dwResult))
  1387. dwResult = GetLastError();
  1388. if (m_pi.hProcess != INVALID_HANDLE_VALUE) {
  1389. CloseHandle(m_pi.hProcess);
  1390. m_pi.hProcess = INVALID_HANDLE_VALUE;
  1391. }
  1392. if (m_pi.hThread != INVALID_HANDLE_VALUE) {
  1393. CloseHandle(m_pi.hThread);
  1394. m_pi.hThread = INVALID_HANDLE_VALUE;
  1395. }
  1396. SetNotWaitingForEXE();
  1397. if (DeleteEXEWhenDone()) {
  1398. DeleteFile(m_szWaitForEXE);
  1399. ResetDeleteEXEWhenDone();
  1400. }
  1401. hr = HRESULT_FROM_WIN32(dwResult);
  1402. if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED) ) {
  1403. SetRebootRequired();
  1404. hr = S_OK;
  1405. }
  1406. m_hr = hr;
  1407. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP, this, 0);
  1408. if (pPkt) {
  1409. hr = pPkt->Post();
  1410. } else {
  1411. hr = E_OUTOFMEMORY;
  1412. }
  1413. Assert(SUCCEEDED(hr));
  1414. DEBUG_LEAVE(hr);
  1415. return hr;
  1416. }
  1417. // ---------------------------------------------------------------------------
  1418. // %%Function: CCodeDownload::SetManifest()
  1419. // ---------------------------------------------------------------------------
  1420. HRESULT
  1421. CCodeDownload::SetManifest(FILEXTN extn, LPCSTR szManifest)
  1422. {
  1423. DEBUG_ENTER((DBG_DOWNLOAD,
  1424. Hresult,
  1425. "CCodeDownload::SetManifest",
  1426. "this=%#x, %#x, %.80q",
  1427. this, extn, szManifest
  1428. ));
  1429. HRESULT hr = S_OK;
  1430. LPSTR szFile = new char [lstrlen(szManifest)+1];
  1431. if (!szFile) {
  1432. hr = E_OUTOFMEMORY;
  1433. goto Exit;
  1434. }
  1435. lstrcpy(szFile, szManifest);
  1436. if (extn == FILEXTN_INF) {
  1437. SAFEDELETE(m_szInf);
  1438. m_szInf = szFile;
  1439. } else {
  1440. SAFEDELETE(m_szOSD);
  1441. m_szOSD = szFile;
  1442. }
  1443. Exit:
  1444. DEBUG_LEAVE(hr);
  1445. return hr;
  1446. }
  1447. // ---------------------------------------------------------------------------
  1448. // %%Function: CCodeDownload::VersionFromManifest
  1449. // ---------------------------------------------------------------------------
  1450. BOOL
  1451. CCodeDownload::VersionFromManifest(LPSTR szVersionInManifest, int iLen)
  1452. {
  1453. DEBUG_ENTER((DBG_DOWNLOAD,
  1454. Hresult,
  1455. "CCodeDownload::VersionFromManifest",
  1456. "this=%#x, %.80q",
  1457. this, szVersionInManifest
  1458. ));
  1459. if (m_szVersionInManifest) {
  1460. StrNCpy(szVersionInManifest, m_szVersionInManifest, iLen);
  1461. DEBUG_LEAVE(TRUE);
  1462. return TRUE;
  1463. }
  1464. DEBUG_LEAVE(FALSE);
  1465. return FALSE;
  1466. }
  1467. // ---------------------------------------------------------------------------
  1468. // %%Function: CCodeDownload::ProcessJavaManifest
  1469. // ---------------------------------------------------------------------------
  1470. HRESULT
  1471. CCodeDownload::ProcessJavaManifest(IXMLElement *pJava, const char *szOSD, char *szOSDBaseName, CDownload *pdl)
  1472. {
  1473. DEBUG_ENTER((DBG_DOWNLOAD,
  1474. Hresult,
  1475. "CCodeDownload::ProcessJavaManifest",
  1476. "this=%#x, %#x, %.80q, %.80q, %#x",
  1477. this, pJava, szOSD, szOSDBaseName, pdl
  1478. ));
  1479. HRESULT hr = S_OK;
  1480. IXMLElement *pPackage = NULL, *pElemTmp = NULL, *pConfig = NULL;
  1481. CDownload *pdlCur = NULL;
  1482. LPWSTR szPackageName = NULL;
  1483. char szPackageVersion[MAX_PATH];
  1484. DWORD dwVersionMS = 0, dwVersionLS = 0, dwJavaFlags = 0;
  1485. int nLastPackage, nLastConfig;
  1486. CCodeBaseHold *pcbh = NULL;
  1487. char szPackageURLA[INTERNET_MAX_URL_LENGTH];
  1488. char *pBaseFileName = NULL;
  1489. LPWSTR pszNameSpace = NULL;
  1490. CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL;
  1491. BOOL bDestroyPCBHList = FALSE;
  1492. int iCount = 0;
  1493. if (!pdl->HasJavaPermissions()) {
  1494. if (IsSilentMode())
  1495. {
  1496. SetBitsInCache();
  1497. } else {
  1498. hr = TRUST_E_FAIL;
  1499. goto Exit;
  1500. }
  1501. }
  1502. hr = GetTextContent(pJava, DU_TAG_NAMESPACE, &pszNameSpace);
  1503. if (FAILED(hr))
  1504. goto Exit;
  1505. // while more packages
  1506. nLastPackage = -1;
  1507. while( (GetNextChildTag(pJava, DU_TAG_PACKAGE, &pPackage, nLastPackage)) == S_OK) {
  1508. SAFEDELETE(szPackageName);
  1509. // process package
  1510. hr = DupAttribute(pPackage, DU_ATTRIB_NAME, &szPackageName);
  1511. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_JAVAPACKAGE_SYNTAX);
  1512. if (GetAttributeA(pPackage, DU_ATTRIB_VERSION,
  1513. szPackageVersion, MAX_PATH) == S_OK) {
  1514. hr = GetVersionFromString(szPackageVersion, &dwVersionMS, &dwVersionLS);
  1515. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_JAVAPACKAGE_SYNTAX);
  1516. } else {
  1517. hr = E_INVALIDARG;
  1518. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_JAVAPACKAGE_SYNTAX);
  1519. }
  1520. if (GetFirstChildTag(pPackage, DU_TAG_SYSTEM, &pElemTmp) == S_OK) {
  1521. m_dwSystemComponent = TRUE;
  1522. SAFERELEASE(pElemTmp);
  1523. }
  1524. // check if package of right version is already locally installed
  1525. // if so go to next package
  1526. hr = IsPackageLocallyInstalled(szPackageName, pszNameSpace, dwVersionMS, dwVersionLS);
  1527. if (FAILED(hr))
  1528. goto Exit;
  1529. if (hr == S_OK) {
  1530. // OK, so this package that is reqd by this dist unit
  1531. // is already present on machine
  1532. // we still need to create a NOSETUP JavaSetup obj just so
  1533. // it gets marked as belonging to/used by this dist unit.
  1534. // for a NOSETUP CJavaSetup it doesn't matter which pdl it gets
  1535. // added on to.
  1536. hr = pdl->AddJavaSetup(szPackageName, pszNameSpace, pPackage, dwVersionMS, dwVersionLS, CJS_FLAG_NOSETUP);
  1537. if (FAILED(hr))
  1538. goto Exit;
  1539. goto nextPackage;
  1540. }
  1541. hr = S_OK; // reset
  1542. // else, make a CJavaSetup for each package that needs to be installed
  1543. // also make sure that the CABs in those packages are downloaded
  1544. nLastConfig = -1;
  1545. // OR all NEEDSTRUSTEDSOURCE & SYSTEM flags from all CONFIG's since there may be
  1546. // multiple CODEBASE's.
  1547. dwJavaFlags = CJS_FLAG_INIT;
  1548. if (m_dwSystemComponent) {
  1549. dwJavaFlags |= CJS_FLAG_SYSTEM;
  1550. }
  1551. if (GetFirstChildTag(pPackage, DU_TAG_NEEDSTRUSTEDSOURCE, &pElemTmp) == S_OK) {
  1552. dwJavaFlags |= CJS_FLAG_NEEDSTRUSTEDSOURCE;
  1553. SAFERELEASE(pElemTmp);
  1554. }
  1555. // If no CODEBASE specified in CONFIG, add Setup of Java package to this download.
  1556. pdlCur = pdl;
  1557. while (GetNextChildTag(pPackage, DU_TAG_CONFIG, &pConfig, nLastConfig) == S_OK) {
  1558. // This is destroyed by destructor of DoDownload called
  1559. if (bDestroyPCBHList) {
  1560. DestroyPCBHList(pcbhList);
  1561. SAFEDELETE(pcbhList);
  1562. }
  1563. pcbhList = new CList<CCodeBaseHold *, CCodeBaseHold *>;
  1564. if (pcbhList == NULL) {
  1565. hr = E_OUTOFMEMORY;
  1566. goto Exit;
  1567. }
  1568. bDestroyPCBHList = TRUE;
  1569. pcbhList->RemoveAll();
  1570. if (ProcessImplementation(pConfig, pcbhList, m_lcid
  1571. #ifdef WX86
  1572. , GetMultiArch()
  1573. #endif
  1574. ) == S_OK) {
  1575. iCount = pcbhList->GetCount();
  1576. if (iCount) {
  1577. pcbh = pcbhList->GetHead();
  1578. pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED;
  1579. }
  1580. else {
  1581. pcbh = NULL;
  1582. }
  1583. if (pcbh && pcbh->wszCodeBase) {
  1584. WideCharToMultiByte(CP_ACP, 0, pcbh->wszCodeBase, -1,
  1585. szPackageURLA, sizeof(szPackageURLA),NULL, NULL);
  1586. FILEXTN extn = ::GetExtnAndBaseFileName(szPackageURLA, &pBaseFileName);
  1587. if (extn != FILEXTN_CAB) {
  1588. hr = E_INVALIDARG;
  1589. goto Exit;
  1590. }
  1591. if (pcbh->bHREF) {
  1592. // CODEBASE HREF="..." download CAB with java package
  1593. hr = FindCABInDownloadList(pcbh->wszCodeBase, pdl, &pdlCur);
  1594. if (FAILED(hr))
  1595. goto Exit;
  1596. if (!pdlCur) {
  1597. // did not find CAB
  1598. // fresh CAB needs to get pulled down.
  1599. pdlCur = new CDownload(pcbh->wszCodeBase, extn, &hr);
  1600. if (!pdlCur) {
  1601. hr = E_OUTOFMEMORY;
  1602. }
  1603. if (FAILED(hr)) {
  1604. SAFEDELETE(pdlCur);
  1605. goto Exit;
  1606. }
  1607. AddDownloadToList(pdlCur);
  1608. {
  1609. BOOL bSetOnStack = SetOnStack();
  1610. bDestroyPCBHList = FALSE;
  1611. hr = pdlCur->DoDownload(&m_pmkContext,
  1612. (BINDF_ASYNCHRONOUS|
  1613. BINDF_ASYNCSTORAGE),
  1614. pcbhList);
  1615. if (bSetOnStack)
  1616. ResetOnStack();
  1617. }
  1618. }
  1619. }
  1620. if (FAILED(hr)) {
  1621. goto Exit;
  1622. }
  1623. } else {
  1624. // found a valid config but no CODEBASE
  1625. // assume that the pkg is in 'thiscab'
  1626. // goto add package
  1627. }
  1628. goto addPackage;
  1629. } // Got CONFIG tag successfully
  1630. SAFERELEASE(pConfig);
  1631. } // <CONFIG> tag loop
  1632. if (SUCCEEDED(hr)) {
  1633. hr = HRESULT_FROM_WIN32(ERROR_APP_WRONG_OS);
  1634. }
  1635. goto nextPackage;
  1636. addPackage:
  1637. hr = pdlCur->AddJavaSetup(szPackageName, pszNameSpace, pPackage, dwVersionMS, dwVersionLS, dwJavaFlags);
  1638. nextPackage:
  1639. SAFERELEASE(pPackage);
  1640. SAFERELEASE(pConfig);
  1641. if (FAILED(hr))
  1642. break;
  1643. if (hr == S_FALSE)
  1644. hr = S_OK; // reset
  1645. } // <PACKAGE> tag loop
  1646. Exit:
  1647. SAFERELEASE(pConfig);
  1648. SAFERELEASE(pPackage);
  1649. SAFEDELETE(szPackageName);
  1650. SAFEDELETE(pszNameSpace);
  1651. DEBUG_LEAVE(hr);
  1652. return hr;
  1653. }
  1654. // ---------------------------------------------------------------------------
  1655. // %%Function: CCodeDownload::ProcessDependency
  1656. // Processes <dependency> tag and spins off any dependency code downloads
  1657. // as appropriate.
  1658. // ---------------------------------------------------------------------------
  1659. HRESULT CCodeDownload::ProcessDependency(CDownload *pdl, IXMLElement *pDepend)
  1660. {
  1661. DEBUG_ENTER((DBG_DOWNLOAD,
  1662. Hresult,
  1663. "CCodeDownload::ProcessDependency",
  1664. "this=%#x, %#x, %#x",
  1665. this, pdl, pDepend
  1666. ));
  1667. HRESULT hr = S_OK;
  1668. int nLast2, nLast3;
  1669. BOOL fAssert = FALSE, fInstall = FALSE;
  1670. IXMLElement *pSoftDist2 = NULL, *pLang = NULL, *pConfig = NULL;
  1671. LPWSTR szDistUnit = NULL;
  1672. LPWSTR pwszURL = NULL;
  1673. LPSTR szLanguages = NULL;
  1674. LPSTR pBaseFileName = NULL;
  1675. WCHAR szCDLURL[2*INTERNET_MAX_URL_LENGTH];
  1676. WCHAR wszURLBuf[2*INTERNET_MAX_URL_LENGTH];
  1677. WCHAR szResult[INTERNET_MAX_URL_LENGTH];
  1678. DWORD dwSize = 0;
  1679. DWORD dwVersionMS = 0, dwVersionLS = 0, dwStyle;
  1680. CDownload *pdlCur = NULL;
  1681. CLSID inclsid = CLSID_NULL;
  1682. CCodeBaseHold *pcbh = NULL;
  1683. CLocalComponentInfo lci;
  1684. int i, iCount = 0, iLen = 0;
  1685. LISTPOSITION lpos = 0;
  1686. CCodeBaseHold *pcbhCur = NULL;
  1687. LPWSTR pwszStr = NULL;
  1688. CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL;
  1689. BOOL bDestroyPCBHList = FALSE;
  1690. LPWSTR pwszVersion = NULL;
  1691. union {
  1692. char szAction[MAX_PATH];
  1693. char szVersion[MAX_PATH];
  1694. char szStyle[MAX_PATH];
  1695. char szPackageURLA[INTERNET_MAX_URL_LENGTH];
  1696. };
  1697. if (SUCCEEDED(GetAttributeA(pDepend, DU_ATTRIB_ACTION, szAction, MAX_PATH))) {
  1698. if (lstrcmpi(szAction, "ASSERT") == 0)
  1699. fAssert = TRUE;
  1700. else if (lstrcmpi(szAction, "INSTALL") == 0)
  1701. fInstall = TRUE;
  1702. else
  1703. goto Exit;
  1704. } else
  1705. fAssert = TRUE;
  1706. nLast2 = -1;
  1707. while (GetNextChildTag(pDepend, DU_TAG_SOFTDIST, &pSoftDist2, nLast2) == S_OK) {
  1708. if (FAILED(hr))
  1709. break;
  1710. // get NAME attribute
  1711. hr = DupAttribute(pSoftDist2, DU_ATTRIB_NAME, &szDistUnit);
  1712. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DEPENDENCY_SYNTAX);
  1713. // get VERSION attribute
  1714. hr = GetAttributeA(pSoftDist2, DU_ATTRIB_VERSION, szVersion, MAX_PATH);
  1715. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DEPENDENCY_SYNTAX);
  1716. // convert VERSION string
  1717. hr = GetVersionFromString(szVersion, &dwVersionMS, &dwVersionLS);
  1718. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DEPENDENCY_SYNTAX);
  1719. // remember the version string in uni
  1720. hr = Ansi2Unicode(szVersion, &pwszVersion);
  1721. if (FAILED(hr))
  1722. goto Exit;
  1723. // get STYLE attribute
  1724. if (SUCCEEDED(GetAttributeA(pSoftDist2, DU_ATTRIB_STYLE, szStyle, MAX_PATH))) {
  1725. (void) GetStyleFromString(szStyle, &dwStyle);
  1726. } else
  1727. dwStyle = STYLE_MSICD;
  1728. // Check if distribution unit is currently installed
  1729. // NOTE: This assumes MSICD
  1730. inclsid = CLSID_NULL;
  1731. CLSIDFromString((LPOLESTR)szDistUnit, &inclsid);
  1732. if ((hr = IsControlLocallyInstalled(NULL,
  1733. (LPCLSID)&inclsid, szDistUnit,
  1734. dwVersionMS, dwVersionLS, &lci, NULL)) != S_FALSE) {
  1735. // add distribution unit as a dependency
  1736. AddDistUnitList(szDistUnit);
  1737. goto nextDepend;
  1738. }
  1739. // if Action=ASSERT and we don't have distribution unit, then skip this <softdist>.
  1740. if (fAssert) {
  1741. hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  1742. goto Exit;
  1743. }
  1744. // minimal check for circular dependency
  1745. if (StrCmpIW(szDistUnit, m_szDistUnit)==0) {
  1746. hr = HRESULT_FROM_WIN32(ERROR_CIRCULAR_DEPENDENCY);
  1747. goto Exit;
  1748. }
  1749. // process CONFIG tags
  1750. nLast3 = -1;
  1751. pcbh = NULL;
  1752. while (GetNextChildTag(pSoftDist2, DU_TAG_CONFIG, &pConfig, nLast3) == S_OK) {
  1753. if (bDestroyPCBHList) {
  1754. DestroyPCBHList(pcbhList);
  1755. SAFEDELETE(pcbhList);
  1756. }
  1757. pcbhList = new CList<CCodeBaseHold *, CCodeBaseHold *>;
  1758. if (pcbhList == NULL) {
  1759. hr = E_OUTOFMEMORY;
  1760. goto Exit;
  1761. }
  1762. bDestroyPCBHList = TRUE;
  1763. pcbhList->RemoveAll();
  1764. pcbh = NULL;
  1765. hr = ProcessImplementation(pConfig, pcbhList, m_lcid
  1766. #ifdef WX86
  1767. , GetMultiArch()
  1768. #endif
  1769. );
  1770. if (SUCCEEDED(hr)) {
  1771. iCount = pcbhList->GetCount();
  1772. if (iCount) {
  1773. pcbh = pcbhList->GetHead();
  1774. pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED;
  1775. }
  1776. else {
  1777. pcbh = NULL;
  1778. }
  1779. }
  1780. SAFERELEASE(pConfig);
  1781. if (hr == S_OK) {
  1782. szPackageURLA[0] = '\0';
  1783. //BUGBUG: If no CODEBASE how do we know extension? Assuming it is CAB
  1784. FILEXTN extn = FILEXTN_CAB;
  1785. if (pcbh && pcbh->wszCodeBase && pcbh->bHREF) {
  1786. WideCharToMultiByte(CP_ACP, 0, pcbh->wszCodeBase, -1, szPackageURLA,
  1787. INTERNET_MAX_URL_LENGTH,NULL, NULL);
  1788. extn = ::GetExtnAndBaseFileName(szPackageURLA, &pBaseFileName);
  1789. }
  1790. // "cdl:[clsid=xxx|codebase=xxx|mimetype=xxx|extension=xxx];"
  1791. // we use: "cdl:distunit=xxxx[|codebase=xxxx]"
  1792. // BUGBUG: We could mess up CDLProtocol if any of these embedded fields are
  1793. // illformatted (contains '=' or '\\' or '//').
  1794. // cdl: protocol treats clsid as DistUnit name if not a valid CLSID.
  1795. StrCpyW(szCDLURL, L"cdl:distunit=");
  1796. StrCatBuffW(szCDLURL, szDistUnit, 2*INTERNET_MAX_URL_LENGTH);
  1797. StrCatBuffW(szCDLURL, L";version=", 2*INTERNET_MAX_URL_LENGTH);
  1798. StrCatBuffW(szCDLURL, pwszVersion, 2*INTERNET_MAX_URL_LENGTH);
  1799. if (szPackageURLA[0]) {
  1800. StrCatBuffW(szCDLURL, L";codebase=", 2*INTERNET_MAX_URL_LENGTH);
  1801. if (SUCCEEDED(GetContextMoniker()->GetDisplayName(NULL, NULL, &pwszURL))) {
  1802. dwSize = INTERNET_MAX_URL_LENGTH;
  1803. if(FAILED(UrlCombineW(pwszURL, pcbh->wszCodeBase, szResult, &dwSize, 0))) {
  1804. hr = E_UNEXPECTED;
  1805. goto Exit;
  1806. }
  1807. StrCatBuffW(szCDLURL, szResult, 2*INTERNET_MAX_URL_LENGTH);
  1808. SAFEDELETE(pwszURL);
  1809. }
  1810. else {
  1811. // A context moniker should always exist if we
  1812. // are looking at a dependency.
  1813. hr = E_UNEXPECTED;
  1814. goto Exit;
  1815. }
  1816. }
  1817. // Iterate over all codebases in the list, and covert them
  1818. // to CDL: protocols instead of HTTP:.
  1819. lpos = pcbhList->GetHeadPosition();
  1820. while (lpos) {
  1821. pcbhCur = pcbhList->GetNext(lpos);
  1822. if (pcbhCur != NULL) {
  1823. StrCpyW(wszURLBuf, L"cdl:distunit=");
  1824. StrCatBuffW(wszURLBuf, szDistUnit, 2*INTERNET_MAX_URL_LENGTH);
  1825. StrCatBuffW(wszURLBuf, L";version=", 2*INTERNET_MAX_URL_LENGTH);
  1826. StrCatBuffW(wszURLBuf, pwszVersion, 2*INTERNET_MAX_URL_LENGTH);
  1827. StrCatBuffW(wszURLBuf, L";codebase=", 2*INTERNET_MAX_URL_LENGTH);
  1828. // Combine the context moniker's URL with the
  1829. // codebase supplied to handle relative dependency
  1830. // URLs. If the dependency URL is absolute,
  1831. // UrlCombineW will just return the absolute
  1832. // dependency URL.
  1833. if (SUCCEEDED(GetContextMoniker()->GetDisplayName(NULL, NULL, &pwszURL))) {
  1834. dwSize = INTERNET_MAX_URL_LENGTH;
  1835. if (FAILED(UrlCombineW(pwszURL, pcbhCur->wszCodeBase, szResult, &dwSize, 0))) {
  1836. hr = E_UNEXPECTED;
  1837. goto Exit;
  1838. }
  1839. iLen = lstrlenW(szResult) + lstrlenW(wszURLBuf) + 1;
  1840. pwszStr = new WCHAR[iLen];
  1841. if (pwszStr == NULL) {
  1842. SAFEDELETE(pwszURL);
  1843. hr = E_OUTOFMEMORY;
  1844. goto Exit;
  1845. }
  1846. StrCpyW(pwszStr, wszURLBuf);
  1847. StrCatW(pwszStr, szResult);
  1848. SAFEDELETE(pcbhCur->wszCodeBase);
  1849. pcbhCur->wszCodeBase = pwszStr;
  1850. SAFEDELETE(pwszURL);
  1851. }
  1852. else {
  1853. hr = E_UNEXPECTED;
  1854. goto Exit;
  1855. }
  1856. }
  1857. }
  1858. // Because of way this is processed it should create URLMoniker, which in
  1859. // turn creates CCodeDownload and properly installs before we do our
  1860. // setup here. Thus we don't need to do anything else explicit here.
  1861. pdlCur = new CDownload(szCDLURL, extn, &hr);
  1862. if (!pdlCur) {
  1863. hr = E_OUTOFMEMORY;
  1864. }
  1865. if (FAILED(hr)) {
  1866. SAFEDELETE(pdlCur);
  1867. goto Exit;
  1868. }
  1869. AddDownloadToList(pdlCur);
  1870. hr = pdlCur->SetUsingCdlProtocol(szDistUnit);
  1871. if (FAILED(hr))
  1872. goto Exit;
  1873. {
  1874. BOOL bSetOnStack = SetOnStack();
  1875. bDestroyPCBHList = FALSE;
  1876. hr = pdlCur->DoDownload(&m_pmkContext, (BINDF_ASYNCHRONOUS|
  1877. BINDF_ASYNCSTORAGE), pcbhList);
  1878. if (bSetOnStack)
  1879. ResetOnStack();
  1880. }
  1881. // this is an indication "cdl://" is not installed.
  1882. CHECK_ERROR_EXIT((hr != E_NOINTERFACE),ID_CDLDBG_CDL_HANDLER_MISSING);
  1883. if (FAILED(hr))
  1884. goto Exit;
  1885. goto nextDepend;
  1886. }
  1887. SAFEDELETE(pcbh);
  1888. }
  1889. if (SUCCEEDED(hr))
  1890. hr = HRESULT_FROM_WIN32(ERROR_APP_WRONG_OS);
  1891. nextDepend:
  1892. SAFERELEASE(pLang);
  1893. SAFERELEASE(pSoftDist2);
  1894. SAFEDELETE(szDistUnit);
  1895. SAFEDELETE(szLanguages);
  1896. if (FAILED(hr))
  1897. break;
  1898. }
  1899. Exit:
  1900. SAFERELEASE(pLang);
  1901. SAFERELEASE(pSoftDist2);
  1902. SAFERELEASE(pConfig);
  1903. SAFEDELETE(szDistUnit);
  1904. SAFEDELETE(szLanguages);
  1905. SAFEDELETE(pwszVersion);
  1906. DEBUG_LEAVE(hr);
  1907. return hr;
  1908. }
  1909. // ---------------------------------------------------------------------------
  1910. // %%Function: CCodeDownload::ExtractInnerCAB
  1911. // We have a nested CAB, extract its contents into temporary directory (do not
  1912. // process any OSD, INF files for this). If duplicate files exist we ignore
  1913. // since this is a design error.
  1914. // ---------------------------------------------------------------------------
  1915. HRESULT CCodeDownload::ExtractInnerCAB(CDownload *pdl, LPSTR szCABFile)
  1916. {
  1917. DEBUG_ENTER((DBG_DOWNLOAD,
  1918. Hresult,
  1919. "CCodeDownload::ExtractInnerCAB",
  1920. "this=%#x, %#x, %.80q",
  1921. this, pdl, szCABFile
  1922. ));
  1923. HRESULT hr = S_OK;
  1924. SESSION *psess;
  1925. CHAR szTempCABFile[MAX_PATH];
  1926. psess = new SESSION;
  1927. if (!psess) {
  1928. hr = E_OUTOFMEMORY;
  1929. goto Exit;
  1930. }
  1931. psess->pFileList = NULL;
  1932. psess->cFiles = 0;
  1933. psess->cbCabSize = 0;
  1934. psess->flags = SESSION_FLAG_ENUMERATE | SESSION_FLAG_EXTRACT_ALL;
  1935. lstrcpy(psess->achLocation,pdl->GetSession()->achLocation);
  1936. psess->pFilesToExtract = NULL;
  1937. if (!catDirAndFile(szTempCABFile, MAX_PATH, psess->achLocation, szCABFile)) {
  1938. hr = E_UNEXPECTED;
  1939. goto Exit;
  1940. }
  1941. hr = ExtractFromCabinet(psess, szTempCABFile);
  1942. if (psess->pFileList && SUCCEEDED(hr)) {
  1943. // add extracted files to download list for cleanup purposes
  1944. PFNAME pfl = psess->pFileList;
  1945. SESSION *psessdl = pdl->GetSession();
  1946. while (pfl->pNextName) {
  1947. pfl=pfl->pNextName;
  1948. }
  1949. pfl->pNextName = psessdl->pFileList;
  1950. psessdl->pFileList = psess->pFileList;
  1951. }
  1952. Exit:
  1953. SAFEDELETE(psess);
  1954. DEBUG_LEAVE(hr);
  1955. return hr;
  1956. }
  1957. BOOL CCodeDownload::IsFileProtected(LPCSTR pFileName)
  1958. {
  1959. DEBUG_ENTER((DBG_DOWNLOAD,
  1960. Bool,
  1961. "CCodeDownload::IsFileProtected",
  1962. "this=%#x, %.100q",
  1963. this, pFileName
  1964. ));
  1965. LPWSTR wzFileName = NULL;
  1966. BOOL bIsProtectedFile = FALSE;
  1967. pfnSfcIsFileProtected pfn = NULL;
  1968. if (SUCCEEDED(::Ansi2Unicode(pFileName, &wzFileName)))
  1969. {
  1970. if (!m_hModSFC)
  1971. {
  1972. m_hModSFC = LoadLibrary("SFC.DLL");
  1973. }
  1974. if (m_hModSFC)
  1975. {
  1976. pfn = (pfnSfcIsFileProtected)GetProcAddress(m_hModSFC, "SfcIsFileProtected");
  1977. if (pfn)
  1978. {
  1979. bIsProtectedFile = (*pfn)(NULL,wzFileName);
  1980. }
  1981. }
  1982. SAFEDELETE(wzFileName);
  1983. }
  1984. DEBUG_LEAVE(bIsProtectedFile);
  1985. return bIsProtectedFile;
  1986. }
  1987. // ---------------------------------------------------------------------------
  1988. // %%Function: CCodeDownload::ProcessNativeCode
  1989. // Processes <nativecode> tag and spins off any dependency code downloads
  1990. // as appropriate.
  1991. // ---------------------------------------------------------------------------
  1992. HRESULT CCodeDownload::ProcessNativeCode(CDownload *pdl, IXMLElement *pNativeCode)
  1993. {
  1994. DEBUG_ENTER((DBG_DOWNLOAD,
  1995. Hresult,
  1996. "CCodeDownload::ProcessNativeCode",
  1997. "this=%#x, %#x, %#x",
  1998. this, pdl, pNativeCode
  1999. ));
  2000. HRESULT hr = S_OK;
  2001. int iCount;
  2002. LPWSTR szName = NULL;
  2003. union {
  2004. char szCLSID[MAX_PATH];
  2005. char szVersion[MAX_PATH];
  2006. };
  2007. char szTempFile[INTERNET_MAX_URL_LENGTH];
  2008. LPSTR szCodeBase = NULL, szNativeName = NULL, pBaseFileName = NULL, szTempDir = NULL;
  2009. CCodeBaseHold *pcbh = NULL;
  2010. int nLast2, nLast3;
  2011. DWORD dwVersionMS = 0, dwVersionLS = 0;
  2012. CLSID clsid = CLSID_NULL;
  2013. IXMLElement *pCode = NULL, *pElemTmp = NULL, *pConfig = NULL;
  2014. BOOL fSetupInf = FALSE;
  2015. CLocalComponentInfo lci;
  2016. CSetup *pSetup = NULL;
  2017. ICodeInstall* pCodeInstall = GetICodeInstall();
  2018. BOOL bSystem = FALSE;
  2019. CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList = NULL;
  2020. BOOL bDestroyPCBHList = FALSE;
  2021. if (!pdl->HasAllActiveXPermissions()) {
  2022. if (IsSilentMode())
  2023. {
  2024. SetBitsInCache();
  2025. } else {
  2026. hr = TRUST_E_FAIL;
  2027. goto Exit;
  2028. }
  2029. }
  2030. szTempDir = pdl->GetSession()->achLocation;
  2031. nLast2 = -1;
  2032. while (GetNextChildTag(pNativeCode, DU_TAG_CODE, &pCode, nLast2) == S_OK) {
  2033. SAFEDELETE(szName);
  2034. SAFEDELETE(szNativeName);
  2035. if (FAILED(hr)) break;
  2036. // get CLSID attribute
  2037. hr = GetAttributeA(pCode, DU_ATTRIB_CLSID, szCLSID, MAX_PATH);
  2038. if (SUCCEEDED(hr))
  2039. {
  2040. // convert CLSID attribute
  2041. hr = ConvertFriendlyANSItoCLSID(szCLSID, &clsid);
  2042. CHECK_ERROR_EXIT(SUCCEEDED(hr),ID_CDLDBG_NATIVECODE_SYNTAX);
  2043. }
  2044. else
  2045. {
  2046. clsid = CLSID_NULL;
  2047. szCLSID[0] = '\0';
  2048. }
  2049. // get NAME attribute
  2050. hr = DupAttribute(pCode, DU_ATTRIB_NAME, &szName);
  2051. CHECK_ERROR_EXIT(SUCCEEDED(hr),ID_CDLDBG_NATIVECODE_SYNTAX);
  2052. // use "NAME" attribute as file name to OCX/INF/DLL
  2053. if (FAILED(hr = Unicode2Ansi(szName, &szNativeName)))
  2054. break;
  2055. // get VERSION attribute
  2056. if (SUCCEEDED(GetAttributeA(pCode, DU_ATTRIB_VERSION, szVersion, MAX_PATH))) {
  2057. // convert VERSION string
  2058. hr = GetVersionFromString(szVersion, &dwVersionMS, &dwVersionLS);
  2059. CHECK_ERROR_EXIT(SUCCEEDED(hr),ID_CDLDBG_NATIVECODE_SYNTAX);
  2060. } else {
  2061. dwVersionMS = 0;
  2062. dwVersionLS = 0;
  2063. }
  2064. if (GetFirstChildTag(pCode, DU_TAG_SYSTEM, &pElemTmp) == S_OK) {
  2065. bSystem = TRUE;
  2066. SAFERELEASE(pElemTmp);
  2067. } else {
  2068. bSystem = FALSE;
  2069. }
  2070. // Check if object CLSID unit is currently installed
  2071. // NOTE: This assumes MSICD
  2072. HRESULT hrExact;
  2073. HRESULT hrAny;
  2074. hrAny = IsControlLocallyInstalled(szNativeName,
  2075. (LPCLSID)&clsid, NULL,
  2076. dwVersionMS, dwVersionLS,
  2077. &lci, GetDestDirHint(),
  2078. FALSE);
  2079. if (m_bExactVersion) {
  2080. hrExact = IsControlLocallyInstalled(szNativeName,
  2081. (LPCLSID)&clsid, NULL,
  2082. dwVersionMS, dwVersionLS,
  2083. &lci, GetDestDirHint(),
  2084. TRUE);
  2085. }
  2086. if (m_bExactVersion && hrExact == S_FALSE && hrAny == S_OK) {
  2087. // Newer version exists on the machine.
  2088. // Check if we are going to install outside of DPF
  2089. // and disallow if we are going to downgrade.
  2090. BOOL bIsDPFComponent = FALSE;
  2091. CHAR szOCXCacheDirSFN[MAX_PATH];
  2092. CHAR szFNameSFN[MAX_PATH];
  2093. if (lci.szExistingFileName[0]) {
  2094. GetShortPathName(lci.szExistingFileName, szFNameSFN, MAX_PATH);
  2095. GetShortPathName(g_szOCXCacheDir, szOCXCacheDirSFN, MAX_PATH);
  2096. if (StrStrI(szFNameSFN, szOCXCacheDirSFN)) {
  2097. bIsDPFComponent = TRUE;
  2098. }
  2099. }
  2100. if (!bIsDPFComponent) {
  2101. // Trying to downgrade a system component. Just pretend
  2102. // system component is OK.
  2103. if (!IsEqualGUID(clsid, GetClsid())) {
  2104. if (lci.szExistingFileName[0]) {
  2105. hr = QueueModuleUsage(lci.szExistingFileName, MU_CLIENT);
  2106. }
  2107. }
  2108. goto nextNativeCode;
  2109. }
  2110. }
  2111. // Else, we are a legacy case (non-sxs) or
  2112. // hrExact == S_OK (therefore, hrAny == S_OK) or
  2113. // hrAny == hrExact == S_FALSE (and we fall through).
  2114. else {
  2115. if (hrAny != S_FALSE) {
  2116. if (!IsEqualGUID(clsid, GetClsid())) {
  2117. if (lci.szExistingFileName[0]) {
  2118. hr = QueueModuleUsage(lci.szExistingFileName, MU_CLIENT);
  2119. }
  2120. }
  2121. goto nextNativeCode;
  2122. }
  2123. }
  2124. // Disallow replacement of SFC files for Win2K
  2125. if (g_bNT5OrGreater)
  2126. {
  2127. if (!FileProtectionCheckSucceeded(lci.szExistingFileName))
  2128. {
  2129. hr = INET_E_CANNOT_REPLACE_SFP_FILE;
  2130. goto Exit;
  2131. }
  2132. }
  2133. // process CONFIG tag.
  2134. nLast3 = -1;
  2135. while (GetNextChildTag(pCode, DU_TAG_CONFIG, &pConfig, nLast3) == S_OK) {
  2136. if (bDestroyPCBHList) {
  2137. DestroyPCBHList(pcbhList);
  2138. SAFEDELETE(pcbhList);
  2139. }
  2140. pcbhList = new CList<CCodeBaseHold *, CCodeBaseHold *>;
  2141. if (pcbhList == NULL) {
  2142. hr = E_OUTOFMEMORY;
  2143. goto Exit;
  2144. }
  2145. bDestroyPCBHList = TRUE;
  2146. pcbhList->RemoveAll();
  2147. hr = ProcessImplementation(pConfig, pcbhList, m_lcid
  2148. #ifdef WX86
  2149. , GetMultiArch()
  2150. #endif
  2151. );
  2152. SAFERELEASE(pConfig);
  2153. if (FAILED(hr))
  2154. break;
  2155. if (hr == S_OK) {
  2156. pBaseFileName = NULL;
  2157. iCount = pcbhList->GetCount();
  2158. if (iCount) {
  2159. pcbh = pcbhList->GetHead();
  2160. pcbh->dwFlags |= CBH_FLAGS_DOWNLOADED;
  2161. }
  2162. else {
  2163. pcbh = NULL;
  2164. }
  2165. if (pcbh) {
  2166. if (FAILED(hr = Unicode2Ansi(pcbh->wszCodeBase, &szCodeBase)))
  2167. break;
  2168. if (!pcbh->bHREF) {
  2169. // CODEBASE FILENAME= has precedence over NAME="" for file name.
  2170. // If FILENAME is CAB, then extract contents
  2171. // with szNativeName=NAME, szCodeBase=thiscab
  2172. // otherwise
  2173. // szNativeName=FILENAME, szCodeBase=thiscab, ignore NAME
  2174. FILEXTN extn = ::GetExtnAndBaseFileName(szCodeBase, &pBaseFileName);
  2175. if (extn == FILEXTN_CAB) {
  2176. ExtractInnerCAB(pdl, szCodeBase);
  2177. } else {
  2178. SAFEDELETE(szNativeName);
  2179. if (FAILED(hr = Unicode2Ansi(pcbh->wszCodeBase, &szNativeName)))
  2180. break;
  2181. }
  2182. SAFEDELETE(szCodeBase);
  2183. szCodeBase = new char[lstrlenA(szTHISCAB)+1];
  2184. if (!szCodeBase) {
  2185. hr = E_OUTOFMEMORY;
  2186. break;
  2187. }
  2188. lstrcpyA(szCodeBase, szTHISCAB);
  2189. }
  2190. } else {
  2191. // No FILENAME field, szNativeName=NAME & szCodeBase=thiscab
  2192. szCodeBase = new char[lstrlenA(szTHISCAB)+1];
  2193. if (!szCodeBase) {
  2194. hr = E_OUTOFMEMORY;
  2195. break;
  2196. }
  2197. lstrcpyA(szCodeBase,szTHISCAB);
  2198. }
  2199. FILEXTN extn = ::GetExtnAndBaseFileName(szNativeName, &pBaseFileName);
  2200. //BUGBUG: Should we limit ourselves to at most one INF file per OSD?
  2201. if ((!pcbh || !pcbh->bHREF) && extn == FILEXTN_INF) {
  2202. // File is in temporary directory somewhere, We extract Temp
  2203. if (!catDirAndFile(szTempFile, MAX_PATH, (char *)szTempDir, szNativeName)) {
  2204. hr = E_FAIL;
  2205. goto Exit;
  2206. }
  2207. hr = SetupInf(szTempFile, pBaseFileName, pdl);
  2208. if (SUCCEEDED(hr)) {
  2209. fSetupInf = TRUE;
  2210. }
  2211. } else {
  2212. if (lci.IsPresent() && pCodeInstall) {
  2213. // a prev version exists. get permission to overwrite
  2214. // if ICodeInstall available
  2215. WCHAR szBuf[MAX_PATH];
  2216. MultiByteToWideChar(CP_ACP, 0,
  2217. (lci.szExistingFileName[0])?lci.szExistingFileName:szNativeName, -1, szBuf, MAX_PATH);
  2218. hr = pCodeInstall->OnCodeInstallProblem( CIP_OLDER_VERSION_EXISTS,
  2219. NULL, szBuf, 0);
  2220. if (FAILED(hr)) {
  2221. if (hr == E_ABORT)
  2222. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2223. break;
  2224. }
  2225. }
  2226. //BUGBUG: Need a way to do this stuff in OSD
  2227. DESTINATION_DIR dest = LDID_OCXCACHE;
  2228. //DWORD dwRegisterServer = CST_FLAG_REGISTERSERVER;
  2229. // we can't force a register server here as this will
  2230. // mean as if we have an override in the INF/OSD
  2231. // whereas there is no support for this in OSD.
  2232. // turning this off here means:
  2233. // for EXE we will run if pointed to in the OSD or
  2234. // directly by codebase, but we will run with /regsvr
  2235. // and leave installed only if marked oleself register
  2236. // for an OCX unless overrideen we will alwys register
  2237. // if the DLL is registerable (has dllregisterserver entrypt
  2238. DWORD dwRegisterServer = 0;
  2239. DWORD dwCopyFlags = 0;
  2240. if (m_dwSystemComponent || bSystem) {
  2241. m_dwSystemComponent = TRUE;
  2242. dest = LDID_SYS;
  2243. }
  2244. hr = StartDownload(szNativeName, pdl, szCodeBase,
  2245. dest, lci.lpDestDir, dwRegisterServer, dwCopyFlags,
  2246. pcbhList);
  2247. bDestroyPCBHList = FALSE;
  2248. }
  2249. SAFEDELETE(szCodeBase);
  2250. goto nextNativeCode;
  2251. }
  2252. if (FAILED(hr))
  2253. break;
  2254. }
  2255. // here if anything in above loop failed or we never found an
  2256. // implmentation matching our config
  2257. if (SUCCEEDED(hr))
  2258. hr = HRESULT_FROM_WIN32(ERROR_APP_WRONG_OS);
  2259. nextNativeCode:
  2260. SAFERELEASE(pCode);
  2261. SAFERELEASE(pConfig);
  2262. }
  2263. Exit:
  2264. SAFERELEASE(pCode);
  2265. SAFERELEASE(pConfig);
  2266. SAFEDELETE(szName);
  2267. SAFEDELETE(szNativeName);
  2268. SAFEDELETE(szCodeBase);
  2269. if (SUCCEEDED(hr) && fSetupInf)
  2270. hr = S_FALSE;
  2271. DEBUG_LEAVE(hr);
  2272. return hr;
  2273. }
  2274. // ---------------------------------------------------------------------------
  2275. // %%Function: CCodeDownload::ParseOSD
  2276. // ---------------------------------------------------------------------------
  2277. HRESULT
  2278. CCodeDownload::ParseOSD(const char *szOSD, char *szOSDBaseName, CDownload *pdl)
  2279. {
  2280. DEBUG_ENTER((DBG_DOWNLOAD,
  2281. Hresult,
  2282. "CCodeDownload::ParseOSD",
  2283. "this=%#x, %.80q, %.80q, %#x",
  2284. this, szOSD, szOSDBaseName, pdl
  2285. ));
  2286. HRESULT hr = S_OK;
  2287. IXMLElement *pSoftDist = NULL, *pDepend = NULL, *pJava = NULL,
  2288. *pNativeCode = NULL, *pTitle = NULL, *pExpire = NULL,
  2289. *pSystemTag = NULL, *pSXS = NULL;
  2290. LPSTR pBaseFileName = NULL, lpTmpDir = NULL;
  2291. DWORD len = 0;
  2292. int nLast, nLast2, nLast3;
  2293. BOOL bSetupInf = FALSE;
  2294. // create a CSetup OBJ and add it to the CDownload obj
  2295. CSetup *pSetup = new CSetup(szOSD, szOSDBaseName, FILEXTN_OSD, NULL, &hr);
  2296. if(!pSetup) {
  2297. hr = E_OUTOFMEMORY;
  2298. }
  2299. if (FAILED(hr))
  2300. goto Exit;
  2301. pdl->AddSetupToList(pSetup);
  2302. hr = SetManifest(FILEXTN_OSD, szOSD);
  2303. if (FAILED(hr))
  2304. goto Exit;
  2305. hr = GetSoftDistFromOSD(szOSD, &pSoftDist);
  2306. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_FAILED_OSD_OM);
  2307. hr = DupAttribute(pSoftDist, DU_ATTRIB_NAME, &m_szDistUnit);
  2308. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DU_REQUIRED_ATTRIB_MISSING);
  2309. hr = DupAttributeA(pSoftDist, DU_ATTRIB_VERSION, &m_szVersionInManifest);
  2310. CHECK_ERROR_EXIT(SUCCEEDED(hr), ID_CDLDBG_DU_REQUIRED_ATTRIB_MISSING);
  2311. // process TITLE display name
  2312. if (GetFirstChildTag(pSoftDist, DU_TAG_TITLE, &pTitle) == S_OK) {
  2313. BSTR bstrTitle = NULL;
  2314. hr = pTitle->get_text(&bstrTitle);
  2315. if (FAILED(hr)) {
  2316. goto Exit;
  2317. }
  2318. if (FAILED(Unicode2Ansi(bstrTitle, &m_szDisplayName))) {
  2319. hr = E_OUTOFMEMORY;
  2320. SAFESYSFREESTRING(bstrTitle);
  2321. goto Exit;
  2322. }
  2323. SAFESYSFREESTRING(bstrTitle);
  2324. }
  2325. // See if there is a SYSTEM tag
  2326. if (GetFirstChildTag(pSoftDist, DU_TAG_SYSTEM, &pSystemTag) == S_OK) {
  2327. SAFERELEASE(pSystemTag);
  2328. m_dwSystemComponent = TRUE;
  2329. }
  2330. // process expire date
  2331. if (GetFirstChildTag(pSoftDist, DU_TAG_EXPIRE, &pExpire) == S_OK) {
  2332. BSTR bstrExpire = NULL;
  2333. hr = pExpire->get_text(&bstrExpire);
  2334. if (SUCCEEDED(hr)) {
  2335. OLECHAR *pch = bstrExpire;
  2336. m_dwExpire = 0;
  2337. for ( ; *pch && m_dwExpire <= MAX_EXPIRE_DAYS; pch++ ) {
  2338. if ( (*pch >= TEXT('0') && *pch <= TEXT('9')) )
  2339. m_dwExpire = m_dwExpire * 10 + *pch - TEXT('0');
  2340. else
  2341. break;
  2342. }
  2343. if (m_dwExpire > MAX_EXPIRE_DAYS)
  2344. m_dwExpire = MAX_EXPIRE_DAYS;
  2345. }
  2346. // else treat failure with a NOP
  2347. SAFESYSFREESTRING(bstrExpire);
  2348. }
  2349. if (!m_bExactVersion) {
  2350. // Exact Version necessarily means uninstall old. Don't bother
  2351. // looking it up.
  2352. if (GetFirstChildTag(pSoftDist, DU_TAG_UNINSTALL_OLD, &pSXS) == S_OK)
  2353. {
  2354. m_bUninstallOld = TRUE;
  2355. }
  2356. }
  2357. //REVIEW: optionally look for ABSTRACT
  2358. //REVIEW: CONFIG tags at highest level are ignored.
  2359. // process all DEPENDENCY tags (installing Distribution Units)
  2360. nLast = -1;
  2361. while (GetNextChildTag(pSoftDist, DU_TAG_DEPENDENCY, &pDepend, nLast) == S_OK) {
  2362. hr = ProcessDependency(pdl, pDepend);
  2363. SAFERELEASE(pDepend);
  2364. if (FAILED(hr))
  2365. goto Exit;
  2366. }
  2367. // process only one NATIVECODE tags (Installing ActiveX/CLSID specified controls)
  2368. nLast = -1;
  2369. if (GetNextChildTag(pSoftDist, DU_TAG_NATIVECODE, &pNativeCode, nLast) == S_OK) {
  2370. hr = ProcessNativeCode(pdl, pNativeCode);
  2371. SAFERELEASE(pNativeCode);
  2372. if (FAILED(hr))
  2373. goto Exit;
  2374. if (hr == S_FALSE)
  2375. bSetupInf = TRUE;
  2376. }
  2377. // process JAVA tags (Installing Java packages)
  2378. nLast = -1;
  2379. while (GetNextChildTag(pSoftDist, DU_TAG_JAVA, &pJava, nLast) == S_OK) {
  2380. //BUGBUG: Parameters szOSD, szOSDBaseName are currently unused.
  2381. hr = ProcessJavaManifest(pJava, szOSD, szOSDBaseName, pdl);
  2382. SAFERELEASE(pJava);
  2383. if (FAILED(hr))
  2384. goto Exit;
  2385. }
  2386. Exit:
  2387. if (!bSetupInf) {
  2388. if (SUCCEEDED(hr)) {
  2389. pdl->SetDLState(DLSTATE_READY_TO_SETUP);
  2390. } else {
  2391. // we encountered an error, go to done state.
  2392. pdl->SetDLState(DLSTATE_DONE);
  2393. }
  2394. }
  2395. SAFERELEASE(pJava);
  2396. SAFERELEASE(pTitle);
  2397. SAFERELEASE(pExpire);
  2398. SAFERELEASE(pNativeCode);
  2399. SAFERELEASE(pDepend);
  2400. SAFERELEASE(pSoftDist);
  2401. SAFERELEASE(pSXS);
  2402. DEBUG_LEAVE(hr);
  2403. return hr;
  2404. }
  2405. // ---------------------------------------------------------------------------
  2406. // %%Function: CCodeDownload::AddDistUnitList
  2407. // ---------------------------------------------------------------------------
  2408. HRESULT
  2409. CCodeDownload::AddDistUnitList(LPWSTR szDistUnit)
  2410. {
  2411. DEBUG_ENTER((DBG_DOWNLOAD,
  2412. Hresult,
  2413. "CCodeDownload::AddDistUnitList",
  2414. "this=%#x, %.80wq",
  2415. this, szDistUnit
  2416. ));
  2417. HRESULT hr = E_FAIL;
  2418. LPWSTR wszDistUnit = 0;
  2419. hr = CDLDupWStr(&wszDistUnit, szDistUnit);
  2420. if (SUCCEEDED(hr) && wszDistUnit) {
  2421. m_pDependencies.AddHead(wszDistUnit);
  2422. }
  2423. DEBUG_LEAVE(hr);
  2424. return hr;
  2425. }
  2426. // ---------------------------------------------------------------------------
  2427. // %%Function: CCodeDownload::SetupInf
  2428. // ---------------------------------------------------------------------------
  2429. HRESULT
  2430. CCodeDownload::SetupInf(const char *szInf, char *szInfBaseName, CDownload *pdl)
  2431. {
  2432. DEBUG_ENTER((DBG_DOWNLOAD,
  2433. Hresult,
  2434. "CCodeDownload::SetupInf",
  2435. "this=%#x, %.80q, %.80q, %#x",
  2436. this, szInf, szInfBaseName, pdl
  2437. ));
  2438. HRESULT hr = S_OK;
  2439. CSetup* pSetup = NULL;
  2440. int nBuffSize = MAX_INF_SECTIONS_SIZE;
  2441. char lpSections[MAX_INF_SECTIONS_SIZE];
  2442. const static char *szAddCodeSection = "Add.Code";
  2443. const static char *szHooksSection = "Setup Hooks";
  2444. const static char *szUninstallOld = "UninstallOld";
  2445. static char *szDefault = "";
  2446. DWORD len;
  2447. SetHaveInf();
  2448. if (!pdl->HasAllActiveXPermissions()) {
  2449. if (IsSilentMode())
  2450. {
  2451. SetBitsInCache();
  2452. } else {
  2453. hr = TRUST_E_FAIL;
  2454. goto Exit;
  2455. }
  2456. }
  2457. pdl->SetDLState(DLSTATE_INF_PROCESSING);
  2458. Assert(m_szInf == NULL);
  2459. m_szInf = new char [lstrlen(szInf)+1];
  2460. if (!m_szInf) {
  2461. hr = E_OUTOFMEMORY;
  2462. goto Exit;
  2463. }
  2464. lstrcpy(m_szInf, szInf);
  2465. // Add a setup obj for this INF file
  2466. // We keep the INF file in the ocxcache dir
  2467. // to be able to nuke the OCX
  2468. // create a CSetup OBJ and add it to the CDownload obj
  2469. pSetup = new CSetup(szInf, szInfBaseName, FILEXTN_INF, NULL, &hr);
  2470. if(!pSetup) {
  2471. hr = E_OUTOFMEMORY;
  2472. }
  2473. if (FAILED(hr)) {
  2474. SAFEDELETE(pSetup);
  2475. goto Exit;
  2476. }
  2477. pdl->AddSetupToList(pSetup);
  2478. len = GetPrivateProfileString(szAddCodeSection, NULL, szDefault,
  2479. lpSections, nBuffSize, m_szInf);
  2480. if (!len) {
  2481. // no Internet Code Downloader known sections in INF may be a
  2482. // regular Win32 INF file format, make a hook if the
  2483. // INF came in a CAB, which will be to extract all files in the
  2484. // current CAB and then RunSetupCommand
  2485. // there's no [add.code]
  2486. // look to see if there's a [setup hooks]
  2487. // if not we then create a hook to process the default install section
  2488. // if there's a [setup hooks] we won't make a default hokk for you
  2489. // as you can make a hook yourself to process default install
  2490. // the idea is you either don't know about us (we need to help you)
  2491. // or you are code downloader aware (help yourself with our capabilty)
  2492. // this allows the user to have an INF with any or all of the following
  2493. // 1) [add.code]
  2494. // 2) [Setup hooks]
  2495. // 3) win32 inf : defaultinstall
  2496. len = GetPrivateProfileString(szHooksSection, NULL, szDefault,
  2497. lpSections, nBuffSize, m_szInf);
  2498. if (!len) {
  2499. // make a new hook and add it to this CAB
  2500. // post a message to trigger setup phase as nothing else is needed
  2501. hr = pdl->AddHook(NULL, szInfBaseName, NULL/* szInfSection */, RSC_FLAG_INF);
  2502. goto Exit;
  2503. }
  2504. } else {
  2505. m_pCurCode = m_pAddCodeSection = new char [len + 1];
  2506. if (m_pAddCodeSection) {
  2507. memcpy(m_pAddCodeSection, lpSections, len);
  2508. m_pAddCodeSection[len] = '\0';
  2509. }
  2510. }
  2511. if (!m_bExactVersion) {
  2512. m_bUninstallOld=GetPrivateProfileInt(szAddCodeSection, szUninstallOld, 0, m_szInf);
  2513. }
  2514. Exit:
  2515. if (SUCCEEDED(hr)) {
  2516. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_PROCESS_INF, this, (DWORD_PTR)pdl);
  2517. if (pPkt) {
  2518. hr = pPkt->Post();
  2519. } else {
  2520. hr = E_OUTOFMEMORY;
  2521. }
  2522. }
  2523. DEBUG_LEAVE(hr);
  2524. return hr;
  2525. }
  2526. // ---------------------------------------------------------------------------
  2527. // %%Function: CCodeDownload::IsSectionInINF
  2528. // Checks if a section is in the INF
  2529. // returns:
  2530. // S_OK: lpCurCode has the satellite binary name
  2531. // S_FALSE: ignore this code and use default resources in main dll
  2532. // E_XXX: any other error
  2533. BOOL
  2534. CCodeDownload::IsSectionInINF(
  2535. LPCSTR lpCurCode)
  2536. {
  2537. DEBUG_ENTER((DBG_DOWNLOAD,
  2538. Bool,
  2539. "CCodeDownload::IsSectionInINF",
  2540. "this=%#x, %.80q",
  2541. this, lpCurCode
  2542. ));
  2543. const char *szDefault = "";
  2544. DWORD len;
  2545. #define FAKE_BUF_SIZE 3
  2546. char szBuf[FAKE_BUF_SIZE];
  2547. len = GetPrivateProfileString(lpCurCode, NULL, szDefault,
  2548. szBuf, FAKE_BUF_SIZE, m_szInf);
  2549. if (len == (FAKE_BUF_SIZE - 2)) { // returns Out Of Buffer Space?
  2550. // yes, section found
  2551. DEBUG_LEAVE(TRUE);
  2552. return TRUE;
  2553. } else {
  2554. DEBUG_LEAVE(FALSE);
  2555. return FALSE;
  2556. }
  2557. }
  2558. void CCodeDownload::CodeDownloadDebugOut(int iOption, BOOL fOperationFailed,
  2559. UINT iResId, ...)
  2560. {
  2561. DEBUG_ENTER((DBG_DOWNLOAD,
  2562. None,
  2563. "CCodeDownload::CodeDownloadDebugOut",
  2564. "this=%#x, %d, %B, %#x, ...",
  2565. this, iOption, fOperationFailed, iResId
  2566. ));
  2567. // Temp solution to prevent buffer overruns in debug logging code.
  2568. // Long term, the printfs should be constrained. It will be a must
  2569. // if URLs become fully dynamic.
  2570. static char szDebugString[MAX_DEBUG_STRING_LENGTH*5];
  2571. static char szFormatString[MAX_DEBUG_FORMAT_STRING_LENGTH];
  2572. va_list args;
  2573. LoadString(g_hInst, iResId, szFormatString, MAX_DEBUG_FORMAT_STRING_LENGTH);
  2574. va_start(args, iResId);
  2575. vsprintf(szDebugString, szFormatString, args);
  2576. va_end(args);
  2577. m_debuglog->DebugOutPreFormatted(iOption, fOperationFailed, szDebugString);
  2578. DEBUG_LEAVE(0);
  2579. }
  2580. // ---------------------------------------------------------------------------
  2581. // %%Function: CCodeDownload::GetSatelliteName
  2582. // gets the lang specific satellite DLL name
  2583. // in the INF
  2584. // returns:
  2585. // S_OK: lpCurCode has the satellite binary name
  2586. // S_FALSE: ignore this code and use default resources in main dll
  2587. // E_XXX: any other error
  2588. HRESULT
  2589. CCodeDownload::GetSatelliteName(
  2590. LPSTR lpCurCode,
  2591. int iLen)
  2592. {
  2593. DEBUG_ENTER((DBG_DOWNLOAD,
  2594. Hresult,
  2595. "CCodeDownload::GetSatelliteName",
  2596. "this=%#x, %.80q",
  2597. this, lpCurCode
  2598. ));
  2599. HRESULT hr = S_OK;
  2600. const char *szDefault = "";
  2601. DWORD len;
  2602. #define FAKE_BUF_SIZE 3
  2603. char szBuf[FAKE_BUF_SIZE];
  2604. char szExtension[5];
  2605. int iReturn = 0;
  2606. Assert(lpCurCode);
  2607. szExtension[0] = *lpCurCode = '\0';
  2608. // get a quick out for code that does not have any vars in them
  2609. if ((StrChr(m_pCurCode, '%') == NULL) &&
  2610. IsSectionInINF(m_pCurCode)) {
  2611. // not a satellite
  2612. StrNCpy(lpCurCode, m_pCurCode, iLen);
  2613. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ITEM_PROCESSED, lpCurCode);
  2614. DEBUG_LEAVE(hr);
  2615. return hr;
  2616. }
  2617. // allow IE3 workarounds for %LANG%
  2618. // by looking for sections that have a %LANG% literally in them
  2619. // after looking for sections with the variable expanded
  2620. // BEGIN NOTE: add vars and values in matching order
  2621. // add a var by adding a new define VAR_NEW_VAR = NUM_VARS++
  2622. const char *szVars[] = {
  2623. #define VAR_LANG 0 // 3 letter lang extension
  2624. "%LANG%",
  2625. #define NUM_VARS 1
  2626. ""
  2627. };
  2628. const char *szValues[NUM_VARS + 1];
  2629. szValues[VAR_LANG] = szExtension;
  2630. szValues[NUM_VARS] = NULL;
  2631. // END NOTE: add vars and values in matching order
  2632. UINT uLocaleTest=0;
  2633. uLocaleTest = (LOWORD(m_lcid) & (~(~0 << 4) << 0)) >> 0;
  2634. // obtain the 3 character Lang abbreviation for the
  2635. // LCID we're running on.
  2636. // if it doesn't exist we'll get just the 2 charact Lang abbreviation
  2637. // and try again, failing that we default to English
  2638. iReturn = m_langinfo.GetLocaleStrings(m_lcid, szExtension, sizeof(szExtension));
  2639. if (!iReturn) {
  2640. hr = HRESULT_FROM_WIN32(GetLastError());
  2641. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_PRIMARY_LANGUAGE, hr, lpCurCode);
  2642. goto Exit;
  2643. }
  2644. // expand the variables names if any
  2645. hr = CSetupHook::ExpandCommandLine(m_pCurCode, lpCurCode, MAX_PATH, szVars, szValues);
  2646. if (FAILED(hr)) { // failed
  2647. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_NO_SECTION, m_pCurCode, szExtension);
  2648. goto Exit;
  2649. }
  2650. // vars are expanded correctly (S_OK) or
  2651. // no vars got expanded.(S_FALSE) maybe we could try the section as is
  2652. if ( IsSectionInINF(lpCurCode)) {
  2653. // satellite found!
  2654. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_SATELLITE_FOUND, lpCurCode);
  2655. hr = S_OK;
  2656. goto Exit;
  2657. }
  2658. // we couldn't find it with the entire LCID, try it with just the primary
  2659. // langid
  2660. LCID lcid;
  2661. lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(LANGIDFROMLCID(m_lcid)), SUBLANG_DEFAULT), SORT_DEFAULT);
  2662. iReturn = m_langinfo.GetLocaleStrings(lcid, szExtension, sizeof(szExtension));
  2663. if (!iReturn) {
  2664. hr = HRESULT_FROM_WIN32(GetLastError());
  2665. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_PROCESSINF_FAILED, hr, lpCurCode);
  2666. goto Exit;
  2667. }
  2668. // expand the variables names with new value
  2669. hr = CSetupHook::ExpandCommandLine(m_pCurCode, lpCurCode, MAX_PATH, szVars, szValues);
  2670. if (FAILED(hr) || (hr == S_FALSE)) { // failed or no vars
  2671. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_NO_SECTION, m_pCurCode, szExtension);
  2672. if (hr == S_FALSE)
  2673. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  2674. goto Exit;
  2675. }
  2676. // try the INF section again
  2677. if ( !IsSectionInINF(lpCurCode)) {
  2678. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_ERR_NO_SECTION, m_pCurCode, szExtension);
  2679. // no section for this language. This is OK skip the file
  2680. // browser will end up using default lang/resources
  2681. hr = S_FALSE;
  2682. } else {
  2683. // satellite found!
  2684. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_SATELLITE_FOUND, lpCurCode);
  2685. }
  2686. Exit:
  2687. DEBUG_LEAVE(hr);
  2688. return hr;
  2689. }
  2690. // ---------------------------------------------------------------------------
  2691. // %%Function: CCodeDownload::GetInfCodeLocation
  2692. // gets the platform specific or independent location URL of the code specified
  2693. // in the INF
  2694. // returns:
  2695. // S_OK: szURL has the location
  2696. // S_FALSE: ignore this code for the current platform
  2697. // E_XXX: any other error
  2698. HRESULT
  2699. CCodeDownload::GetInfCodeLocation(
  2700. LPCSTR lpCurCode,
  2701. LPSTR szURL)
  2702. {
  2703. DEBUG_ENTER((DBG_DOWNLOAD,
  2704. Hresult,
  2705. "CCodeDownload::GetInfCodeLocation",
  2706. "this=%#x, %.80q, %.80q",
  2707. this, lpCurCode, szURL
  2708. ));
  2709. const static char *szLoc = "File";
  2710. static char *szDefault = "";
  2711. HRESULT hr = S_OK;
  2712. Assert(m_szInf);
  2713. szURL[0] = '\0'; // init to empty string
  2714. // look for platform specific URL first
  2715. // this is needed to skip some files for some
  2716. // platforms
  2717. #ifdef WX86
  2718. char *szPreferredArch;
  2719. char *szAlternateArch;
  2720. HRESULT hrArch;
  2721. GetMultiArch()->SelectArchitecturePreferences(
  2722. g_szPlatform,
  2723. "file-win32-x86",
  2724. &szPreferredArch,
  2725. &szAlternateArch);
  2726. GetPrivateProfileString(lpCurCode, szPreferredArch, szDefault, szURL,
  2727. INTERNET_MAX_URL_LENGTH, m_szInf);
  2728. if (szURL[0] != '\0' && lstrcmpi(szURL, szIGNORE) != 0) {
  2729. // There was a URL and it was not 'ignore' to indicate it is not
  2730. // applicable to this platform.
  2731. CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_WX86_REQUIRE_PRIMARY_ARCH, szURL);
  2732. hrArch = GetMultiArch()->RequirePrimaryArch();
  2733. Assert(SUCCEEDED(hrArch));
  2734. } else if (szAlternateArch) {
  2735. GetPrivateProfileString(lpCurCode, szAlternateArch, szDefault, szURL,
  2736. INTERNET_MAX_URL_LENGTH, m_szInf);
  2737. if (szURL[0]) {
  2738. if (lstrcmpi(szURL, szIGNORE) != 0) {
  2739. // The alternate architecture matched and the URL was not
  2740. // 'ignore' to indicate it is not applicable to this platform.
  2741. CodeDownloadDebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_WX86_REQUIRE_ALTERNATE_ARCH, szURL);
  2742. hrArch = GetMultiArch()->RequireAlternateArch();
  2743. Assert(SUCCEEDED(hrArch));
  2744. }
  2745. }
  2746. }
  2747. #else
  2748. GetPrivateProfileString(lpCurCode, g_szPlatform, szDefault, szURL,
  2749. INTERNET_MAX_URL_LENGTH, m_szInf);
  2750. #endif
  2751. if (szURL[0] == '\0') {
  2752. GetPrivateProfileString(lpCurCode, szLoc, szDefault,
  2753. szURL, INTERNET_MAX_URL_LENGTH, m_szInf);
  2754. } else {
  2755. // got a platform specific URL
  2756. // look for 'ignore' keyword to mean that this is
  2757. // not applicable for this platform
  2758. if (lstrcmpi(szURL, szIGNORE) == 0) {
  2759. hr = S_FALSE;
  2760. }
  2761. }
  2762. DEBUG_LEAVE(hr);
  2763. return hr;
  2764. }
  2765. // ---------------------------------------------------------------------------
  2766. // %%Function: CCodeDownload::GetInfSectionInfo
  2767. HRESULT
  2768. CCodeDownload::GetInfSectionInfo(
  2769. LPSTR lpCurCode,
  2770. int iLen,
  2771. LPSTR szURL,
  2772. LPCLSID *plpClsid,
  2773. LPDWORD pdwFileVersionMS,
  2774. LPDWORD pdwFileVersionLS,
  2775. DESTINATION_DIR *pdest,
  2776. LPDWORD pdwRegisterServer,
  2777. LPDWORD pdwCopyFlags,
  2778. BOOL *pbDestDir
  2779. )
  2780. {
  2781. DEBUG_ENTER((DBG_DOWNLOAD,
  2782. Hresult,
  2783. "CCodeDownload::GetInfSectionInfo",
  2784. "this=%#x, %.80q, %.80q, %#x, %#x, %#x, %#x, %#x, %#x, %#x",
  2785. this, lpCurCode, szURL, plpClsid, pdwFileVersionMS, pdwFileVersionLS,
  2786. pdest, pdwRegisterServer, pdwCopyFlags, pbDestDir
  2787. ));
  2788. const static char *szFileVersion = "FileVersion";
  2789. const static char *szDest = "DestDir";
  2790. const static char *szRegisterServerOverride = "RegisterServer";
  2791. const static char *szCopyFlags = "CopyFlags";
  2792. const static char *szForceDestDir = "ForceDestDir";
  2793. static char *szDefault = "";
  2794. DWORD len;
  2795. HRESULT hr = S_OK;
  2796. char szBuf[MAX_PATH];
  2797. hr = GetSatelliteName(lpCurCode, iLen);
  2798. if (hr != S_OK)
  2799. goto Exit;
  2800. hr = GetInfCodeLocation( lpCurCode, szURL);
  2801. if (hr != S_OK)
  2802. goto Exit;
  2803. // get RegisterServerOverride if any
  2804. if (GetPrivateProfileString(lpCurCode, szRegisterServerOverride, szDefault,
  2805. szBuf, MAX_PATH, m_szInf)) {
  2806. *pdwRegisterServer = CST_FLAG_REGISTERSERVER_OVERRIDE;
  2807. if ((szBuf[0] == 'y') || (szBuf[0] == 'Y') ||
  2808. (szBuf[0] == '1') || (lstrcmpi(szBuf, "true") == 0)) {
  2809. *pdwRegisterServer |= CST_FLAG_REGISTERSERVER;
  2810. }
  2811. }
  2812. // get CopyFlags if any
  2813. *pdwCopyFlags=GetPrivateProfileInt(lpCurCode, szCopyFlags, 0, m_szInf);
  2814. // get version string
  2815. if (!(len =GetPrivateProfileString(lpCurCode, szFileVersion, szDefault,
  2816. szBuf, MAX_PATH, m_szInf))) {
  2817. // if no version specified, local copy is always OK!
  2818. szBuf[0] = '\0';
  2819. }
  2820. if ( FAILED(GetVersionFromString(szBuf, pdwFileVersionMS,
  2821. pdwFileVersionLS))){
  2822. hr = HRESULT_FROM_WIN32(GetLastError());
  2823. goto Exit;
  2824. }
  2825. // get Destination dir if suggested
  2826. *pdest=(DESTINATION_DIR)GetPrivateProfileInt(lpCurCode, szDest, 0, m_szInf);
  2827. // get ForceDestDir flag
  2828. *pbDestDir=GetPrivateProfileInt(lpCurCode, szForceDestDir, 0, m_szInf);
  2829. // get clsid string
  2830. if (!(len = GetPrivateProfileString(lpCurCode, szCLSID, szDefault,
  2831. szBuf, MAX_PATH, m_szInf))){
  2832. // if no clsid specified, not a control, just a plain dll?
  2833. *plpClsid = NULL;
  2834. goto Exit;
  2835. }
  2836. // Get CLSID from string
  2837. hr = ConvertANSItoCLSID(szBuf, *plpClsid);
  2838. Exit:
  2839. DEBUG_LEAVE(hr);
  2840. return hr;
  2841. }
  2842. // ---------------------------------------------------------------------------
  2843. // %%Function: CCodeDownload::StartDownload
  2844. HRESULT
  2845. CCodeDownload::StartDownload(
  2846. LPSTR szCurCode,
  2847. CDownload *pdl,
  2848. LPSTR szURL,
  2849. DESTINATION_DIR dest,
  2850. LPSTR szDestDir,
  2851. DWORD dwRegisterServer,
  2852. DWORD dwCopyFlags,
  2853. CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList)
  2854. {
  2855. DEBUG_ENTER((DBG_DOWNLOAD,
  2856. Hresult,
  2857. "CCodeDownload::StartDownload",
  2858. "this=%#x, %.80q, %#x, %.80q, %#x, %.80q, %#x, %#x, %#x",
  2859. this, szCurCode, pdl, szURL, dest,
  2860. szDestDir, dwRegisterServer, dwCopyFlags, pcbhList
  2861. ));
  2862. FILEXTN extn;
  2863. char *pBaseFileName;
  2864. HRESULT hr = NO_ERROR;
  2865. WCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  2866. CDownload *pdlCur = NULL;
  2867. CSetup* pSetup = NULL;
  2868. BOOL bDestroyList = TRUE;
  2869. extn = ::GetExtnAndBaseFileName(szURL, &pBaseFileName);
  2870. // if this INF came in a CAB then anything pointing to
  2871. // file=thiscab, means this szCurCode can be found in the CAB
  2872. // that this INF came in. This makes authoring the INFs easy
  2873. // because you don't have to know the name of the site that's going
  2874. // to distribute the OCX.
  2875. // Also, allows for web publisher to change the name of the
  2876. // CAB
  2877. if ((pdl->GetExtn() == FILEXTN_CAB) &&
  2878. (lstrcmpi(szTHISCAB, szURL) == 0)) {
  2879. pdl->AddSetupToExistingCAB(szCurCode, szDestDir, dest,
  2880. dwRegisterServer, dwCopyFlags);
  2881. goto Exit;
  2882. }
  2883. switch (extn) {
  2884. case FILEXTN_INF:
  2885. case FILEXTN_OSD:
  2886. hr = E_INVALIDARG; // don't supp multiple INFs (recursive downloads)
  2887. goto Exit;
  2888. case FILEXTN_CAB:
  2889. // check if URL is a cab that the inf came with (pdl->psess)
  2890. // else check if CAB has been submitted for download in some other
  2891. // CDownload that we just started when processing lines in INF
  2892. // above this one
  2893. // either case if you find a CAB then piggy back this code setup to
  2894. // that CDownload of the same CAB file
  2895. MultiByteToWideChar(CP_ACP, 0, szURL, -1, szBuf,
  2896. INTERNET_MAX_URL_LENGTH);
  2897. hr = FindCABInDownloadList(szBuf, pdl, &pdlCur);
  2898. if (FAILED(hr))
  2899. goto Exit;
  2900. if (pdlCur) {
  2901. // matching CAB found that we can pile on this setup
  2902. pdlCur->AddSetupToExistingCAB(szCurCode, szDestDir, dest, dwRegisterServer, dwCopyFlags);
  2903. goto Exit;
  2904. }
  2905. // fresh CAB needs to get pulled down.
  2906. // download the CODE=URL (ie. CAB or INF file first)
  2907. pdlCur = new CDownload(szBuf, extn, &hr);
  2908. if (!pdlCur) {
  2909. hr = E_OUTOFMEMORY;
  2910. }
  2911. if (FAILED(hr)) {
  2912. SAFEDELETE(pdlCur);
  2913. goto Exit;
  2914. }
  2915. AddDownloadToList(pdlCur);
  2916. {
  2917. BOOL bSetOnStack = SetOnStack();
  2918. hr = (pcbhList == NULL) ? (pdlCur->DoDownload(&m_pmkContext,
  2919. (BINDF_ASYNCHRONOUS|
  2920. BINDF_ASYNCSTORAGE)))
  2921. : (pdlCur->DoDownload(&m_pmkContext,
  2922. (BINDF_ASYNCHRONOUS|
  2923. BINDF_ASYNCSTORAGE),
  2924. pcbhList));
  2925. bDestroyList = FALSE;
  2926. if (bSetOnStack)
  2927. ResetOnStack();
  2928. }
  2929. if (FAILED(hr)) {
  2930. goto Exit;
  2931. }
  2932. pdlCur->AddSetupToExistingCAB(szCurCode, szDestDir, dest, dwRegisterServer, dwCopyFlags);
  2933. break;
  2934. case FILEXTN_EXE:
  2935. case FILEXTN_OCX:
  2936. case FILEXTN_DLL:
  2937. case FILEXTN_NONE:
  2938. case FILEXTN_UNKNOWN:
  2939. MultiByteToWideChar(CP_ACP, 0, szURL, -1, szBuf,
  2940. INTERNET_MAX_URL_LENGTH);
  2941. // download the CODE=URL (ie. CAB or INF file first)
  2942. pdlCur = new CDownload(szBuf, extn, &hr);
  2943. if (!pdlCur){
  2944. hr = E_OUTOFMEMORY;
  2945. }
  2946. if (FAILED(hr))
  2947. goto Exit;
  2948. AddDownloadToList(pdlCur);
  2949. // create a CSetup OBJ and add it to the CDownload obj
  2950. pSetup = new CSetup(NULL, szCurCode, extn, szDestDir, &hr,dest);
  2951. if(!pSetup) {
  2952. hr = E_OUTOFMEMORY;
  2953. goto Exit;
  2954. } else if (FAILED(hr)) {
  2955. delete pSetup;
  2956. goto Exit;
  2957. }
  2958. pSetup->SetCopyFlags (dwCopyFlags);
  2959. if (dwRegisterServer) {
  2960. pSetup->SetUserOverrideRegisterServer
  2961. (dwRegisterServer&CST_FLAG_REGISTERSERVER);
  2962. }
  2963. pdlCur->AddSetupToList(pSetup);
  2964. {
  2965. BOOL bSetOnStack = SetOnStack();
  2966. hr = (pcbhList == NULL) ? (pdlCur->DoDownload(&m_pmkContext,
  2967. (BINDF_ASYNCHRONOUS|
  2968. BINDF_ASYNCSTORAGE)))
  2969. : (pdlCur->DoDownload(&m_pmkContext,
  2970. (BINDF_ASYNCHRONOUS|
  2971. BINDF_ASYNCSTORAGE),
  2972. pcbhList));
  2973. bDestroyList = FALSE;
  2974. if (bSetOnStack)
  2975. ResetOnStack();
  2976. }
  2977. if (FAILED(hr)) {
  2978. goto Exit;
  2979. }
  2980. }
  2981. Exit:
  2982. if (bDestroyList && pcbhList) {
  2983. DestroyPCBHList(pcbhList);
  2984. SAFEDELETE(pcbhList);
  2985. }
  2986. DEBUG_LEAVE(hr);
  2987. return hr;
  2988. }
  2989. // ---------------------------------------------------------------------------
  2990. // %%Function: CCodeDownload::ProcessInf
  2991. /*
  2992. *sample INF file:
  2993. ;This is the INF file for CIRC3.OCX
  2994. [Add.Code]
  2995. circ3.ocx=circ3.ocx
  2996. random.dll=random.dll
  2997. mfc40.dll=mfc40.dll
  2998. foo.ocx=foo.ocx
  2999. [circ3.ocx]
  3000. file=http:\\ohserv\users\vatsanp\circ3.cab
  3001. clsid={9DBAFCCF-592F-101B-85CE-00608CEC297B}
  3002. FileVersion=1,0,0,143
  3003. [random.dll]
  3004. file=http://ohserv/users/vatsanp/random.dll
  3005. FileVersion=
  3006. ;DestDir = 10 or 11 ( LDID_WIN or LDID_SYS by INF convention)
  3007. ; if none specified installed in ocxcache directory, which is the typical case.
  3008. DestDir=10
  3009. [mfc40.dll]
  3010. ; way of saying I need mfc40 (version 4,0,0,5) but, I can't provide it
  3011. ; if absent on client fail load!
  3012. file=
  3013. FileVersion=4,0,0,5
  3014. [foo.ocx]
  3015. ; way of saying I need foo (clsid, version 4,0,0,5) but, I can't provide it
  3016. ; if absent on client fail load!
  3017. file=
  3018. clsid={DEADBEEF-592F-101B-85CE-00608CEC297B}
  3019. FileVersion=1,0,0,143
  3020. */
  3021. //
  3022. // We walk thru all the INF sections of code that needs to get installed.
  3023. // For each we get the CLSID, FileVersion (both optional) and URL to get from
  3024. // Depending on the extension of the URL we:
  3025. //
  3026. // CAB:
  3027. // if CAB is the one the INF came with
  3028. // extract file; create CSetup to install it (piggy back to pdl)
  3029. // else if some other CAB that has been set for download
  3030. // attach file to be extracted to pFilesToExtract
  3031. // attach a CSetup for this file
  3032. // else
  3033. // make a CDownload for this new CAB
  3034. // attach file to be extracted to pFilesToExtract
  3035. // attach a CSetup for this file
  3036. // start off download
  3037. // INF:
  3038. // Fail: don't support multiple INFs
  3039. //
  3040. // Anything else:
  3041. // Make a new CDownload for this
  3042. // start off download
  3043. // make CSetup
  3044. //
  3045. // ---------------------------------------------------------------------------
  3046. VOID
  3047. CCodeDownload::ProcessInf(CDownload *pdl)
  3048. {
  3049. DEBUG_ENTER((DBG_DOWNLOAD,
  3050. None,
  3051. "CCodeDownload::ProcessInf",
  3052. "this=%#x, %#x",
  3053. this, pdl
  3054. ));
  3055. char szURL[INTERNET_MAX_URL_LENGTH];
  3056. static char *szDefault = "";
  3057. const static char *szHOOK = "Hook";
  3058. char szCurCode[MAX_PATH];
  3059. DWORD len = 0;
  3060. FILEXTN extn;
  3061. DESTINATION_DIR dest;
  3062. DWORD dwFileVersionMS = 0;
  3063. DWORD dwFileVersionLS = 0;
  3064. CLSID clsid;
  3065. LPCLSID lpclsid = &clsid;
  3066. HRESULT hr = NO_ERROR;
  3067. char * pFileName = NULL;
  3068. DWORD dwRegisterServer = 0;
  3069. DWORD dwCopyFlags = 0;
  3070. BOOL bForceDestDir = FALSE;
  3071. CLocalComponentInfo lci;
  3072. ICodeInstall* pCodeInstall = GetICodeInstall();
  3073. if ( pdl->GetDLState() == DLSTATE_ABORT) {
  3074. hr = E_ABORT;
  3075. goto PI_Exit; // all done
  3076. }
  3077. if (!m_pCurCode || !(*m_pCurCode)) {
  3078. goto PI_Exit; // all done
  3079. }
  3080. hr = GetInfSectionInfo( szCurCode, sizeof(szCurCode), szURL, &lpclsid,
  3081. &dwFileVersionMS, &dwFileVersionLS, &dest, &dwRegisterServer, &dwCopyFlags,
  3082. &bForceDestDir
  3083. );
  3084. if (hr != S_OK)
  3085. goto PI_Exit;
  3086. HRESULT hrExact;
  3087. HRESULT hrAny;
  3088. if (m_bExactVersion) {
  3089. hrExact = IsControlLocallyInstalled(szCurCode,
  3090. lpclsid, NULL,
  3091. dwFileVersionMS, dwFileVersionLS,
  3092. &lci, GetDestDirHint(),
  3093. TRUE);
  3094. }
  3095. hrAny = IsControlLocallyInstalled(szCurCode,
  3096. lpclsid, NULL,
  3097. dwFileVersionMS, dwFileVersionLS,
  3098. &lci, GetDestDirHint(),
  3099. FALSE);
  3100. if (m_bExactVersion && hrExact == S_FALSE && hrAny == S_OK) {
  3101. // Newer version exists on the machine.
  3102. // Check if we are going to install outside of DPF
  3103. // and disallow if we are going to downgrade.
  3104. BOOL bIsDPFComponent = FALSE;
  3105. CHAR szOCXCacheDirSFN[MAX_PATH];
  3106. CHAR szFNameSFN[MAX_PATH];
  3107. GetShortPathName(lci.szExistingFileName, szFNameSFN, MAX_PATH);
  3108. GetShortPathName(g_szOCXCacheDir, szOCXCacheDirSFN, MAX_PATH);
  3109. if (StrStrI(szFNameSFN, szOCXCacheDirSFN)) {
  3110. bIsDPFComponent = TRUE;
  3111. }
  3112. if (!bIsDPFComponent) {
  3113. // Trying to downgrade a system component. Just pretend
  3114. // system component is OK.
  3115. if (lpclsid && IsEqualGUID(clsid, GetClsid())) {
  3116. goto PI_Exit;
  3117. }
  3118. if (lci.szExistingFileName[0])
  3119. hr= QueueModuleUsage(lci.szExistingFileName, MU_CLIENT);
  3120. goto PI_Exit;
  3121. }
  3122. }
  3123. // Else, we are a legacy case (non-sxs) or
  3124. // hrExact == S_OK (therefore, hrAny == S_OK) or
  3125. // hrAny == hrExact == S_FALSE (and we fall through).
  3126. else {
  3127. if (hrAny == S_OK) {
  3128. // make sure we have a ref count for the code downloader in
  3129. // shareddlls as well as mark us as a client in the usage section
  3130. // we need to do this only for a dependency, not for the main
  3131. // ocx. We can always get the main OCX back with CODEBASE. Its
  3132. // only if the dependency gets removed are we somewhat busted.
  3133. // Keep the registry small and simple.
  3134. if (lpclsid && IsEqualGUID(clsid, GetClsid())) {
  3135. goto PI_Exit;
  3136. }
  3137. if (lci.szExistingFileName[0])
  3138. hr= QueueModuleUsage(lci.szExistingFileName, MU_CLIENT);
  3139. goto PI_Exit;
  3140. }
  3141. }
  3142. if (g_bNT5OrGreater && !(bForceDestDir && dest == LDID_OCXCACHE))
  3143. {
  3144. if (!FileProtectionCheckSucceeded(lci.szExistingFileName))
  3145. {
  3146. hr = INET_E_CANNOT_REPLACE_SFP_FILE;
  3147. goto PI_Exit;
  3148. }
  3149. }
  3150. if (szURL[0] == '\0') {
  3151. // if not file/location is available then look to see if a
  3152. // hook is available to download/install this component.
  3153. if (GetPrivateProfileString(szCurCode, szHOOK, szDefault,
  3154. szURL, MAX_PATH, m_szInf)) {
  3155. hr = ProcessHookSection(szURL /* hook section */, pdl);
  3156. goto PI_Exit;
  3157. }
  3158. // this is a way someone can say I need this file (clsid, version)
  3159. // to run, if absent just fail the load!
  3160. hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  3161. goto PI_Exit;
  3162. }
  3163. if (lci.IsPresent() && pCodeInstall) {
  3164. // a prev ver exists. get permission to overwrite
  3165. // if ICodeInstall available
  3166. WCHAR szBuf[MAX_PATH];
  3167. MultiByteToWideChar(CP_ACP, 0,
  3168. (lci.szExistingFileName[0])?lci.szExistingFileName:szCurCode, -1, szBuf, MAX_PATH);
  3169. hr = pCodeInstall->OnCodeInstallProblem( CIP_OLDER_VERSION_EXISTS,
  3170. NULL, szBuf, 0);
  3171. // hr == E_ABORT: abort whole download
  3172. if (FAILED(hr)) {
  3173. if (hr == E_ABORT)
  3174. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  3175. // else preserve error code of OnCodeInstallProblem
  3176. goto PI_Exit;
  3177. }
  3178. }
  3179. hr = StartDownload( szCurCode, pdl, szURL,
  3180. dest, ((bForceDestDir) ? (NULL) : (lci.lpDestDir)), dwRegisterServer, dwCopyFlags);
  3181. PI_Exit:
  3182. if (SUCCEEDED(hr)) {
  3183. if (m_pCurCode)
  3184. len = lstrlen(m_pCurCode);
  3185. else
  3186. len = 0;
  3187. if (len) {
  3188. m_pCurCode += (len+1); // next
  3189. // skip side by side
  3190. while (!StrCmpI(m_pCurCode, INF_TAG_UNINSTALL_OLD)) {
  3191. len = lstrlen(m_pCurCode);
  3192. m_pCurCode += (len+1);
  3193. }
  3194. if (*m_pCurCode) {
  3195. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_PROCESS_INF,
  3196. this, (DWORD_PTR)pdl);
  3197. if (pPkt) {
  3198. hr = pPkt->Post();
  3199. } else {
  3200. hr = E_OUTOFMEMORY;
  3201. }
  3202. if (SUCCEEDED(hr))
  3203. goto Exit;
  3204. }
  3205. }
  3206. hr = ProcessHooks(pdl);
  3207. }
  3208. if (FAILED(hr)) {
  3209. m_debuglog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_PROCESSINF_FAILED,
  3210. hr, (m_pCurCode && *m_pCurCode)?m_pCurCode:"Setup Hooks");
  3211. // done with this CDownload. Mark it ready for setup
  3212. pdl->SetDLState(DLSTATE_DONE);
  3213. } else {
  3214. // done with this CDownload. Mark it ready for setup
  3215. pdl->SetDLState(DLSTATE_READY_TO_SETUP);
  3216. }
  3217. pdl->CompleteSignal(hr, S_OK, S_OK, NULL);
  3218. Exit:
  3219. DEBUG_LEAVE(0);
  3220. return;
  3221. }
  3222. // ---------------------------------------------------------------------------
  3223. // %%Function: CCodeDownload::QueueModuleUsage
  3224. // ---------------------------------------------------------------------------
  3225. HRESULT
  3226. CCodeDownload::QueueModuleUsage(
  3227. LPCSTR szFileName,
  3228. LONG muFlags)
  3229. {
  3230. DEBUG_ENTER((DBG_DOWNLOAD,
  3231. Hresult,
  3232. "CCodeDownload::QueueModuleUsage",
  3233. "this=%#x, %.80q, %#x",
  3234. this, szFileName, muFlags
  3235. ));
  3236. HRESULT hr = S_OK;
  3237. CModuleUsage *pModuleUsage = new CModuleUsage(szFileName, muFlags, &hr);
  3238. if (!pModuleUsage) {
  3239. hr = E_OUTOFMEMORY;
  3240. goto Exit;
  3241. } else if (FAILED(hr)) {
  3242. delete pModuleUsage;
  3243. goto Exit;
  3244. }
  3245. m_ModuleUsage.AddTail(pModuleUsage);
  3246. Exit:
  3247. DEBUG_LEAVE(hr);
  3248. return hr;
  3249. }
  3250. // ---------------------------------------------------------------------------
  3251. // %%Function: CCodeDownload::UpdateModuleUsage
  3252. // ---------------------------------------------------------------------------
  3253. HRESULT
  3254. CCodeDownload::UpdateModuleUsage()
  3255. {
  3256. DEBUG_ENTER((DBG_DOWNLOAD,
  3257. Hresult,
  3258. "CCodeDownload::UpdateModuleUsage",
  3259. "this=%#x",
  3260. this
  3261. ));
  3262. HRESULT hr = S_OK;
  3263. char *lpClientName = NULL;
  3264. LPOLESTR pwcsClsid = (LPOLESTR)GetMainDistUnit();
  3265. LISTPOSITION curpos;
  3266. int i, iNumClients;
  3267. CLSID myclsid;
  3268. Assert(pwcsClsid);
  3269. if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &lpClientName))))
  3270. {
  3271. goto Exit;
  3272. }
  3273. curpos = m_ModuleUsage.GetHeadPosition();
  3274. iNumClients = m_ModuleUsage.GetCount();
  3275. for (i=0; i < iNumClients; i++) {
  3276. (m_ModuleUsage.GetNext(curpos))->Update(lpClientName);
  3277. }
  3278. Exit:
  3279. if (pwcsClsid && (pwcsClsid != GetMainDistUnit()) )
  3280. delete pwcsClsid;
  3281. if (lpClientName)
  3282. delete lpClientName;
  3283. DEBUG_LEAVE(hr);
  3284. return hr;
  3285. }
  3286. // ---------------------------------------------------------------------------
  3287. // %%Function: CCodeDownload::ProcessHookSection
  3288. // ---------------------------------------------------------------------------
  3289. HRESULT
  3290. CCodeDownload::ProcessHookSection(LPCSTR lpCurHook, CDownload *pdl)
  3291. {
  3292. DEBUG_ENTER((DBG_DOWNLOAD,
  3293. Hresult,
  3294. "CCodeDownload::ProcessHookSection",
  3295. "this=%#x, %.80q, %#x",
  3296. this, lpCurHook, pdl
  3297. ));
  3298. HRESULT hr = S_OK;
  3299. char szURL[INTERNET_MAX_URL_LENGTH];
  3300. WCHAR szBuf[INTERNET_MAX_URL_LENGTH];
  3301. char szCmdLine[1024];
  3302. char szInfSection[MAX_PATH];
  3303. const static char *szINFNAME = "InfFile";
  3304. const static char *szINFSECTION = "InfSection";
  3305. const static char *szCMDLINE = "Run";
  3306. static char *szDefault = "";
  3307. DWORD flags = 0;
  3308. CDownload *pdlCur = pdl;
  3309. char *pBaseFileName = NULL;
  3310. // initialize szInfSection
  3311. szInfSection[0] = '\0';
  3312. // Get cmd line for hook if any
  3313. szCmdLine[0] = '\0';
  3314. GetPrivateProfileString(lpCurHook, szCMDLINE, szDefault,
  3315. szCmdLine, MAX_PATH, m_szInf);
  3316. if (!szCmdLine[0]) {
  3317. flags |= RSC_FLAG_INF;
  3318. // Get Inf filename if any
  3319. GetPrivateProfileString(lpCurHook, szINFNAME, szDefault,
  3320. szCmdLine, MAX_PATH, m_szInf);
  3321. // Get Inf section name if any
  3322. GetPrivateProfileString(lpCurHook, szINFSECTION, szDefault,
  3323. szInfSection, MAX_PATH, m_szInf);
  3324. }
  3325. hr = GetInfCodeLocation(lpCurHook, szURL);
  3326. if (hr != S_OK)
  3327. goto Exit;
  3328. if (szURL[0]) {
  3329. MultiByteToWideChar(CP_ACP, 0, szURL, -1, szBuf,
  3330. INTERNET_MAX_URL_LENGTH);
  3331. pdlCur = NULL;
  3332. hr = FindCABInDownloadList(szBuf, pdl, &pdlCur);
  3333. if (FAILED(hr))
  3334. goto Exit;
  3335. if (!pdlCur) {
  3336. // did not find CAB
  3337. // fresh CAB needs to get pulled down.
  3338. FILEXTN extn = ::GetExtnAndBaseFileName(szURL, &pBaseFileName);
  3339. if (extn != FILEXTN_CAB) {
  3340. hr = E_INVALIDARG;
  3341. goto Exit;
  3342. }
  3343. pdlCur = new CDownload(szBuf, extn, &hr);
  3344. if (!pdlCur) {
  3345. hr = E_OUTOFMEMORY;
  3346. }
  3347. if (FAILED(hr))
  3348. goto Exit;
  3349. AddDownloadToList(pdlCur);
  3350. {
  3351. BOOL bSetOnStack = SetOnStack();
  3352. hr = pdlCur->DoDownload(&m_pmkContext,
  3353. (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE));
  3354. if (bSetOnStack)
  3355. ResetOnStack();
  3356. }
  3357. if (FAILED(hr)) {
  3358. goto Exit;
  3359. }
  3360. }
  3361. }
  3362. if ( !szCmdLine[0] )
  3363. ::GetExtnAndBaseFileName(m_szInf, &pBaseFileName);
  3364. Assert(pdlCur);
  3365. hr = pdlCur->AddHook(lpCurHook, (szCmdLine[0])?szCmdLine:pBaseFileName,
  3366. (szInfSection[0])?szInfSection:NULL,
  3367. flags);
  3368. Exit:
  3369. DEBUG_LEAVE(hr);
  3370. return hr;
  3371. }
  3372. // ---------------------------------------------------------------------------
  3373. // %%Function: CCodeDownload::ProcessHooks
  3374. // ---------------------------------------------------------------------------
  3375. HRESULT
  3376. CCodeDownload::ProcessHooks(CDownload *pdl)
  3377. {
  3378. DEBUG_ENTER((DBG_DOWNLOAD,
  3379. Hresult,
  3380. "CCodeDownload::ProcessHooks",
  3381. "this=%#x, %#x",
  3382. this, pdl
  3383. ));
  3384. HRESULT hr = S_OK;
  3385. int nBuffSize = MAX_INF_SECTIONS_SIZE;
  3386. char lpSections[MAX_INF_SECTIONS_SIZE];
  3387. const static char *szHooksSection = "Setup Hooks";
  3388. static char *szDefault = "";
  3389. char *lpCurHook = NULL;
  3390. DWORD len;
  3391. len = GetPrivateProfileString(szHooksSection, NULL, szDefault,
  3392. lpSections, nBuffSize, m_szInf);
  3393. if (len) {
  3394. for (lpCurHook =lpSections;*lpCurHook;
  3395. lpCurHook+= (lstrlen(lpCurHook)+1)) {
  3396. hr = ProcessHookSection(lpCurHook, pdl);
  3397. if (FAILED(hr))
  3398. break;
  3399. }
  3400. } else {
  3401. hr = S_FALSE; // no hooks!
  3402. }
  3403. DEBUG_LEAVE(hr);
  3404. return hr;
  3405. }
  3406. // ---------------------------------------------------------------------------
  3407. // %%Function: CCodeDownload::Complete
  3408. // CCodeDownload::Complete is called whenever a CDownload obj completes
  3409. // its download and initiates further downloads if necessary (eg. ProcessInf)
  3410. // It does nothing until all pending downloads are complete. Until then it
  3411. // just returns and we unwind back to BSC::OnStopBinding
  3412. //
  3413. // When all downloads completed, we then start processingall the Csetups
  3414. // We do this code download in two stages to
  3415. // keep capability to back out of entire code download for as late as we can
  3416. // until the setup stage calling CClBinding::Abort with IBinding returned by
  3417. // code downloader in client's BSC::OnStartBinding will cleanly abort and
  3418. // restore initial state.
  3419. // We don't honor Abort once in setup stage.
  3420. //
  3421. // To keep this stage as clean and failsafe as we can we check for
  3422. // disk space in the OCX cache as well as check for IN USE OCXes that we
  3423. // plan on updating. We abort on either of these two conditions.
  3424. //
  3425. // CCodeDownload::Complete than proceeds to walk thru all its download objs
  3426. // calling DoSetup which in turn causes CSetup::DoSetup() to get invoked
  3427. // for every CSetup.
  3428. //
  3429. // ---------------------------------------------------------------------------
  3430. VOID
  3431. CCodeDownload::CompleteOne(CDownload *pdl, HRESULT hrOSB, HRESULT hrStatus, HRESULT hrResponseHdr, LPCWSTR szError)
  3432. {
  3433. DEBUG_ENTER((DBG_DOWNLOAD,
  3434. None,
  3435. "CCodeDownload::CompleteOne",
  3436. "this=%#x, %#x, %#x, %#x, %#x, %.80wq",
  3437. this, pdl, hrOSB, hrStatus, hrResponseHdr, szError
  3438. ));
  3439. CDownload *pdlCur = NULL;
  3440. HRESULT hr = S_OK;
  3441. HGLOBAL hPostData = NULL;
  3442. WCHAR szURL[INTERNET_MAX_URL_LENGTH];
  3443. FILEXTN extn = FILEXTN_UNKNOWN;
  3444. LPWSTR lpDownloadURL;
  3445. CDownload *pdlNew;
  3446. DWORD cbPostData = 0;
  3447. BOOL fWaitForAbortCompletion = FALSE;
  3448. LISTPOSITION curpos;
  3449. int i = 0;
  3450. m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_COMPLETEONE_IN,
  3451. hrStatus, hrOSB, hrResponseHdr, pdl->GetURL());
  3452. CUrlMkTls tls(hr); // hr passed by reference!
  3453. Assert(SUCCEEDED(hr));
  3454. if (pdl->GetDLState() != DLSTATE_READY_TO_SETUP) {
  3455. pdl->SetDLState(DLSTATE_DONE);
  3456. }
  3457. if (FAILED(hr)) {
  3458. goto Complete_failed;
  3459. }
  3460. Assert(tls->pCDLPacketMgr);
  3461. // called each time a download object is done downloading
  3462. // and installing itself
  3463. // this is the master state analyser that will determine if the total
  3464. // code download is complete and clean up if reqd
  3465. Assert(m_pDownloads.GetCount()); // atleast one (this one)
  3466. // the three HRESULTS passed in are as follows
  3467. // hrOSB = hr of OnStopBinding, ie URLMON came back with good HR
  3468. // but we had some 'processing error with the data we got back
  3469. // in such cases just assume a bad install and fail the operation. ie.
  3470. // don't go into next component of CodeSearchPath to retify such errors
  3471. if (FAILED(hrOSB)) {
  3472. hr = hrOSB;
  3473. goto Complete_failed;
  3474. }
  3475. // hrStatus = hr that URLMON came back with for the binding
  3476. // right now URLMON does a terrible job with errors. sometimes we get back
  3477. // an HTML response with a displayable error and URLMON say things
  3478. // succeeded, which is why we have our own hrResponseHdr which is the
  3479. // status as we fill in OnResponse.
  3480. // there are some URLMON errors that make sense to allow further search
  3481. // on CodeSearchPath and some others like E_ABORT, ie the
  3482. // client did an IBinding::Abort().
  3483. if (SUCCEEDED(hrResponseHdr) && SUCCEEDED(hrStatus)) {
  3484. // here if the current download was completely successful
  3485. // if all downloads are done then call DoSetup()
  3486. if (WeAreReadyToSetup()) { // more processing left?
  3487. // no, enter setup phase
  3488. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP, this, 0);
  3489. if (pPkt) {
  3490. hr = pPkt->Post();
  3491. } else {
  3492. hr = E_OUTOFMEMORY;
  3493. }
  3494. if (FAILED(hr)) {
  3495. goto Complete_failed;
  3496. }
  3497. }
  3498. goto Exit;
  3499. }
  3500. if (hrStatus == E_ABORT) {
  3501. // USER cancelled, abort entire code download
  3502. hr = hrStatus;
  3503. goto Complete_failed;
  3504. }
  3505. // here if the response header indicated a failure
  3506. // errors we know about now are if the response URL is absent and no
  3507. // suitable MIME tyoe was found or
  3508. // the resource we queried for is absent on this server
  3509. // try the next comp. on CodeSearchPath
  3510. Assert(m_pmkContext);
  3511. // if a top level req. failed wtih a HTTP error
  3512. // we need to go next on searchpath.
  3513. // we detect top level, either by the fact that it involed a POST
  3514. // or by the fact that the context moniker is the same
  3515. // moniker as the current download. By same moniker, we mean
  3516. // the same pointer (not pmk->IsEqual(), this will match for
  3517. // same URLs which is not necessarily top level)
  3518. // This check makes an assumption that we will not change the
  3519. // context moniker, excpet when redirecting a POST. if we do this is a
  3520. // BUGBUG: !!!
  3521. if (!(pdl->DoPost()) && (m_pmkContext != pdl->GetMoniker())) {
  3522. if (FAILED(hrStatus))
  3523. hr = hrStatus;
  3524. else
  3525. hr = hrResponseHdr;
  3526. goto Complete_failed;
  3527. }
  3528. // reset the context to zero, so we will set a fresh one to the next
  3529. // element on code searchpath
  3530. if (RelContextMk()) {
  3531. SAFERELEASE(m_pmkContext);
  3532. ResetNewContextMoniker();
  3533. DEBUG_PRINT(DOWNLOAD,
  3534. INFO,
  3535. ("this=%#x, Releasing m_pmkContext: %#x\n",
  3536. this, m_pmkContext
  3537. ));
  3538. } else {
  3539. m_pmkContext = NULL;
  3540. DEBUG_PRINT(DOWNLOAD,
  3541. INFO,
  3542. ("this=%#x, Setting m_pmkContext to NULL: %#x\n",
  3543. this, m_pmkContext
  3544. ));
  3545. }
  3546. // if the HTTP_ERROR was Not Modified, then this at the top level
  3547. // is not an error: ie use current version. But, we any way go past
  3548. // CODEBASE (that's the only one that can come back with Not Modified
  3549. // everything else on the searchpath is a POST) to check all
  3550. // servers on searchpath before we decide to use the current local version
  3551. hr = GetNextOnInternetSearchPath(GetClsid(), &hPostData, &cbPostData,
  3552. szURL, INTERNET_MAX_URL_LENGTH, &lpDownloadURL, &extn);
  3553. if (FAILED(hr)) {
  3554. // OK all tries failed at the top level
  3555. // were we monkeying around for the very LATEST version
  3556. // when in fact there was a local version already?
  3557. if ( NeedLatestVersion() && m_plci->IsPresent()) {
  3558. Assert(WeAreReadyToSetup());
  3559. hr = S_OK; // no, fake a success
  3560. SetFakeSuccess();
  3561. CompleteAll(hr, NULL); // and instantiate the object
  3562. goto Exit;
  3563. } else {
  3564. goto Complete_failed;
  3565. }
  3566. }
  3567. // download the CODE=URL (ie. CAB or INF file first)
  3568. pdlNew = new CDownload(lpDownloadURL, extn, &hr);
  3569. if (!pdlNew) {
  3570. hr = E_OUTOFMEMORY;
  3571. goto Complete_failed;
  3572. } else if (FAILED(hr)) {
  3573. delete pdlNew;
  3574. goto Complete_failed;
  3575. }
  3576. AddDownloadToList(pdlNew);
  3577. if (hPostData) {
  3578. pdlNew->SetPostData(hPostData, cbPostData);
  3579. hPostData = NULL; // mark as delegated, destructor for pdl will free
  3580. }
  3581. {
  3582. BOOL bSetOnStack = SetOnStack();
  3583. hr = pdlNew->DoDownload(&m_pmkContext,
  3584. (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE));
  3585. if (bSetOnStack)
  3586. ResetOnStack();
  3587. }
  3588. if (SUCCEEDED(hr)) {
  3589. // initiated a new download, return and wait for that to complete
  3590. goto Exit;
  3591. }
  3592. // error initiating new download, abort
  3593. Complete_failed:
  3594. Assert(FAILED(hr));
  3595. if (SUCCEEDED(m_hr)) {
  3596. // first failure in a multi-piece download
  3597. // save away the real reason we failed. We pass this to
  3598. // CompleteAll
  3599. m_hr = hr;
  3600. }
  3601. // problem with download
  3602. // abort all other downloads and then CompleteAll/cleanup
  3603. // to mark that atleast one real URLMON bindign was aborted
  3604. // in this case URLMON will post an OnStopBinding for that
  3605. // and we will end up aborting all other bindings and the whole
  3606. // code download. However if that's not the case then we were probably
  3607. // in some post binding processing such as verifytrust cab extraction etc
  3608. // and so we need to post a DoSetup() packet with UserCancelled flag set.
  3609. fWaitForAbortCompletion = FALSE;
  3610. curpos = m_pDownloads.GetHeadPosition();
  3611. for (i=0; !IsOnStack() && ( i < m_pDownloads.GetCount()); i++) {
  3612. pdlCur = m_pDownloads.GetNext(curpos);
  3613. if (!pdlCur->IsSignalled(this)) {
  3614. // packet processing pending for this state. we will check for
  3615. // DLSTATE_ABORT in each packet processing state and if true
  3616. // it will call CompleteOne(us), which marks each piece DLSTATE_DONE
  3617. BOOL bSetOnStack = SetOnStack();
  3618. pdlCur->Abort(this);
  3619. if (bSetOnStack)
  3620. ResetOnStack();
  3621. if (!pdlCur->IsSignalled(this)) {
  3622. fWaitForAbortCompletion = TRUE;
  3623. }
  3624. }
  3625. }
  3626. if (FAILED(m_hr)) {
  3627. // fail with first real failure of a multipart code download
  3628. hr = m_hr;
  3629. }
  3630. if (!fWaitForAbortCompletion && !IsOnStack()) // more processing left?
  3631. CompleteAll(hr, szError); // no, call complete all to cleanup
  3632. Exit:
  3633. DEBUG_LEAVE(0);
  3634. return;
  3635. }
  3636. // ---------------------------------------------------------------------------
  3637. // %%Function: CCodeDownload::WeAreReadyToSetup()
  3638. // ---------------------------------------------------------------------------
  3639. BOOL
  3640. CCodeDownload::WeAreReadyToSetup()
  3641. {
  3642. DEBUG_ENTER((DBG_DOWNLOAD,
  3643. Bool,
  3644. "CCodeDownload::WeAreReadyToSetup",
  3645. "this=%#x",
  3646. this
  3647. ));
  3648. BOOL fReady = TRUE;
  3649. CDownload *pdlCur = NULL;
  3650. LISTPOSITION curpos = m_pDownloads.GetHeadPosition();
  3651. for (int i=0; i < m_pDownloads.GetCount(); i++) {
  3652. pdlCur = m_pDownloads.GetNext(curpos);
  3653. if (! (( pdlCur->GetDLState() == DLSTATE_READY_TO_SETUP) ||
  3654. ( pdlCur->GetDLState() == DLSTATE_DONE)) ) {
  3655. fReady = FALSE;
  3656. break;
  3657. }
  3658. }
  3659. DEBUG_LEAVE(fReady);
  3660. return fReady;
  3661. }
  3662. // ---------------------------------------------------------------------------
  3663. // %%Function: CCodeDownload::ResolveCacheDirNameConflicts()
  3664. // ---------------------------------------------------------------------------
  3665. HRESULT
  3666. CCodeDownload::ResolveCacheDirNameConflicts()
  3667. {
  3668. DEBUG_ENTER((DBG_DOWNLOAD,
  3669. Bool,
  3670. "CCodeDownload::ResolveCacheDirNameConflicts",
  3671. "this=%#x",
  3672. this
  3673. ));
  3674. HRESULT hr = S_OK;
  3675. char szDir[MAX_PATH];
  3676. static char *szCONFLICT = "CONFLICT";
  3677. CDownload *pdlCur = NULL;
  3678. int n = 1;
  3679. if (m_szCacheDir) // the non-zeroness of this is also used by DoSetup
  3680. goto Exit; // to find it it's state machine has been init'ed
  3681. // ease the update of in-memory OCXes that have been released
  3682. // but still in memory as an optiization.
  3683. CoFreeUnusedLibraries();
  3684. // get a cache dir that has no name collisions for any of the
  3685. // Csetup objs for this CodeDownload
  3686. m_szCacheDir = g_szOCXCacheDir;
  3687. do {
  3688. LISTPOSITION curpos = m_pDownloads.GetHeadPosition();
  3689. for (int i=0; i < m_pDownloads.GetCount(); i++) {
  3690. pdlCur = m_pDownloads.GetNext(curpos);
  3691. if ( (hr = pdlCur->CheckForNameCollision(m_szCacheDir)) != S_OK)
  3692. break;
  3693. }
  3694. if (hr == S_OK) {
  3695. if (m_szCacheDir == g_szOCXCacheDir)
  3696. goto Exit;
  3697. else
  3698. goto Alloc_new;
  3699. }
  3700. // current m_szCacheDir did not work, try next conflict.<n> dir
  3701. wnsprintf(szDir, sizeof(szDir)-1, "%s\\%s.%d", g_szOCXCacheDir, szCONFLICT, n++);
  3702. m_szCacheDir = szDir;
  3703. } while (GetFileAttributes(szDir) != -1); // while conflict dirs exist
  3704. // none of our existing conflict dirs solved the problem
  3705. // create a new conflict dir named conflict.<n>
  3706. if (!CreateDirectory(szDir, NULL)) {
  3707. hr = HRESULT_FROM_WIN32(GetLastError());
  3708. goto Exit;
  3709. }
  3710. Alloc_new:
  3711. m_szCacheDir = new char [lstrlen(szDir)+1];
  3712. if (m_szCacheDir) {
  3713. lstrcpy(m_szCacheDir, szDir);
  3714. } else {
  3715. hr = E_OUTOFMEMORY;
  3716. }
  3717. Exit:
  3718. DEBUG_LEAVE(hr);
  3719. return hr;
  3720. }
  3721. // ---------------------------------------------------------------------------
  3722. // %%Function: CCodeDownload::DoSetup()
  3723. // Setup Phase:
  3724. // ---------------------------------------------------------------------------
  3725. VOID
  3726. CCodeDownload::DoSetup()
  3727. {
  3728. DEBUG_ENTER((DBG_DOWNLOAD,
  3729. None,
  3730. "CCodeDownload::DoSetup",
  3731. "this=%#x",
  3732. this
  3733. ));
  3734. HRESULT hr = S_OK;
  3735. CDownload *pdlCur = NULL;
  3736. int nSetupsPerCall = 0;
  3737. HRESULT hr1 = S_OK;
  3738. CUrlMkTls tls(hr1); // hr1 passed by reference!
  3739. Assert(SUCCEEDED(hr1));
  3740. Assert(tls->pCDLPacketMgr);
  3741. int i;
  3742. LISTPOSITION curpos;
  3743. if (FAILED(m_hr)) {
  3744. // the self-registering EXE failed or user cancelled waiting
  3745. // for self-registering EXE
  3746. hr = m_hr;
  3747. goto ErrorExit;
  3748. }
  3749. if (UserCancelled()) {
  3750. // user cancelled and CodeInstallProblem asked to abort
  3751. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  3752. goto ErrorExit;
  3753. }
  3754. if (IsSilentMode()) {
  3755. SetBitsInCache(); // flag that we have a new available version
  3756. hr = ERROR_IO_INCOMPLETE;
  3757. goto ErrorExit;
  3758. }
  3759. // ease the update of in-memory OCXes that have been released
  3760. // but still in memory as an optiization.
  3761. CoFreeUnusedLibraries();
  3762. if (m_bUninstallOld) {
  3763. LPSTR pPluginFileName = NULL;
  3764. CLSID myclsid = GetClsid();
  3765. CLocalComponentInfo lci;
  3766. if ((SUCCEEDED(GetClsidFromExtOrMime( GetClsid(), myclsid,
  3767. GetMainExt(), GetMainType(), &pPluginFileName)))) {
  3768. if (IsControlLocallyInstalled(pPluginFileName,
  3769. (pPluginFileName)?(LPCLSID)&GetClsid():&myclsid,
  3770. GetMainDistUnit(), 0, 0, &lci, NULL) == S_OK) {
  3771. HMODULE hMod;
  3772. CHAR *szDU = NULL;
  3773. REMOVECONTROLBYNAME pfn = NULL;
  3774. hMod = LoadLibrary("OCCACHE.DLL");
  3775. if (hMod) {
  3776. pfn = (REMOVECONTROLBYNAME)GetProcAddress(hMod, "RemoveControlByName");
  3777. if (pfn) {
  3778. if (SUCCEEDED(Unicode2Ansi(GetMainDistUnit(), &szDU))) {
  3779. (*pfn)(lci.szExistingFileName, szDU, NULL, FALSE, TRUE);
  3780. SAFEDELETE(szDU);
  3781. }
  3782. }
  3783. FreeLibrary(hMod);
  3784. }
  3785. }
  3786. }
  3787. }
  3788. hr = ResolveCacheDirNameConflicts();
  3789. if (FAILED(hr)) {
  3790. goto ErrorExit;
  3791. }
  3792. // -------- UNSAFE TO ABORT BEGIN --------------
  3793. SetUnsafeToAbort();
  3794. // we can start processing CSetup
  3795. curpos = m_pDownloads.GetHeadPosition();
  3796. for (i=0; i < m_pDownloads.GetCount(); i++) {
  3797. pdlCur = m_pDownloads.GetNext(curpos);
  3798. if ( (pdlCur->GetDLState() == DLSTATE_READY_TO_SETUP) ||
  3799. (pdlCur->GetDLState() == DLSTATE_SETUP)) {
  3800. // serialize all setups in this thread
  3801. hr = AcquireSetupCookie();
  3802. if (FAILED(hr)) {
  3803. goto ErrorExit;
  3804. } else if (hr == S_FALSE) {
  3805. goto Exit; // some other Code download on same thread
  3806. // is already in Setup phase. We will get a
  3807. // msg when its our turn
  3808. }
  3809. // acquired the setup cookie!
  3810. if (nSetupsPerCall++) {
  3811. // here if we have already done 1 setup in one
  3812. // CDownload
  3813. // post a message to ourselves and we can do the next
  3814. // setup in that. This will give a chance for our client
  3815. // to process messages.
  3816. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP,this,S_OK);
  3817. if (pPkt) {
  3818. hr = pPkt->Post();
  3819. } else {
  3820. hr = E_OUTOFMEMORY;
  3821. }
  3822. if (FAILED(hr))
  3823. break;
  3824. goto Exit;
  3825. }
  3826. if (m_bExactVersion)
  3827. {
  3828. pdlCur->SetExactVersion(TRUE);
  3829. }
  3830. hr = pdlCur->DoSetup();
  3831. if (FAILED(hr))
  3832. break;
  3833. if(WaitingForEXE()) { // Did the setup start a self-registering EXE?
  3834. // if we are waiting for an EXE to complete self registeration,
  3835. // we can't proceed unless it completes. So kick off a
  3836. // packet for waiting for the EXE to complete.
  3837. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_WAIT_FOR_EXE,
  3838. this,0);
  3839. if (pPkt) {
  3840. hr = pPkt->Post();
  3841. } else {
  3842. hr = E_OUTOFMEMORY;
  3843. }
  3844. if (FAILED(hr))
  3845. break;
  3846. goto Exit;
  3847. }
  3848. if ( (pdlCur->GetDLState() == DLSTATE_READY_TO_SETUP) ||
  3849. (pdlCur->GetDLState() == DLSTATE_SETUP)) {
  3850. // more setup work left in pdlCur
  3851. // wait to get to this and other pieces in next msg
  3852. CCDLPacket *pPkt= new CCDLPacket(CODE_DOWNLOAD_SETUP,this,S_OK);
  3853. if (pPkt) {
  3854. hr = pPkt->Post();
  3855. } else {
  3856. hr = E_OUTOFMEMORY;
  3857. }
  3858. if (FAILED(hr))
  3859. break;
  3860. goto Exit;
  3861. }
  3862. } /* if pdlCur needs setup */
  3863. } /* for each pdlCur */
  3864. ErrorExit:
  3865. hr1 = tls->pCDLPacketMgr->AbortPackets(GetDownloadHead());//aborts pdlCur, pdlCur->pcdl
  3866. Assert(SUCCEEDED(hr1));
  3867. if (FAILED(hr1)) {
  3868. hr = hr1;
  3869. }
  3870. // here when completed the setup phase
  3871. // give up the cookie and let someone else thru.
  3872. RelinquishSetupCookie();
  3873. CompleteAll(hr, NULL);
  3874. Exit:
  3875. DEBUG_LEAVE(0);
  3876. return;
  3877. // -------- NO ABORT TILL SETUP COMPLETES in COmpleteAll --------------
  3878. }
  3879. HRESULT CCodeDownload::UpdateJavaList(HKEY hkeyContains)
  3880. {
  3881. DEBUG_ENTER((DBG_DOWNLOAD,
  3882. Hresult,
  3883. "CCodeDownload::UpdateJavaList",
  3884. "this=%#x, %#x",
  3885. this, hkeyContains
  3886. ));
  3887. HRESULT hr = S_OK;
  3888. HKEY hkeyJava = 0;
  3889. LPSTR lpVersion = "";
  3890. CDownload *pdlCur = NULL;
  3891. int iNumJava = 0;
  3892. int i;
  3893. const static char *szJAVA = "Java";
  3894. LONG lResult = ERROR_SUCCESS;
  3895. // count total number of Java setups if any
  3896. LISTPOSITION curpos = m_pDownloads.GetHeadPosition();
  3897. for (i=0; i < m_pDownloads.GetCount(); i++) {
  3898. pdlCur = m_pDownloads.GetNext(curpos);
  3899. iNumJava += (pdlCur->GetJavaSetupList())->GetCount();
  3900. }
  3901. if (!iNumJava)
  3902. goto Exit;
  3903. // open/create the Contains\Java key for this dist unit.
  3904. if (RegOpenKeyEx( hkeyContains, szJAVA,
  3905. 0, KEY_ALL_ACCESS, &hkeyJava) != ERROR_SUCCESS) {
  3906. if ((lResult = RegCreateKey( hkeyContains,
  3907. szJAVA, &hkeyJava)) != ERROR_SUCCESS) {
  3908. hr = HRESULT_FROM_WIN32(lResult);
  3909. goto Exit;
  3910. }
  3911. }
  3912. curpos = m_pDownloads.GetHeadPosition();
  3913. for (i=0; i < m_pDownloads.GetCount(); i++) {
  3914. pdlCur = m_pDownloads.GetNext(curpos);
  3915. LISTPOSITION curJavapos = (pdlCur->GetJavaSetupList())->GetHeadPosition();
  3916. iNumJava = (pdlCur->GetJavaSetupList())->GetCount();
  3917. for (int j=0; j < iNumJava; j++) {
  3918. CJavaSetup *pJavaSetup = (pdlCur->GetJavaSetupList())->GetNext(curJavapos);
  3919. LPCWSTR szPkg = pJavaSetup->GetPackageName();
  3920. LPCWSTR szNameSpace = pJavaSetup->GetNameSpace();
  3921. char szPkgA[MAX_PATH];
  3922. if (szPkg)
  3923. WideCharToMultiByte(CP_ACP, 0, szPkg, -1, szPkgA,
  3924. MAX_PATH, NULL, NULL);
  3925. char szNameSpaceA[MAX_PATH];
  3926. if (szNameSpace)
  3927. WideCharToMultiByte(CP_ACP, 0, szNameSpace, -1, szNameSpaceA,
  3928. MAX_PATH, NULL, NULL);
  3929. if (szNameSpace == NULL) { // global namespace if not specified
  3930. if ( (lResult = ::RegSetValueEx(hkeyJava, szPkgA, NULL, REG_SZ,
  3931. (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
  3932. hr = HRESULT_FROM_WIN32(lResult);
  3933. goto Exit;
  3934. }
  3935. } else {
  3936. // specific namespace provided. create a key under java
  3937. // for that namespace
  3938. HKEY hkeyNameSpace = 0;
  3939. // open/create the Contains\Java\<namespace> key
  3940. if (RegOpenKeyEx( hkeyJava, szNameSpaceA,
  3941. 0, KEY_ALL_ACCESS, &hkeyNameSpace) != ERROR_SUCCESS) {
  3942. if ((lResult = RegCreateKey( hkeyJava,
  3943. szNameSpaceA, &hkeyNameSpace)) != ERROR_SUCCESS){
  3944. hr = HRESULT_FROM_WIN32(lResult);
  3945. goto Exit;
  3946. }
  3947. }
  3948. if ((lResult=RegSetValueEx(hkeyNameSpace, szPkgA, NULL, REG_SZ,
  3949. (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
  3950. hr = HRESULT_FROM_WIN32(lResult);
  3951. goto Exit;
  3952. }
  3953. if (hkeyNameSpace)
  3954. RegCloseKey(hkeyNameSpace);
  3955. }
  3956. }
  3957. }
  3958. Exit:
  3959. SAFEREGCLOSEKEY(hkeyJava);
  3960. DEBUG_LEAVE(hr);
  3961. return hr;
  3962. }
  3963. HRESULT CCodeDownload::UpdateFileList(HKEY hkeyContains)
  3964. {
  3965. DEBUG_ENTER((DBG_DOWNLOAD,
  3966. Hresult,
  3967. "CCodeDownload::UpdateFileList",
  3968. "this=%#x, %#x",
  3969. this, hkeyContains
  3970. ));
  3971. HRESULT hr = S_OK;
  3972. HKEY hkeyFiles = 0;
  3973. LPSTR lpVersion = "";
  3974. LONG lResult = ERROR_SUCCESS;
  3975. const static char * szFILES = "Files";
  3976. int iNumFiles = m_ModuleUsage.GetCount();
  3977. int i;
  3978. LISTPOSITION curpos = m_ModuleUsage.GetHeadPosition();
  3979. char szAnsiFileName[MAX_PATH];
  3980. // open/create the Contains\Files key for this dist unit.
  3981. if (RegOpenKeyEx( hkeyContains, szFILES,
  3982. 0, KEY_ALL_ACCESS, &hkeyFiles) != ERROR_SUCCESS) {
  3983. if (iNumFiles && (lResult = RegCreateKey( hkeyContains,
  3984. szFILES, &hkeyFiles)) != ERROR_SUCCESS) {
  3985. hr = HRESULT_FROM_WIN32(lResult);
  3986. goto Exit;
  3987. }
  3988. }
  3989. if ( hkeyFiles) {
  3990. int iValue = 0;
  3991. DWORD dwType = REG_SZ;
  3992. DWORD dwValueSize = MAX_PATH;
  3993. char szFileName[MAX_PATH];
  3994. while (RegEnumValue(hkeyFiles, iValue++,
  3995. szFileName, &dwValueSize, 0, &dwType, NULL, NULL) == ERROR_SUCCESS) {
  3996. dwValueSize = MAX_PATH; // reset
  3997. if (GetFileAttributes(szFileName) == -1) {
  3998. // if file is not physically present then clear out our
  3999. // database. This is typically so, when you update
  4000. // on older version with a newer version, but deleted the
  4001. // old copy before installing the new one + changed the file
  4002. // names or location.
  4003. iValue = 0;
  4004. RegDeleteValue(hkeyFiles, szFileName);
  4005. }
  4006. }
  4007. }
  4008. for (i=0; i < iNumFiles; i++) {
  4009. LPCSTR szFileName = (m_ModuleUsage.GetNext(curpos))->GetFileName();
  4010. char szShortFileName[MAX_PATH];
  4011. #ifdef SHORTEN
  4012. if (!GetShortPathName(szFileName, szShortFileName, MAX_PATH)) {
  4013. hr = HRESULT_FROM_WIN32(GetLastError());
  4014. goto Exit;
  4015. }
  4016. #else
  4017. StrNCpy(szShortFileName, szFileName, MAX_PATH);
  4018. #endif
  4019. // Under Win95 (and ONLY Win95), Setup API will convert characters
  4020. // from the OEM code page to the ANSI code page. The codebase we have
  4021. // is in the OEM codepage. After the Setup API installed the file,
  4022. // the installed file name is in ANSI. Therefore, in the enumeration,
  4023. // we need to look for the ANSI file name. Under other platforms,
  4024. // this just works, and converting to the ANSI code page should not
  4025. // be done. See IE5 RAID #34606 for more details.
  4026. if (g_bRunOnWin95) {
  4027. OemToCharBuff(szShortFileName, szAnsiFileName, sizeof(szAnsiFileName) / sizeof(szAnsiFileName[0]));
  4028. StrNCpy(szShortFileName, szAnsiFileName, MAX_PATH);
  4029. }
  4030. if ( (lResult = ::RegSetValueEx(hkeyFiles, szShortFileName, NULL, REG_SZ,
  4031. (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
  4032. hr = HRESULT_FROM_WIN32(lResult);
  4033. goto Exit;
  4034. }
  4035. }
  4036. Exit:
  4037. SAFEREGCLOSEKEY(hkeyFiles);
  4038. DEBUG_LEAVE(hr);
  4039. return hr;
  4040. }
  4041. HRESULT CCodeDownload::UpdateDependencyList(HKEY hkeyContains)
  4042. {
  4043. DEBUG_ENTER((DBG_DOWNLOAD,
  4044. Hresult,
  4045. "CCodeDownload::UpdateDependencyList",
  4046. "this=%#x, %#x",
  4047. this, hkeyContains
  4048. ));
  4049. HRESULT hr = S_OK;
  4050. HKEY hkeyDU = 0;
  4051. LPSTR lpVersion = "";
  4052. LONG lResult = ERROR_SUCCESS;
  4053. const static char * szDU = "Distribution Units";
  4054. int iNumFiles;
  4055. int i;
  4056. LISTPOSITION curpos;
  4057. BOOL fFirstDependency = TRUE;
  4058. LPWSTR wszDistUnit = NULL;
  4059. LPSTR szDistUnit = NULL;
  4060. iNumFiles = m_pDownloads.GetCount();
  4061. curpos = m_pDownloads.GetHeadPosition();
  4062. RegDeleteKey(hkeyContains, szDU); // delete old version dependencies
  4063. for (i=0; i < iNumFiles; i++) {
  4064. CDownload *pdl = m_pDownloads.GetNext(curpos);
  4065. if (pdl->UsingCdlProtocol() && pdl->GetDLState() == DLSTATE_DONE) {
  4066. AddDistUnitList(pdl->GetDistUnitName());
  4067. }
  4068. }
  4069. iNumFiles = m_pDependencies.GetCount();
  4070. curpos = m_pDependencies.GetHeadPosition();
  4071. if (!iNumFiles)
  4072. goto Exit;
  4073. for (i=0; i < iNumFiles; i++) {
  4074. wszDistUnit = m_pDependencies.GetNext(curpos);
  4075. if (wszDistUnit) {
  4076. SAFEDELETE(szDistUnit);
  4077. if (FAILED(Unicode2Ansi(wszDistUnit, &szDistUnit))) {
  4078. hr = S_OK;
  4079. goto Exit;
  4080. }
  4081. if (fFirstDependency) {
  4082. if ((lResult = RegCreateKey( hkeyContains,
  4083. szDU, &hkeyDU)) != ERROR_SUCCESS) {
  4084. hr = HRESULT_FROM_WIN32(lResult);
  4085. goto Exit;
  4086. }
  4087. fFirstDependency = FALSE;
  4088. }
  4089. if ( (lResult = ::RegSetValueEx(hkeyDU, szDistUnit, NULL, REG_SZ,
  4090. (unsigned char *)lpVersion, 1)) != ERROR_SUCCESS) {
  4091. hr = HRESULT_FROM_WIN32(lResult);
  4092. goto Exit;
  4093. }
  4094. }
  4095. }
  4096. Exit:
  4097. SAFEREGCLOSEKEY(hkeyDU);
  4098. SAFEDELETE(szDistUnit);
  4099. DEBUG_LEAVE(hr);
  4100. return hr;
  4101. }
  4102. // ---------------------------------------------------------------------------
  4103. // %%Function: CCodeDownload::UpdateLanguageCheck()
  4104. // ---------------------------------------------------------------------------
  4105. HRESULT
  4106. CCodeDownload::UpdateLanguageCheck(CLocalComponentInfo *plci)
  4107. {
  4108. DEBUG_ENTER((DBG_DOWNLOAD,
  4109. Hresult,
  4110. "CCodeDownload::UpdateLanguageCheck",
  4111. "this=%#x, %#x",
  4112. this, plci
  4113. ));
  4114. HRESULT hr = S_OK;
  4115. BOOL bNullClsid = IsEqualGUID(GetClsid() , CLSID_NULL);
  4116. HKEY hkeyCheckPeriod = 0;
  4117. HKEY hkeyClsid = 0;
  4118. HKEY hkeyEmbedding = 0;
  4119. LPOLESTR pwcsClsid = NULL;
  4120. DWORD dwType;
  4121. LONG lResult = ERROR_SUCCESS;
  4122. LPSTR pszClsid = NULL;
  4123. FILETIME ftnow;
  4124. SYSTEMTIME st;
  4125. const char *szCHECKPERIOD = "LanguageCheckPeriod";
  4126. const char *szLASTCHECKEDHI = "LastCheckedHi";
  4127. if (bNullClsid)
  4128. goto Exit;
  4129. // return if we can't get a valid string representation of the CLSID
  4130. if (FAILED((hr=StringFromCLSID(GetClsid(), &pwcsClsid))))
  4131. goto Exit;
  4132. Assert(pwcsClsid != NULL);
  4133. // Open root HKEY_CLASSES_ROOT\CLSID key
  4134. lResult = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hkeyClsid);
  4135. if (lResult == ERROR_SUCCESS)
  4136. {
  4137. if (FAILED((hr=::Unicode2Ansi(pwcsClsid, &pszClsid))))
  4138. {
  4139. goto Exit;
  4140. }
  4141. // Open the key for this embedding:
  4142. lResult = ::RegOpenKeyEx(hkeyClsid, pszClsid, 0, KEY_ALL_ACCESS,
  4143. &hkeyEmbedding);
  4144. if (lResult == ERROR_SUCCESS) {
  4145. if ((lResult = RegOpenKeyEx( hkeyEmbedding, szCHECKPERIOD,
  4146. 0, KEY_ALL_ACCESS, &hkeyCheckPeriod)) != ERROR_SUCCESS) {
  4147. if ((lResult = RegCreateKey( hkeyEmbedding,
  4148. szCHECKPERIOD, &hkeyCheckPeriod)) != ERROR_SUCCESS) {
  4149. hr = HRESULT_FROM_WIN32(lResult);
  4150. goto Exit;
  4151. }
  4152. }
  4153. GetSystemTime(&st);
  4154. SystemTimeToFileTime(&st, &ftnow);
  4155. RegSetValueEx(hkeyCheckPeriod, szLASTCHECKEDHI, NULL, REG_DWORD,
  4156. (unsigned char *)&ftnow.dwHighDateTime, sizeof(DWORD));
  4157. }
  4158. }
  4159. Exit:
  4160. SAFEDELETE(pwcsClsid);
  4161. SAFEDELETE (pszClsid);
  4162. SAFEREGCLOSEKEY (hkeyClsid);
  4163. SAFEREGCLOSEKEY (hkeyEmbedding);
  4164. SAFEREGCLOSEKEY (hkeyCheckPeriod);
  4165. DEBUG_LEAVE(hr);
  4166. return hr;
  4167. }
  4168. // ---------------------------------------------------------------------------
  4169. // %%Function: CCodeDownload::UpdateDistUnit()
  4170. // Add proper entries to the registry and register control to
  4171. // WebCheck so that control gets updated periodically.
  4172. // ---------------------------------------------------------------------------
  4173. HRESULT
  4174. CCodeDownload::UpdateDistUnit(CLocalComponentInfo *plci)
  4175. {
  4176. DEBUG_ENTER((DBG_DOWNLOAD,
  4177. Hresult,
  4178. "CCodeDownload::UpdateDistUnit",
  4179. "this=%#x, %#x",
  4180. this, plci
  4181. ));
  4182. HRESULT hr = S_OK;
  4183. LONG lResult = ERROR_SUCCESS;
  4184. HKEY hkeyDist =0;
  4185. HKEY hkeyThisDist = 0;
  4186. HKEY hkeyDownloadInfo = 0;
  4187. HKEY hkeyContains = 0;
  4188. HKEY hkeyVersion = 0;
  4189. const static char * szInstalledVersion = "InstalledVersion";
  4190. const static char * szAvailableVersion = "AvailableVersion";
  4191. const static char * szDownloadInfo = "DownloadInformation";
  4192. const static char * szCODEBASE = "CODEBASE";
  4193. const static char * szContains = "Contains";
  4194. const static char * szLOCALINF = "INF";
  4195. const static char * szLOCALOSD = "OSD";
  4196. const static char * szLASTMODIFIED = "LastModified";
  4197. const static char * szETAG = "Etag";
  4198. const static char * szINSTALLER = "Installer";
  4199. const static char * szExpire = "Expire";
  4200. const static char * szMSICD = "MSICD";
  4201. const static char * szPrecache = "Precache";
  4202. const static char * szSYSTEM = "SystemComponent";
  4203. LPSTR pszDist = NULL;
  4204. LPSTR pszURL = NULL;
  4205. LPWSTR pwszURL = NULL;
  4206. char szVersionBuf[MAX_PATH];
  4207. DWORD dwExpire;
  4208. if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_DIST_UNITS,
  4209. 0, KEY_ALL_ACCESS, &hkeyDist)) != ERROR_SUCCESS) {
  4210. if ((lResult = RegCreateKey( HKEY_LOCAL_MACHINE,
  4211. REGSTR_PATH_DIST_UNITS, &hkeyDist)) != ERROR_SUCCESS) {
  4212. hr = HRESULT_FROM_WIN32(lResult);
  4213. goto Exit;
  4214. }
  4215. }
  4216. if (FAILED((hr=::Unicode2Ansi(m_szDistUnit, &pszDist))))
  4217. {
  4218. goto Exit;
  4219. }
  4220. if(GetContextMoniker()) {
  4221. if (SUCCEEDED(hr = GetContextMoniker()->GetDisplayName(NULL, NULL, &pwszURL))) {
  4222. hr = Unicode2Ansi( pwszURL, &pszURL);
  4223. }
  4224. if (FAILED(hr)) {
  4225. goto Exit;
  4226. }
  4227. }
  4228. // open/create the dist unit key for this dist unit.
  4229. if (RegOpenKeyEx( hkeyDist, pszDist,
  4230. 0, KEY_ALL_ACCESS, &hkeyThisDist) != ERROR_SUCCESS) {
  4231. if ((lResult = RegCreateKey( hkeyDist,
  4232. pszDist, &hkeyThisDist)) != ERROR_SUCCESS) {
  4233. hr = HRESULT_FROM_WIN32(lResult);
  4234. goto Exit;
  4235. }
  4236. }
  4237. if (m_szDisplayName &&
  4238. ((lResult = ::RegSetValueEx(hkeyThisDist, NULL, NULL, REG_SZ,
  4239. (unsigned char *)m_szDisplayName,
  4240. lstrlen(m_szDisplayName)+1)) != ERROR_SUCCESS)){
  4241. hr = HRESULT_FROM_WIN32(lResult);
  4242. goto Exit;
  4243. }
  4244. lResult = ::RegSetValueEx(hkeyThisDist, szSYSTEM, NULL, REG_DWORD,
  4245. (unsigned char *)&m_dwSystemComponent,
  4246. sizeof(DWORD));
  4247. if (lResult != ERROR_SUCCESS) {
  4248. hr = HRESULT_FROM_WIN32(lResult);
  4249. goto Exit;
  4250. }
  4251. lResult = ::RegSetValueEx(hkeyThisDist, szINSTALLER, NULL, REG_SZ,
  4252. (unsigned char *)szMSICD, sizeof(szMSICD)+1);
  4253. if (lResult != ERROR_SUCCESS) {
  4254. hr = HRESULT_FROM_WIN32(lResult);
  4255. goto Exit;
  4256. }
  4257. // if the OSD told us an expire interval, or the PE specifies it.
  4258. if ( m_dwExpire != 0xFFFFFFFF ||
  4259. (plci->szExistingFileName[0] &&
  4260. WantsAutoExpire( plci->szExistingFileName, &m_dwExpire )) ) {
  4261. lResult = ::RegSetValueEx(hkeyThisDist, szExpire, NULL, REG_DWORD,
  4262. (unsigned char *)&m_dwExpire, sizeof(DWORD));
  4263. if (lResult != ERROR_SUCCESS) {
  4264. hr = HRESULT_FROM_WIN32(lResult);
  4265. goto Exit;
  4266. }
  4267. }
  4268. // open/create the download info key for this dist unit.
  4269. if (RegOpenKeyEx( hkeyThisDist, szDownloadInfo,
  4270. 0, KEY_ALL_ACCESS, &hkeyDownloadInfo) != ERROR_SUCCESS) {
  4271. if ((lResult = RegCreateKey( hkeyThisDist,
  4272. szDownloadInfo, &hkeyDownloadInfo)) != ERROR_SUCCESS) {
  4273. hr = HRESULT_FROM_WIN32(lResult);
  4274. goto Exit;
  4275. }
  4276. }
  4277. // set download info params
  4278. if (pszURL && (lResult = ::RegSetValueEx(hkeyDownloadInfo, szCODEBASE,
  4279. NULL, REG_SZ, (unsigned char *)pszURL, lstrlen(pszURL)+1)) != ERROR_SUCCESS) {
  4280. hr = HRESULT_FROM_WIN32(lResult);
  4281. goto Exit;
  4282. }
  4283. if (!BitsInCache()) {
  4284. char szOldManifest[MAX_PATH];
  4285. DWORD Size = MAX_PATH;
  4286. DWORD dwType;
  4287. DWORD lResult = ::RegQueryValueEx(hkeyDownloadInfo, szLOCALINF, NULL, &dwType,
  4288. (unsigned char *)szOldManifest, &Size);
  4289. if (lResult == ERROR_SUCCESS) {
  4290. if (!(GetMainInf() && (lstrcmpi(GetMainInf(), szOldManifest) == 0)) ) {
  4291. // there is an old entry, clean up the entry and also the file
  4292. // before upgrading to newer version
  4293. DeleteFile(szOldManifest);
  4294. if (!GetMainInf())
  4295. RegDeleteValue(hkeyDownloadInfo, szLOCALINF);
  4296. }
  4297. }
  4298. Size = MAX_PATH;
  4299. lResult = ::RegQueryValueEx(hkeyDownloadInfo, szLOCALOSD, NULL, &dwType,
  4300. (unsigned char *)szOldManifest, &Size);
  4301. if (lResult == ERROR_SUCCESS) {
  4302. if (!(GetOSD() && (lstrcmpi(GetOSD(), szOldManifest) == 0)) ) {
  4303. // there is an old entry, clean up the entry and also the file
  4304. // before upgrading to newer version
  4305. DeleteFile(szOldManifest);
  4306. if (!GetOSD())
  4307. RegDeleteValue(hkeyDownloadInfo, szLOCALOSD);
  4308. }
  4309. }
  4310. if (GetOSD() && (lResult = ::RegSetValueEx(hkeyDownloadInfo,
  4311. szLOCALOSD, NULL, REG_SZ, (unsigned char *)GetOSD(), lstrlen(GetOSD())+1)) != ERROR_SUCCESS) {
  4312. hr = HRESULT_FROM_WIN32(lResult);
  4313. goto Exit;
  4314. }
  4315. if (GetMainInf() && (lResult = ::RegSetValueEx(hkeyDownloadInfo,
  4316. szLOCALINF, NULL, REG_SZ, (unsigned char *)GetMainInf(), lstrlen(GetMainInf())+1)) != ERROR_SUCCESS) {
  4317. hr = HRESULT_FROM_WIN32(lResult);
  4318. goto Exit;
  4319. }
  4320. }
  4321. // end set download info params
  4322. if (!VersionFromManifest(szVersionBuf, sizeof(szVersionBuf))) {
  4323. if (!BitsInCache()) {
  4324. if (!plci->IsPresent()) {
  4325. // This used to be an E_UNEXPECTED case. Still unexpected,
  4326. // but we'll trace it and cope with it.
  4327. m_debuglog->DebugOut(DEB_CODEDL, FALSE,
  4328. ID_CDLDBG_DL_UPDATE_DU_NO_VERS,
  4329. plci->szExistingFileName);
  4330. plci->dwLocFVLS = 1;
  4331. }
  4332. wsprintf(szVersionBuf, "%d,%d,%d,%d",
  4333. (plci->dwLocFVMS & 0xffff0000)>>16,
  4334. (plci->dwLocFVMS & 0xffff),
  4335. (plci->dwLocFVLS & 0xffff0000)>>16,
  4336. (plci->dwLocFVLS & 0xffff));
  4337. } else {
  4338. // use the version number in the HTML or
  4339. // the one called by the code download delivery agent
  4340. // if present
  4341. if (m_dwFileVersionMS | m_dwFileVersionLS) {
  4342. wsprintf(szVersionBuf, "%d,%d,%d,%d",
  4343. (m_dwFileVersionMS & 0xffff0000)>>16,
  4344. (m_dwFileVersionMS & 0xffff),
  4345. (m_dwFileVersionLS & 0xffff0000)>>16,
  4346. (m_dwFileVersionLS & 0xffff));
  4347. } else {
  4348. lstrcpy(szVersionBuf, "-1,-1,-1,-1");
  4349. }
  4350. }
  4351. }
  4352. if (BitsInCache()) {
  4353. if (RegOpenKeyEx( hkeyThisDist, szAvailableVersion,
  4354. 0, KEY_ALL_ACCESS, &hkeyVersion) != ERROR_SUCCESS) {
  4355. if ((lResult = RegCreateKey( hkeyThisDist,
  4356. szAvailableVersion, &hkeyVersion)) != ERROR_SUCCESS) {
  4357. hr = HRESULT_FROM_WIN32(lResult);
  4358. goto Exit;
  4359. }
  4360. }
  4361. // record result of caching bits.
  4362. HRESULT hrRecord = m_hr;
  4363. if (m_hr == TRUST_E_FAIL ||
  4364. m_hr == TRUST_E_SUBJECT_NOT_TRUSTED)
  4365. {
  4366. hrRecord = ERROR_IO_INCOMPLETE;
  4367. }
  4368. lResult = ::RegSetValueEx(hkeyVersion, szPrecache, NULL, REG_DWORD,
  4369. (unsigned char *)&hrRecord, sizeof(DWORD));
  4370. if (lResult != ERROR_SUCCESS) {
  4371. hr = HRESULT_FROM_WIN32(lResult);
  4372. goto Exit;
  4373. }
  4374. } else {
  4375. if (RegOpenKeyEx( hkeyThisDist, szInstalledVersion,
  4376. 0, KEY_ALL_ACCESS, &hkeyVersion) != ERROR_SUCCESS) {
  4377. if ((lResult = RegCreateKey( hkeyThisDist,
  4378. szInstalledVersion, &hkeyVersion)) != ERROR_SUCCESS) {
  4379. hr = HRESULT_FROM_WIN32(lResult);
  4380. goto Exit;
  4381. }
  4382. }
  4383. // when we install a real version take out the
  4384. // AvailableVersion key if one exists
  4385. RegDeleteKey(hkeyThisDist, szAvailableVersion);
  4386. }
  4387. lResult = ::RegSetValueEx(hkeyVersion, NULL, NULL, REG_SZ,
  4388. (unsigned char *)szVersionBuf, lstrlen(szVersionBuf)+1);
  4389. if (lResult != ERROR_SUCCESS) {
  4390. hr = HRESULT_FROM_WIN32(lResult);
  4391. goto Exit;
  4392. }
  4393. if (BitsInCache()) { // in silent mode the control is not
  4394. // installed and so the below params to
  4395. // the dist unit are not relevant.
  4396. goto Exit;
  4397. }
  4398. if (GetLastMod() && (lResult = ::RegSetValueEx(hkeyVersion,
  4399. szLASTMODIFIED, NULL, REG_SZ, (unsigned char *)GetLastMod(), lstrlen(GetLastMod())+1)) != ERROR_SUCCESS) {
  4400. hr = HRESULT_FROM_WIN32(lResult);
  4401. goto Exit;
  4402. }
  4403. if (GetEtag() && (lResult = ::RegSetValueEx(hkeyVersion,
  4404. szETAG, NULL, REG_SZ, (unsigned char *)GetEtag(), lstrlen(GetEtag())+1)) != ERROR_SUCCESS) {
  4405. hr = HRESULT_FROM_WIN32(lResult);
  4406. goto Exit;
  4407. }
  4408. // store dist unit dependencies
  4409. // store the dist unit files, pkgs installed
  4410. // save away the manifest location/name
  4411. // open/create the Contains key for this dist unit.
  4412. if (RegOpenKeyEx( hkeyThisDist, szContains,
  4413. 0, KEY_ALL_ACCESS, &hkeyContains) != ERROR_SUCCESS) {
  4414. if ((lResult = RegCreateKey( hkeyThisDist,
  4415. szContains, &hkeyContains)) != ERROR_SUCCESS) {
  4416. hr = HRESULT_FROM_WIN32(lResult);
  4417. goto Exit;
  4418. }
  4419. }
  4420. hr = UpdateFileList(hkeyContains);
  4421. if (SUCCEEDED(hr))
  4422. hr = UpdateDependencyList(hkeyContains);
  4423. if (SUCCEEDED(hr))
  4424. hr = UpdateJavaList(hkeyContains);
  4425. Exit:
  4426. SAFEDELETE(pszDist);
  4427. SAFEDELETE(pszURL);
  4428. SAFEDELETE(pwszURL);
  4429. SAFEREGCLOSEKEY(hkeyContains);
  4430. SAFEREGCLOSEKEY(hkeyDownloadInfo);
  4431. SAFEREGCLOSEKEY(hkeyVersion);
  4432. SAFEREGCLOSEKEY(hkeyDist);
  4433. SAFEREGCLOSEKEY(hkeyThisDist);
  4434. DEBUG_LEAVE(hr);
  4435. return hr;
  4436. }
  4437. typedef BOOL (WINAPI *SHRESTARTDIALOG)( HWND, LPTSTR, DWORD );
  4438. HRESULT DoReboot(HWND hWndParent)
  4439. {
  4440. DEBUG_ENTER((DBG_DOWNLOAD,
  4441. Hresult,
  4442. "DoReboot",
  4443. "%#x",
  4444. hWndParent
  4445. ));
  4446. HRESULT hr = S_OK;
  4447. HINSTANCE hShell32Lib;
  4448. #define SHRESTARTDIALOG_ORDINAL 59 // restart only exported by ordinal
  4449. SHRESTARTDIALOG pfSHRESTARTDIALOG = NULL;
  4450. if ( ( hShell32Lib = LoadLibrary( "shell32.dll" ) ) != NULL ) {
  4451. if ( !( pfSHRESTARTDIALOG = (SHRESTARTDIALOG)
  4452. GetProcAddress( hShell32Lib, MAKEINTRESOURCE(SHRESTARTDIALOG_ORDINAL)) ) ) {
  4453. hr = HRESULT_FROM_WIN32(GetLastError());
  4454. } else {
  4455. pfSHRESTARTDIALOG(hWndParent, NULL, EWX_REBOOT);
  4456. }
  4457. } else {
  4458. hr = HRESULT_FROM_WIN32(GetLastError());
  4459. }
  4460. if (hShell32Lib)
  4461. FreeLibrary( hShell32Lib );
  4462. DEBUG_LEAVE(hr);
  4463. return hr;
  4464. }
  4465. // ---------------------------------------------------------------------------
  4466. // %%Function: CCodeDownload::CompleteAll(HRESULT hr, LPCWSTR szError)
  4467. // All code is installed. If code install was succesful instantiate
  4468. // object if reqd, and report ClientBSC::OnStopBinding.
  4469. // ---------------------------------------------------------------------------
  4470. VOID
  4471. CCodeDownload::CompleteAll(HRESULT hr, LPCWSTR szError)
  4472. {
  4473. DEBUG_ENTER((DBG_DOWNLOAD,
  4474. None,
  4475. "CCodeDownload::CompleteAll",
  4476. "this=%#x, %#x, %.80wq",
  4477. this, hr, szError
  4478. ));
  4479. char szCacheFileName[MAX_PATH];
  4480. HRESULT hrTls = S_OK;
  4481. LISTPOSITION curpos;
  4482. int iNumClients;
  4483. int i;
  4484. // TCHAR szBuffer[MAX_FORMAT_MESSAGE_BUFFER_LEN];
  4485. LPTSTR szBuffer = NULL;
  4486. DWORD dwFMResult = 0;
  4487. BOOL bForceWriteLog = FALSE;
  4488. TCHAR szDll[MAX_PATH];
  4489. BOOL bLogGenOk = FALSE;
  4490. OSVERSIONINFO osvi;
  4491. WCHAR *pwszOSBErrMsg = NULL;
  4492. char *pszExactErrMsg = NULL;
  4493. char szDPFPath[MAX_PATH];
  4494. Assert(GetState() != CDL_Completed);
  4495. SetState(CDL_Completed);
  4496. CUrlMkTls tls(hrTls); // hr passed by reference!
  4497. if (FAILED(hrTls)) {
  4498. hr = hrTls;
  4499. }
  4500. // get the installed version one more time
  4501. // to store in the dist unit db
  4502. CLocalComponentInfo lci;
  4503. LPSTR pPluginFileName = NULL;
  4504. CLSID myclsid = GetClsid();
  4505. if ((SUCCEEDED(GetClsidFromExtOrMime( GetClsid(), myclsid,
  4506. GetMainExt(), GetMainType(), &pPluginFileName)))) {
  4507. // get current version, pass 0, 1 to goose IsControl
  4508. // into filling in the version data, otherwise UpdateDistUnit
  4509. // will put a funny version in the registry ( which is better
  4510. // than bug 12081
  4511. //BUGBUG: make sure this call does the right things with zero impact
  4512. IsControlLocallyInstalled(pPluginFileName,
  4513. (pPluginFileName)?(LPCLSID)&GetClsid():&myclsid, GetMainDistUnit(),
  4514. 0, 1, &lci, NULL);
  4515. }
  4516. if ( m_plci->bForceLangGetLatest ||
  4517. (lci.bForceLangGetLatest && SUCCEEDED(hr)) ) {
  4518. hr = UpdateLanguageCheck(&lci);
  4519. }
  4520. if (SUCCEEDED(hr) && hr != ERROR_IO_INCOMPLETE)
  4521. {
  4522. // update all the queued up ModuleUsage records
  4523. // we need to also remap to get the main clsid
  4524. // incase we didn't have one to begin with
  4525. UpdateModuleUsage();
  4526. }
  4527. if ( !FakeSuccess() && (SUCCEEDED(hr) || BitsInCache())) {
  4528. UpdateDistUnit(&lci);
  4529. }
  4530. if (NeedToReboot()) {
  4531. HWND hWnd = GetClientBinding()->GetHWND();
  4532. // pass a notification to reboot
  4533. if (hWnd != INVALID_HANDLE_VALUE) {
  4534. // g_RunSetupHook.DoReboot(hWnd, TRUE);
  4535. DoReboot(hWnd);
  4536. } else {
  4537. ICodeInstall* pCodeInstall = GetICodeInstall();
  4538. if (pCodeInstall)
  4539. pCodeInstall->OnCodeInstallProblem( CIP_NEED_REBOOT, NULL, NULL, 0);
  4540. }
  4541. }
  4542. iNumClients = m_pClientbinding.GetCount();
  4543. // if called from CoGetClassFromURL we need to report
  4544. // ClientBSC::OnObjectAvailable with requested obj
  4545. if (SUCCEEDED(hr) && NeedObject() && hr != ERROR_IO_INCOMPLETE) {
  4546. curpos = m_pClientbinding.GetHeadPosition();
  4547. for (i=0; i < iNumClients; i++) {
  4548. hr = (m_pClientbinding.GetNext(curpos))->InstantiateObjectAndReport(this);
  4549. if(FAILED(hr)) {
  4550. bLogGenOk = GenerateErrStrings(hr, &pszExactErrMsg, &pwszOSBErrMsg);
  4551. if (!bLogGenOk) {
  4552. pwszOSBErrMsg = NULL;
  4553. pszExactErrMsg = NULL;
  4554. }
  4555. }
  4556. }
  4557. } else {
  4558. // call OnStopBinding for all BSCs (since we either do not need
  4559. // an instantiated object or we don't have one to give)
  4560. if(FAILED(hr)) {
  4561. bLogGenOk = GenerateErrStrings(hr, &pszExactErrMsg, &pwszOSBErrMsg);
  4562. if (!bLogGenOk) {
  4563. pwszOSBErrMsg = NULL;
  4564. pszExactErrMsg = NULL;
  4565. }
  4566. }
  4567. // call client's onstopbinding
  4568. curpos = m_pClientbinding.GetHeadPosition();
  4569. for (i=0; i < iNumClients; i++) {
  4570. ((m_pClientbinding.GetNext(curpos))->GetAssBSC())->
  4571. OnStopBinding(hr, pwszOSBErrMsg);
  4572. }
  4573. SAFEDELETE(pwszOSBErrMsg);
  4574. m_debuglog->DebugOut(DEB_CODEDL, hr != S_OK, ID_CDLDBG_ONSTOPBINDING_CALLED,
  4575. hr, (hr == S_OK)?TEXT(" (SUCCESS)"):TEXT(" (FAILED)"),
  4576. (GetClsid()).Data1, GetMainURL(), GetMainType(),
  4577. GetMainExt());
  4578. }
  4579. if (m_hKeySearchPath) {
  4580. if (RegQueryValueEx(m_hKeySearchPath,"ForceCodeDownloadLog", NULL, NULL,
  4581. NULL, NULL) == ERROR_SUCCESS)
  4582. bForceWriteLog = TRUE;
  4583. }
  4584. if (bForceWriteLog || (hr != S_OK && hr != ERROR_IO_INCOMPLETE)) {
  4585. // BUGBUG: move these into .rc
  4586. if (!bLogGenOk && (HRESULT_FACILITY(hr) == FACILITY_CERT)) {
  4587. DumpDebugLog(szCacheFileName, "Trust verification failed!!", hr);
  4588. } else if (!bLogGenOk &&
  4589. (hr==HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH))) {
  4590. DumpDebugLog(szCacheFileName,
  4591. "Incompatible Binary for your platform", hr);
  4592. } else if (bLogGenOk) {
  4593. DumpDebugLog(szCacheFileName, pszExactErrMsg, hr);
  4594. } else {
  4595. DumpDebugLog(szCacheFileName, "Unknown Error!!", hr);
  4596. }
  4597. }
  4598. // Refresh OCCACHE
  4599. // Only do this for NT for now. For some reason under Win95, sending
  4600. // this message here will cause a crash in SHELL32.DLL.
  4601. osvi.dwOSVersionInfoSize = sizeof(osvi);
  4602. GetVersionEx(&osvi);
  4603. if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && m_szCacheDir) {
  4604. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, m_szCacheDir, 0);
  4605. }
  4606. // free all memory and clean up temp files
  4607. SAFEDELETE(pszExactErrMsg);
  4608. Release();
  4609. DEBUG_LEAVE(0);
  4610. return;
  4611. // -------- END OF UNSAFE TO ABORT --------------
  4612. }
  4613. // ---------------------------------------------------------------------------
  4614. // %%Function: CCodeDownload::GenerateErrStrings()
  4615. // Parameters:
  4616. // ppszErrMsg: Saved error message or result of FormatMessage
  4617. // pwszError: Error message to pass back as szError in OSB
  4618. // hr: HRESULT of binding operation
  4619. // Returns:
  4620. // TRUE if successful
  4621. // ---------------------------------------------------------------------------
  4622. BOOL CCodeDownload::GenerateErrStrings(HRESULT hr, char **ppszErrMsg,
  4623. WCHAR **ppwszError)
  4624. {
  4625. DEBUG_ENTER((DBG_DOWNLOAD,
  4626. Bool,
  4627. "CCodeDownload::GenerateErrStrings",
  4628. "this=%#x, %#x, %#x, %#x",
  4629. this, hr, ppszErrMsg, ppwszError
  4630. ));
  4631. DWORD dwFMResult;
  4632. LPCTSTR pszSavedErrMsg = NULL;
  4633. TCHAR *szBuf = NULL;
  4634. char *szURL = NULL;
  4635. char *pszErrorMessage = NULL;
  4636. char szErrString[MAX_DEBUG_STRING_LENGTH];
  4637. char szDetails[MAX_DEBUG_STRING_LENGTH];
  4638. int iSize = 0;
  4639. if (!ppszErrMsg || !ppwszError) {
  4640. dwFMResult = FALSE;
  4641. goto Exit;
  4642. }
  4643. // Get a saved error message if available
  4644. dwFMResult = FALSE;
  4645. pszSavedErrMsg = CDLDebugLog::GetSavedMessage();
  4646. if (pszSavedErrMsg[0] != '\0') {
  4647. *ppszErrMsg = new char[lstrlen(pszSavedErrMsg) + 1];
  4648. if (!*ppszErrMsg) {
  4649. dwFMResult = FALSE;
  4650. goto Exit;
  4651. }
  4652. lstrcpy(*ppszErrMsg, pszSavedErrMsg);
  4653. dwFMResult = TRUE;
  4654. }
  4655. if (!dwFMResult) {
  4656. // We don't have a saved message we can use. Try calling
  4657. // FormatMessage().
  4658. if (!dwFMResult) {
  4659. dwFMResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  4660. FORMAT_MESSAGE_FROM_SYSTEM, 0, hr, 0,
  4661. (LPTSTR)&szBuf,
  4662. 0, NULL);
  4663. }
  4664. if (!dwFMResult) {
  4665. dwFMResult = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  4666. FORMAT_MESSAGE_FROM_HMODULE, g_hInst,
  4667. hr, 0, (LPTSTR)&szBuf, 0, NULL);
  4668. }
  4669. if (dwFMResult) {
  4670. ASSERT(szBuf);
  4671. ASSERT(lstrlen(szBuf));
  4672. *ppszErrMsg = new char[lstrlen(szBuf) + 1];
  4673. if (!*ppszErrMsg) {
  4674. dwFMResult = FALSE;
  4675. goto Exit;
  4676. }
  4677. lstrcpy(*ppszErrMsg, szBuf);
  4678. LocalFree(szBuf);
  4679. }
  4680. else {
  4681. char szUnknown[MAX_DEBUG_FORMAT_STRING_LENGTH];
  4682. if (!dwFMResult && HRESULT_FACILITY(hr) == FACILITY_SETUPAPI) {
  4683. LoadString(g_hInst, ID_CDLDBG_UNKNOWN_SETUP_ERROR, szUnknown,
  4684. MAX_DEBUG_FORMAT_STRING_LENGTH);
  4685. }
  4686. else {
  4687. LoadString(g_hInst, ID_CDLDBG_UNKNOWN_ERROR, szUnknown,
  4688. MAX_DEBUG_FORMAT_STRING_LENGTH);
  4689. }
  4690. *ppszErrMsg = new char[lstrlen(szUnknown) + 1];
  4691. if (!*ppszErrMsg) {
  4692. dwFMResult = FALSE;
  4693. goto Exit;
  4694. }
  4695. lstrcpy(*ppszErrMsg, szUnknown);
  4696. }
  4697. }
  4698. // ppszErrMsg now holds saved error message or whatever came back from
  4699. // FormatMessage(). Construct a complete error message.
  4700. m_debuglog->MakeFile();
  4701. LoadString(g_hInst, ID_CDLDBG_ERROR_STRING, szErrString, MAX_DEBUG_STRING_LENGTH);
  4702. LoadString(g_hInst, ID_CDLDBG_DETAILS_STRING, szDetails, MAX_DEBUG_STRING_LENGTH);
  4703. szURL = (char *)m_debuglog->GetUrlName();
  4704. ASSERT(szURL[0] != '\0');
  4705. iSize = lstrlen(*ppszErrMsg) + lstrlen(szErrString) + lstrlen(szDetails)
  4706. + lstrlen(szURL) + 1;
  4707. pszErrorMessage = new char[iSize];
  4708. if (!pszErrorMessage) {
  4709. dwFMResult = FALSE;
  4710. goto Exit;
  4711. }
  4712. wnsprintfA(pszErrorMessage, ID_CDLDBG_UNKNOWN_ERROR, "%s%s%s%s"
  4713. , szErrString, *ppszErrMsg, szDetails, szURL);
  4714. if (FAILED(Ansi2Unicode(pszErrorMessage, ppwszError))) {
  4715. dwFMResult = FALSE;
  4716. goto Exit;
  4717. }
  4718. Exit:
  4719. SAFEDELETE(pszErrorMessage);
  4720. DEBUG_LEAVE((dwFMResult != 0));
  4721. return (dwFMResult != 0);
  4722. }
  4723. // ---------------------------------------------------------------------------
  4724. // %%Function: CCodeDownload::DumpDebugLog()
  4725. // Output the debug error log. This log is written as a cache entry.
  4726. // ---------------------------------------------------------------------------
  4727. void CCodeDownload::DumpDebugLog(char *szCacheFileName, LPTSTR szErrorMsg,
  4728. HRESULT hrError)
  4729. {
  4730. DEBUG_ENTER((DBG_DOWNLOAD,
  4731. None,
  4732. "CCodeDownload::DumpDebugLog",
  4733. "this=%#x, %.80q, %#x, %#x",
  4734. this, szCacheFileName, szErrorMsg, hrError
  4735. ));
  4736. m_debuglog->DumpDebugLog(szCacheFileName, MAX_PATH,
  4737. szErrorMsg, hrError);
  4738. DEBUG_LEAVE(0);
  4739. }
  4740. // ---------------------------------------------------------------------------
  4741. // %%Function: CCodeDownload::AddRef
  4742. // ---------------------------------------------------------------------------
  4743. STDMETHODIMP_(ULONG)
  4744. CCodeDownload::AddRef()
  4745. {
  4746. DEBUG_ENTER((DBG_DOWNLOAD,
  4747. Dword,
  4748. "CCodeDownload::IUnknown::AddRef",
  4749. "this=%#x",
  4750. this
  4751. ));
  4752. ULONG ulRet = m_cRef++;
  4753. DEBUG_LEAVE(ulRet);
  4754. return ulRet;
  4755. }
  4756. // ---------------------------------------------------------------------------
  4757. // %%Function: CCodeDownload::Release
  4758. // Clean up all temp files and free all memory
  4759. // Caller of this function cannot rely on accessing any data
  4760. // other than locals on their stack.
  4761. // ---------------------------------------------------------------------------
  4762. STDMETHODIMP_(ULONG)
  4763. CCodeDownload::Release()
  4764. {
  4765. DEBUG_ENTER((DBG_DOWNLOAD,
  4766. Dword,
  4767. "CCodeDownload::IUnknown::Release",
  4768. "this=%#x",
  4769. this
  4770. ));
  4771. CDownload *pdlCur;
  4772. HRESULT hr = S_OK;
  4773. Assert(m_cRef > 0);
  4774. if (--m_cRef != 0) {
  4775. DEBUG_LEAVE(m_cRef);
  4776. return m_cRef;
  4777. }
  4778. // release all CDownload objs
  4779. LISTPOSITION curpos = m_pDownloads.GetHeadPosition();
  4780. for (int i=0; i < m_pDownloads.GetCount(); i++) {
  4781. pdlCur = m_pDownloads.GetNext(curpos);
  4782. pdlCur->ReleaseParent(this);
  4783. }
  4784. CUrlMkTls tls(hr); // hr passed by reference!
  4785. Assert(SUCCEEDED(hr));
  4786. // remove this CCodeDownload from the per-thread list
  4787. if (m_ListCookie)
  4788. tls->pCodeDownloadList->RemoveAt(m_ListCookie);
  4789. delete this;
  4790. DEBUG_LEAVE(0);
  4791. return 0;
  4792. }
  4793. // ---------------------------------------------------------------------------
  4794. // %%Function: CCodeDownload::AcquireSetupCookie()
  4795. // ---------------------------------------------------------------------------
  4796. HRESULT
  4797. CCodeDownload::AcquireSetupCookie()
  4798. {
  4799. DEBUG_ENTER((DBG_DOWNLOAD,
  4800. Hresult,
  4801. "CCodeDownload::AcquireSetupCookie",
  4802. "this=%#x",
  4803. this
  4804. ));
  4805. HRESULT hr = S_OK;
  4806. CUrlMkTls tls(hr); // hr passed by reference!
  4807. if (FAILED(hr)) // if tls ctor failed above
  4808. goto Exit;
  4809. Assert(tls->pSetupCookie);
  4810. // need to serialize all Setup on this thread
  4811. // grab the Setup cookie
  4812. hr = tls->pSetupCookie->Acquire(this);
  4813. if (hr != S_OK) {
  4814. Assert(!tls->pSetupCookie->IsFree());
  4815. Assert(!tls->pSetupCookie->IsOwner(this));
  4816. // wait till we get posted a message when the current owner
  4817. // relinquishes the cookie
  4818. goto Exit;
  4819. }
  4820. // have the cookie
  4821. Assert(tls->pSetupCookie->IsOwner(this));
  4822. SetState(CDL_Setup);
  4823. Exit:
  4824. DEBUG_LEAVE(hr);
  4825. return hr;
  4826. }
  4827. // ---------------------------------------------------------------------------
  4828. // %%Function: CCodeDownload::RelinquishSetupCookie()
  4829. // ---------------------------------------------------------------------------
  4830. HRESULT
  4831. CCodeDownload::RelinquishSetupCookie()
  4832. {
  4833. DEBUG_ENTER((DBG_DOWNLOAD,
  4834. Hresult,
  4835. "CCodeDownload::RelinquishSetupCookie",
  4836. "this=%#x",
  4837. this
  4838. ));
  4839. HRESULT hr = S_OK;
  4840. CUrlMkTls tls(hr); // hr passed by reference!
  4841. if (FAILED(hr)) // if tls ctor failed above
  4842. goto Exit;
  4843. if (tls->pSetupCookie->IsOwner(this)) {
  4844. tls->pSetupCookie->Relinquish(this);
  4845. Assert(!tls->pSetupCookie->IsOwner(this));
  4846. }
  4847. Exit:
  4848. DEBUG_LEAVE(hr);
  4849. return hr;
  4850. }
  4851. // ---------------------------------------------------------------------------
  4852. // %%Function: CCodeDownload::AddDownloadToList
  4853. // ---------------------------------------------------------------------------
  4854. #ifndef unix
  4855. inline VOID
  4856. #else
  4857. VOID
  4858. #endif /* !unix */
  4859. CCodeDownload::AddDownloadToList(CDownload *pdl)
  4860. {
  4861. DEBUG_ENTER((DBG_DOWNLOAD,
  4862. None,
  4863. "CCodeDownload::AddDownloadToList",
  4864. "this=%#x, %#x",
  4865. this, pdl
  4866. ));
  4867. pdl->AddParent(this);
  4868. m_pDownloads.AddHead(pdl);
  4869. DEBUG_LEAVE(0);
  4870. }
  4871. // ---------------------------------------------------------------------------
  4872. // %%Function: CCodeDownload:: FindCABInDownloadList(szURL, pdlHint)
  4873. // Find a download (typically a CAB) in download list
  4874. // pdlHint is the first thing we look at (for perf.) as most usually
  4875. // is a case of primary OCX in a CAB that the INF came in
  4876. // Returns:
  4877. // hr = ERROR (some error occurred, ignore *pdlMatch
  4878. // hr = S_OK
  4879. // if (*pdlMatch) match found, match is *pdlMatch
  4880. // else
  4881. // no match, or dups in other code downloads, download your own
  4882. // ---------------------------------------------------------------------------
  4883. HRESULT
  4884. CCodeDownload::FindCABInDownloadList(LPCWSTR szURL, CDownload* pdlHint, CDownload **ppdlMatch)
  4885. {
  4886. DEBUG_ENTER((DBG_DOWNLOAD,
  4887. Hresult,
  4888. "CCodeDownload::FindCABInDownloadList",
  4889. "this=%#x, %.80wq, %#x, %#x",
  4890. this, szURL, pdlHint, ppdlMatch
  4891. ));
  4892. CDownload *pdlCur = NULL;
  4893. HRESULT hr = S_OK;
  4894. IMoniker* pmk = NULL;
  4895. int i;
  4896. LISTPOSITION curpos;
  4897. *ppdlMatch = pdlCur;
  4898. // create a moniker for the URL passed in and then we can pmk->IsEqual
  4899. // with every other CDownload's moniker.
  4900. IBindHost *pBH = GetClientBinding()->GetIBindHost();
  4901. if (pBH) {
  4902. hr = pBH->CreateMoniker((LPWSTR)szURL, pdlHint->GetBindCtx(), &pmk, 0);
  4903. } else {
  4904. hr = CreateURLMoniker(m_pmkContext, szURL, &pmk);
  4905. }
  4906. if (FAILED(hr))
  4907. goto Exit;
  4908. pdlCur = pdlHint; // assume hit
  4909. hr = pmk->IsEqual(pdlHint->GetMoniker());
  4910. if (hr != S_FALSE)
  4911. goto Exit;
  4912. if (pdlHint->DoPost()) {
  4913. hr = pmk->IsEqual(m_pmkContext);
  4914. if (hr != S_FALSE)
  4915. goto Exit;
  4916. }
  4917. // hint failed, try the whole list
  4918. curpos = m_pDownloads.GetHeadPosition();
  4919. for (i=0; i < m_pDownloads.GetCount(); i++) {
  4920. pdlCur = m_pDownloads.GetNext(curpos);
  4921. if (pdlCur == pdlHint) // already tried the pdlHint, don't retry
  4922. continue;
  4923. hr = pmk->IsEqual(pdlCur->GetMoniker());
  4924. if (hr != S_FALSE)
  4925. goto Exit;
  4926. }
  4927. pdlCur = NULL;
  4928. // now look across downloads
  4929. hr = FindDupCABInThread(pmk, &pdlCur);
  4930. Exit:
  4931. if (pmk)
  4932. pmk->Release();
  4933. *ppdlMatch = pdlCur;
  4934. DEBUG_LEAVE(hr);
  4935. return hr;
  4936. }
  4937. // ---------------------------------------------------------------------------
  4938. // %%Function: CCodeDownload::FindDupCABInThread(IMoniker *pmk, CDownload **ppdlMatch)
  4939. // Find a download (typically a CAB) across all code downloads in thread
  4940. // Returns:
  4941. // hr = ERROR
  4942. // hr = S_OK pdlCur?(match found):(no match found, do your own download)
  4943. // ---------------------------------------------------------------------------
  4944. HRESULT
  4945. CCodeDownload::FindDupCABInThread(IMoniker *pmk, CDownload **ppdlMatch)
  4946. {
  4947. DEBUG_ENTER((DBG_DOWNLOAD,
  4948. Hresult,
  4949. "CCodeDownload::FindDupCABInThread",
  4950. "this=%#x, %#x, %#x",
  4951. this, pmk, ppdlMatch
  4952. ));
  4953. CDownload *pdlCur = NULL;
  4954. HRESULT hr = S_OK;
  4955. LISTPOSITION curposCDL, curposDL;
  4956. CCodeDownload *pcdl;
  4957. int iNumCDL;
  4958. int i,j;
  4959. CUrlMkTls tls(hr); // hr passed by reference!
  4960. if (FAILED(hr))
  4961. goto Exit;
  4962. iNumCDL = tls->pCodeDownloadList->GetCount();
  4963. curposCDL = tls->pCodeDownloadList->GetHeadPosition();
  4964. // walk thru all the code downloads in the thread and check for DUPs
  4965. for (i=0; i < iNumCDL; i++) {
  4966. pcdl = tls->pCodeDownloadList->GetNext(curposCDL);
  4967. if (pcdl == this)
  4968. continue;
  4969. // look into this CCodeDownload tree for dup
  4970. curposDL = pcdl->m_pDownloads.GetHeadPosition();
  4971. for (j=0; j < pcdl->m_pDownloads.GetCount(); j++) {
  4972. pdlCur = pcdl->m_pDownloads.GetNext(curposDL);
  4973. hr = pmk->IsEqual(pdlCur->GetMoniker());
  4974. if (hr != S_FALSE)
  4975. goto Exit;
  4976. }
  4977. pdlCur = NULL;
  4978. }
  4979. hr = S_OK;
  4980. Exit:
  4981. if (pdlCur) {
  4982. // found a match in another Code Download
  4983. // add this pdl to our download list as well.
  4984. if (pdlCur->GetDLState() > DLSTATE_SETUP) {
  4985. pdlCur = NULL; // too late to piggy back
  4986. } else {
  4987. m_debuglog->DebugOut(DEB_CODEDL, FALSE, ID_CDLDBG_FOUND_DUP,
  4988. pdlCur->GetURL(), GetClsid().Data1,
  4989. GetMainURL(), m_dwFileVersionMS,
  4990. m_dwFileVersionLS);
  4991. AddDownloadToList(pdlCur);
  4992. }
  4993. }
  4994. *ppdlMatch = pdlCur;
  4995. DEBUG_LEAVE(hr);
  4996. return hr;
  4997. }
  4998. // ---------------------------------------------------------------------------
  4999. // %%Function: CCodeDownload::InitLastModifiedFromDistUnit
  5000. // ---------------------------------------------------------------------------
  5001. VOID
  5002. CCodeDownload::InitLastModifiedFromDistUnit()
  5003. {
  5004. DEBUG_ENTER((DBG_DOWNLOAD,
  5005. None,
  5006. "CCodeDownload::InitLastModifiedFromDistUnit",
  5007. "this=%#x",
  5008. this
  5009. ));
  5010. WIN32_FIND_DATA fd;
  5011. HANDLE hf;
  5012. IsDistUnitLocallyInstalled( m_szDistUnit, 0, 0, m_plci, NULL, NULL, 0);
  5013. if (!m_plci->GetLastModifiedTime() ) {
  5014. if ((hf = FindFirstFile(m_plci->szExistingFileName, &fd)) != INVALID_HANDLE_VALUE) {
  5015. memcpy(&(m_plci->ftLastModified), &(fd.ftLastWriteTime), sizeof(FILETIME));
  5016. FindClose(hf);
  5017. }
  5018. }
  5019. DEBUG_LEAVE(0);
  5020. }
  5021. // ---------------------------------------------------------------------------
  5022. // %%Function: CCodeDownload::DoCodeDownload
  5023. // Main action entry point for CCodeDownload
  5024. //
  5025. // This triggers creation of the first CDownload object for the CODE url
  5026. // if a local check for CLSID,FileVersion returns update_needed.
  5027. // (note : it is interesting to note here that if a control needs to just
  5028. // update a dependent DLL file it still needs to update the FileVersion
  5029. // of the primary control file (with CLSID implementation) for triggering
  5030. // any download at all!
  5031. //
  5032. // Once DoCodeDownload determines that an update is in order it creates
  5033. // a CClBinding for its client to call client BSC::OnstartBinding with.
  5034. //
  5035. // It then adds this CDownload obj to its list of downloads.
  5036. //
  5037. // If the m_url is a CAB or INF we need to download it before we know
  5038. // what we need to do next. Otherwise we create a CSetup obj for the
  5039. // download and add it to CDownload's list of pending Setup processing for
  5040. // stage 2 (setup and registeration). CSetup details later.
  5041. //
  5042. // ---------------------------------------------------------------------------
  5043. HRESULT
  5044. CCodeDownload::DoCodeDownload(
  5045. CLocalComponentInfo *plci,
  5046. DWORD flags)
  5047. {
  5048. DEBUG_ENTER((DBG_DOWNLOAD,
  5049. Hresult,
  5050. "CCodeDownload::DoCodeDownload",
  5051. "this=%#x, %#x, %#x",
  5052. this, plci, flags
  5053. ));
  5054. CDownload *pdl = NULL;
  5055. HRESULT hr = NOERROR;
  5056. FILEXTN extn = FILEXTN_UNKNOWN;
  5057. WCHAR szURL[INTERNET_MAX_URL_LENGTH];
  5058. LPWSTR lpDownloadURL;
  5059. HGLOBAL hPostData = NULL;
  5060. DWORD cbPostData = 0;
  5061. ICodeInstall* pCodeInstall = GetICodeInstall();
  5062. // set if we need to instantiate the object or just download/install it
  5063. SetNeedObject(flags);
  5064. // set if we should ignore the internet search path
  5065. SetUseCodebaseOnly(flags);
  5066. m_plci = plci;
  5067. Assert(plci);
  5068. // get lcid from the bind context
  5069. BIND_OPTS2 bopts;
  5070. bopts.cbStruct = sizeof(BIND_OPTS2);
  5071. if (SUCCEEDED(GetClientBC()->GetBindOptions(&bopts)) &&
  5072. (bopts.cbStruct == sizeof(BIND_OPTS2)) ) {
  5073. m_lcid = bopts.locale; // else user default lcid is already in
  5074. DEBUG_PRINT(DOWNLOAD,
  5075. INFO,
  5076. ("CCodeDownload::DoCodeDownload::this=%#x, m_lcid: %d (%#x)\n",
  5077. this, m_lcid, m_lcid
  5078. ));
  5079. }
  5080. if (m_plci->IsPresent() && pCodeInstall) {
  5081. // a prev ver exists. get permission to overwrite
  5082. // if ICodeInstall available
  5083. WCHAR szBuf[MAX_PATH];
  5084. MultiByteToWideChar(CP_ACP, 0, m_plci->szExistingFileName, -1, szBuf, MAX_PATH);
  5085. hr = pCodeInstall->OnCodeInstallProblem( CIP_OLDER_VERSION_EXISTS,
  5086. NULL, szBuf, 0);
  5087. // hr == E_ABORT: abort whole download
  5088. if (FAILED(hr)) {
  5089. if (hr == E_ABORT)
  5090. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  5091. // else preserve error code of OnCodeInstallProblem
  5092. goto CD_Exit;
  5093. }
  5094. }
  5095. // we need local version modified time only when doing GetLatest and
  5096. // only for the top most file
  5097. if (NeedLatestVersion() && m_plci->szExistingFileName[0] &&
  5098. !m_plci->GetLastModifiedTime() ) {
  5099. InitLastModifiedFromDistUnit();
  5100. }
  5101. if ((!m_url) || !(*m_url)) // if no CODE= <url>, mark that the option is
  5102. SetUsedCodeURL(); // already exhausted
  5103. // get the first site to try downloading from
  5104. hr = GetNextOnInternetSearchPath(GetClsid(), &hPostData, &cbPostData, szURL,
  5105. INTERNET_MAX_URL_LENGTH, &lpDownloadURL, &extn);
  5106. if ( FAILED(hr))
  5107. goto CD_Exit;
  5108. // download the CODE=URL (ie. CAB or INF file first)
  5109. pdl = new CDownload(lpDownloadURL, extn, &hr);
  5110. if (!pdl) {
  5111. hr = E_OUTOFMEMORY;
  5112. goto CD_Exit;
  5113. } else if (FAILED(hr)) {
  5114. delete pdl;
  5115. goto CD_Exit;
  5116. }
  5117. AddDownloadToList(pdl);
  5118. if (hPostData) {
  5119. pdl->SetPostData(hPostData, cbPostData);
  5120. hPostData = NULL; // mark as delegated, destructor for pdl will free
  5121. }
  5122. // don't need to set on stack for this case as we have addref'ed the
  5123. // pcdl. The reason we don't use the same addref technique on other
  5124. // situations is because while addref controls the life of the object
  5125. // the onstack is a dictate to not issue the OnStopBinding
  5126. // setting onstack from here will prevent the client from getting
  5127. // the OnStopBinding a must if an OnStartBinding has been issued.
  5128. hr = pdl->DoDownload(&m_pmkContext,
  5129. (BINDF_ASYNCHRONOUS| BINDF_ASYNCSTORAGE));
  5130. if (hr == MK_S_ASYNCHRONOUS) {
  5131. SetState(CDL_Downloading);
  5132. }
  5133. CD_Exit:
  5134. if (FAILED(hr)) {
  5135. if (hPostData)
  5136. GlobalFree(hPostData);
  5137. }
  5138. DEBUG_LEAVE(hr);
  5139. return hr;
  5140. }
  5141. // ---------------------------------------------------------------------------
  5142. // %%Function: CCodeDownload::SetupCODEUrl
  5143. // ---------------------------------------------------------------------------
  5144. HRESULT
  5145. CCodeDownload::SetupCODEUrl(LPWSTR *ppDownloadURL, FILEXTN *pextn)
  5146. {
  5147. DEBUG_ENTER((DBG_DOWNLOAD,
  5148. Hresult,
  5149. "CCodeDownload::SetupCODEUrl",
  5150. "this=%#x, %#x, %#x",
  5151. this, ppDownloadURL, pextn
  5152. ));
  5153. char *pBaseFileName = NULL;
  5154. char szBuf[INTERNET_MAX_URL_LENGTH];
  5155. WideCharToMultiByte(CP_ACP, 0, m_url, -1, szBuf,
  5156. INTERNET_MAX_URL_LENGTH, 0,0);
  5157. *pextn = GetExtnAndBaseFileName( szBuf, &pBaseFileName);
  5158. *ppDownloadURL = m_url;
  5159. SetUsedCodeURL();
  5160. DEBUG_LEAVE(S_OK);
  5161. return S_OK;
  5162. }
  5163. // ---------------------------------------------------------------------------
  5164. // %%Function: CCodeDownload::GetNextComponent
  5165. // ---------------------------------------------------------------------------
  5166. HRESULT
  5167. CCodeDownload::GetNextComponent(
  5168. LPSTR szURL,
  5169. LPSTR *ppCur
  5170. )
  5171. {
  5172. DEBUG_ENTER((DBG_DOWNLOAD,
  5173. Hresult,
  5174. "CCodeDownload::GetNextComponent",
  5175. "this=%#x, %.80q, %#x",
  5176. this, szURL, ppCur
  5177. ));
  5178. HRESULT hr = S_OK;
  5179. LPSTR pch = *ppCur;
  5180. LPSTR pchOut = szURL;
  5181. int cbBuffer = 0;
  5182. #define BEGIN_ANGLE_BRKT '<'
  5183. #define END_ANGLE_BRKT '>'
  5184. #define COMP_DELIMITER ';'
  5185. if (!pch || *pch == '\0') {
  5186. hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  5187. goto Exit;
  5188. }
  5189. if (*pch == BEGIN_ANGLE_BRKT) {
  5190. pch++; // skip BEGIN_ANGLE_BRKT
  5191. for (; *pch && (*pch != END_ANGLE_BRKT);) {
  5192. *pchOut++ = *pch++;
  5193. if (cbBuffer++ >= INTERNET_MAX_URL_LENGTH) {
  5194. hr = E_INVALIDARG;
  5195. goto Exit;
  5196. }
  5197. }
  5198. if (*pch)
  5199. pch++; // skip the END_ANGLE_BRKT
  5200. } else {
  5201. // assume its CODEBASE, just copy the string till we reach the
  5202. // next COMP_DELIMITER
  5203. for (; *pch && (*pch != COMP_DELIMITER);) {
  5204. *pchOut++ = *pch++;
  5205. if (cbBuffer++ >= INTERNET_MAX_URL_LENGTH) {
  5206. hr = E_INVALIDARG;
  5207. goto Exit;
  5208. }
  5209. }
  5210. }
  5211. *pchOut = '\0';
  5212. if (*pch)
  5213. *ppCur = pch+1; // skip the COMP_DELIMITER
  5214. else
  5215. *ppCur = pch;
  5216. Exit:
  5217. DEBUG_LEAVE(hr);
  5218. return hr;
  5219. }
  5220. // ---------------------------------------------------------------------------
  5221. // %%Function: CCodeDownload::GetNextOnInternetSearchPath
  5222. // ---------------------------------------------------------------------------
  5223. HRESULT
  5224. CCodeDownload::GetNextOnInternetSearchPath(
  5225. REFCLSID rclsid,
  5226. HGLOBAL *phPostData,
  5227. DWORD *pcbPostData,
  5228. LPWSTR szURL,
  5229. DWORD dwSize,
  5230. LPWSTR *ppDownloadURL,
  5231. FILEXTN *pextn
  5232. )
  5233. {
  5234. DEBUG_ENTER((DBG_DOWNLOAD,
  5235. Hresult,
  5236. "CCodeDownload::GetNextOnInternetSearchPath",
  5237. "this=%#x, %#x, %#x, %#x, %.80wq, %#x, %#x, %#x",
  5238. this, &rclsid, phPostData, pcbPostData, szURL, dwSize, ppDownloadURL, pextn
  5239. ));
  5240. LONG lResult;
  5241. HRESULT hr = S_OK;
  5242. DWORD Size;
  5243. DWORD dwType;
  5244. char szBuf[INTERNET_MAX_URL_LENGTH];
  5245. DWORD cb;
  5246. static char *szISP = "CodeBaseSearchPath";
  5247. char szClsid[MAX_PATH];
  5248. char szID[MAX_PATH];
  5249. char szHackMimeType[MAX_PATH];
  5250. HGLOBAL hPostData = NULL;
  5251. char szNeedVersion[100]; // enough to hold four shorts as a,b,c,d + nulterm
  5252. BOOL bMimeType = FALSE;
  5253. // Ignore Internet Search path if set.
  5254. if (UseCodebaseOnly())
  5255. {
  5256. SetupCODEUrl(ppDownloadURL,pextn);
  5257. goto Exit;
  5258. }
  5259. if (!m_hKeySearchPath) {
  5260. lResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0,
  5261. KEY_READ, &m_hKeySearchPath);
  5262. if (lResult == ERROR_SUCCESS) {
  5263. // get size reqd to store away entire searchpath
  5264. lResult = ::SHQueryValueEx(m_hKeySearchPath, szISP, NULL, &dwType,
  5265. /* get size */ NULL, &Size);
  5266. if ( lResult == ERROR_SUCCESS) {
  5267. if (Size == 0) {
  5268. // we don't check the CODE url in the case where there is a
  5269. // searchpath specified in the registry, but UseCodeURL is
  5270. // not one of the elements in the searchpath.
  5271. // This gives the client a choice to completely ignore the
  5272. // CODE URL if needed, but without specifying any other
  5273. // HTTP-POST url either
  5274. hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  5275. goto Exit;
  5276. }
  5277. // alloc memory
  5278. Size++;
  5279. m_pSearchPath = new char [Size];
  5280. if (m_pSearchPath) {
  5281. lResult = ::SHQueryValueEx(m_hKeySearchPath, szISP, NULL,
  5282. &dwType, (unsigned char *)m_pSearchPath,
  5283. &Size);
  5284. Assert(lResult == ERROR_SUCCESS);
  5285. m_pSearchPathNextComp = m_pSearchPath;
  5286. } else {
  5287. lResult = E_OUTOFMEMORY;
  5288. }
  5289. }
  5290. }
  5291. if (lResult != ERROR_SUCCESS) {
  5292. if (UsedCodeURL()) { // no searchpath, already used CODE url?
  5293. hr = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  5294. goto Exit;
  5295. }
  5296. // no searchpath, use CODE=<url> in OBJECT tag
  5297. SetupCODEUrl(ppDownloadURL,pextn);
  5298. goto Exit;
  5299. }
  5300. }
  5301. do {
  5302. hr = GetNextComponent(szBuf, &m_pSearchPathNextComp);
  5303. if (FAILED(hr))
  5304. goto Exit;
  5305. if (lstrcmpi(szBuf, sz_USE_CODE_URL) == 0) {
  5306. if (UsedCodeURL()) { // already used CODE url?
  5307. continue;
  5308. }
  5309. // use code=<url> in OBJECT tag
  5310. SetupCODEUrl(ppDownloadURL,pextn);
  5311. goto Exit;
  5312. } else {
  5313. break;
  5314. }
  5315. } while (TRUE);
  5316. // here if HTTP-POST url
  5317. MultiByteToWideChar(CP_ACP, 0, szBuf, -1, szURL, dwSize);
  5318. *ppDownloadURL = szURL;
  5319. // do POST: form the post data
  5320. if (GetMainDistUnit()) {
  5321. WideCharToMultiByte(CP_ACP, 0, GetMainDistUnit(), -1, szClsid, MAX_PATH, 0,0);
  5322. wnsprintf(szID, sizeof(szID)-1, "CLSID=%s", szClsid);
  5323. } else {
  5324. // no clsid, dispatch the mime type or ext
  5325. if (GetMainType()) {
  5326. // type available
  5327. WideCharToMultiByte(CP_ACP, 0, GetMainType(), -1, szClsid, MAX_PATH, 0,0);
  5328. wnsprintf(szID, sizeof(szID)-1, "MIMETYPE=%s", szClsid);
  5329. bMimeType = TRUE;
  5330. } else {
  5331. // ext
  5332. Assert(GetMainExt());
  5333. WideCharToMultiByte(CP_ACP, 0, GetMainExt(), -1, szClsid, MAX_PATH, 0,0);
  5334. wnsprintf(szID, sizeof(szID)-1, "EXTENSION=%s", szClsid);
  5335. }
  5336. }
  5337. cb = lstrlen(szID);
  5338. // compute increased size if Version is specified.
  5339. if (m_dwFileVersionMS || m_dwFileVersionLS) {
  5340. wsprintf(szNeedVersion, "&%s=%d,%d,%d,%d",szVersion,
  5341. (m_dwFileVersionMS & 0xffff0000)>>16,
  5342. (m_dwFileVersionMS & 0xffff),
  5343. (m_dwFileVersionLS & 0xffff0000)>>16,
  5344. (m_dwFileVersionLS & 0xffff));
  5345. cb += lstrlen(szNeedVersion);
  5346. }
  5347. if (bMimeType) {
  5348. // hack the OBJECT index
  5349. // it doesn't support query by mime type
  5350. // so send out post data with the mime type in the CLSID=
  5351. // we also need to escape the '/' if any in the mime type
  5352. ComposeHackClsidFromMime(szHackMimeType, sizeof(szHackMimeType), szClsid);
  5353. cb += lstrlen(szHackMimeType);
  5354. }
  5355. hPostData = GlobalAlloc(GPTR, cb+1 ); // + 1 for null term
  5356. if (!hPostData) {
  5357. hr = HRESULT_FROM_WIN32(GetLastError()); // typically, E_OUTOFMEMORY
  5358. goto ReleaseAndExit;
  5359. }
  5360. lstrcpy((char *)hPostData, szID);
  5361. if (m_dwFileVersionMS || m_dwFileVersionLS)
  5362. lstrcat( (char *)hPostData, szNeedVersion);
  5363. if (bMimeType)
  5364. lstrcat( (char *)hPostData, szHackMimeType);
  5365. Assert(cb == (DWORD)lstrlen((char *)hPostData));
  5366. *pcbPostData = cb;
  5367. ReleaseAndExit:
  5368. Exit:
  5369. *phPostData = hPostData;
  5370. DEBUG_LEAVE(hr);
  5371. return hr;
  5372. }
  5373. // ---------------------------------------------------------------------------
  5374. // %%Function: CCodeDownload::IsPackageLocallyInstalled
  5375. // ---------------------------------------------------------------------------
  5376. HRESULT
  5377. CCodeDownload::IsPackageLocallyInstalled(LPCWSTR szPackageName, LPCWSTR szNameSpace, DWORD dwVersionMS, DWORD dwVersionLS)
  5378. {
  5379. DEBUG_ENTER((DBG_DOWNLOAD,
  5380. Hresult,
  5381. "CCodeDownload::IsPackageLocallyInstalled",
  5382. "this=%#x, %.80wq, %.80wq, %#x, %#x",
  5383. this, szPackageName, szNameSpace, dwVersionMS, dwVersionLS
  5384. ));
  5385. HRESULT hr = ::IsPackageLocallyInstalled(&m_pPackageManager, szPackageName, szNameSpace, dwVersionMS, dwVersionLS);
  5386. DEBUG_LEAVE(hr);
  5387. return hr;
  5388. }
  5389. // ---------------------------------------------------------------------------
  5390. // %%Function: CCodeDownload::DestroyPCBHList
  5391. // ---------------------------------------------------------------------------
  5392. void CCodeDownload::DestroyPCBHList(CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList)
  5393. {
  5394. DEBUG_ENTER((DBG_DOWNLOAD,
  5395. None,
  5396. "CCodeDownload::DestroyPCBHList",
  5397. "this=%#x, %#x",
  5398. this, pcbhList
  5399. ));
  5400. LISTPOSITION lpos = 0;
  5401. CCodeBaseHold *pcbh = NULL;
  5402. if (pcbhList) {
  5403. lpos = pcbhList->GetHeadPosition();
  5404. while (lpos) {
  5405. pcbh = pcbhList->GetNext(lpos);
  5406. delete pcbh;
  5407. }
  5408. pcbhList->RemoveAll();
  5409. }
  5410. DEBUG_LEAVE(0);
  5411. }
  5412. // ---------------------------------------------------------------------------
  5413. // %%Function: CCodeDownload::SetCatalogFile
  5414. // ---------------------------------------------------------------------------
  5415. HRESULT CCodeDownload::SetCatalogFile(LPSTR szCatalogFile)
  5416. {
  5417. DEBUG_ENTER((DBG_DOWNLOAD,
  5418. Hresult,
  5419. "CCodeDownload::SetCatalogFile",
  5420. "this=%#x, %.80q",
  5421. this, szCatalogFile
  5422. ));
  5423. HRESULT hr = S_OK;
  5424. SAFEDELETE(m_szCatalogFile);
  5425. m_szCatalogFile = new char[lstrlen(szCatalogFile) + 1];
  5426. if (m_szCatalogFile == NULL) {
  5427. hr = E_OUTOFMEMORY;
  5428. }
  5429. else {
  5430. lstrcpy(m_szCatalogFile, szCatalogFile);
  5431. }
  5432. DEBUG_LEAVE(hr);
  5433. return hr;
  5434. }
  5435. // ---------------------------------------------------------------------------
  5436. // %%Function: CCodeDownload::GetCatalogFile
  5437. // ---------------------------------------------------------------------------
  5438. LPSTR CCodeDownload::GetCatalogFile()
  5439. {
  5440. DEBUG_ENTER((DBG_DOWNLOAD,
  5441. String,
  5442. "CCodeDownload::GetCatalogFile",
  5443. "this=%#x",
  5444. this
  5445. ));
  5446. HRESULT hr = S_OK;
  5447. LPSTR szCatalogFile = NULL;
  5448. CClBinding *pBinding = NULL;
  5449. IBindStatusCallback *pBSC = NULL;
  5450. IServiceProvider *pServProv = NULL;
  5451. LPCATALOGFILEINFO pcfi = NULL;
  5452. if (m_szCatalogFile) {
  5453. szCatalogFile = m_szCatalogFile;
  5454. }
  5455. else {
  5456. pBinding = m_pClientbinding.GetHead();
  5457. if (pBinding) {
  5458. pBSC = pBinding->GetAssBSC();
  5459. if (pBSC) {
  5460. hr = pBSC->QueryInterface(IID_ICatalogFileInfo, (void **)&pcfi);
  5461. if (SUCCEEDED(hr)) {
  5462. pcfi->GetCatalogFile(&szCatalogFile);
  5463. m_szCatalogFile = szCatalogFile;
  5464. SAFERELEASE(pcfi);
  5465. }
  5466. else {
  5467. hr = pBSC->QueryInterface(IID_IServiceProvider, (void **)&pServProv);
  5468. if (SUCCEEDED(hr)) {
  5469. hr = pServProv->QueryService(IID_ICatalogFileInfo, IID_ICatalogFileInfo, (void **)&pcfi);
  5470. if (SUCCEEDED(hr)) {
  5471. pcfi->GetCatalogFile(&szCatalogFile);
  5472. m_szCatalogFile = szCatalogFile;
  5473. }
  5474. SAFERELEASE(pServProv);
  5475. SAFERELEASE(pcfi);
  5476. }
  5477. }
  5478. }
  5479. }
  5480. }
  5481. DEBUG_LEAVE(szCatalogFile);
  5482. return szCatalogFile;
  5483. }
  5484. // ---------------------------------------------------------------------------
  5485. // %%Function: CCodeDownload::SetMainCABJavaTrustPermissions
  5486. // ---------------------------------------------------------------------------
  5487. HRESULT CCodeDownload::SetMainCABJavaTrustPermissions(PJAVA_TRUST pbJavaTrust)
  5488. {
  5489. DEBUG_ENTER((DBG_DOWNLOAD,
  5490. Hresult,
  5491. "CCodeDownload::SetMainCABJavaTrustPermissions",
  5492. "this=%#x, %#x",
  5493. this, pbJavaTrust
  5494. ));
  5495. DWORD dwLen = 0;
  5496. HRESULT hr = S_OK;
  5497. if (pbJavaTrust && m_pbJavaTrust == NULL) { // only do this once
  5498. // Clone the JAVA_TRUST object
  5499. if (pbJavaTrust->cbSize) {
  5500. m_pbJavaTrust = (PJAVA_TRUST)new BYTE[pbJavaTrust->cbSize];
  5501. if (m_pbJavaTrust == NULL) {
  5502. hr = E_OUTOFMEMORY;
  5503. goto Exit;
  5504. }
  5505. } else {
  5506. m_pbJavaTrust = NULL;
  5507. goto Exit;
  5508. }
  5509. memset(m_pbJavaTrust, 0, sizeof(JAVA_TRUST));
  5510. m_pbJavaTrust->cbJavaPermissions = pbJavaTrust->cbJavaPermissions;
  5511. if (pbJavaTrust->cbJavaPermissions) {
  5512. m_pbJavaTrust->pbJavaPermissions = new BYTE[m_pbJavaTrust->cbJavaPermissions];
  5513. if (m_pbJavaTrust->pbJavaPermissions == NULL) {
  5514. hr = E_OUTOFMEMORY;
  5515. goto Exit;
  5516. }
  5517. memcpy(m_pbJavaTrust->pbJavaPermissions, pbJavaTrust->pbJavaPermissions,
  5518. m_pbJavaTrust->cbJavaPermissions);
  5519. }
  5520. else {
  5521. m_pbJavaTrust->pbJavaPermissions = NULL;
  5522. }
  5523. m_pbJavaTrust->cbSigner = pbJavaTrust->cbSigner;
  5524. if (pbJavaTrust->cbSigner) {
  5525. m_pbJavaTrust->pbSigner = new BYTE[m_pbJavaTrust->cbSigner];
  5526. if (m_pbJavaTrust->pbSigner == NULL) {
  5527. hr = E_OUTOFMEMORY;
  5528. goto Exit;
  5529. }
  5530. memcpy(m_pbJavaTrust->pbSigner, pbJavaTrust->pbSigner,
  5531. m_pbJavaTrust->cbSigner);
  5532. }
  5533. else {
  5534. m_pbJavaTrust->pbSigner = NULL;
  5535. }
  5536. // pbJavaTrust in IE4 had a bug where this zone URL is not NULL
  5537. // terminated. Besides, we don't really require cloning the zone as we
  5538. // don't use it to install. So, we are not cloning the zone url
  5539. m_pbJavaTrust->pwszZone = NULL;
  5540. m_pbJavaTrust->cbSize = pbJavaTrust->cbSize;
  5541. m_pbJavaTrust->flag = pbJavaTrust->flag;
  5542. m_pbJavaTrust->fAllActiveXPermissions = pbJavaTrust->fAllActiveXPermissions;
  5543. m_pbJavaTrust->fAllPermissions = pbJavaTrust->fAllPermissions;
  5544. m_pbJavaTrust->dwEncodingType = pbJavaTrust->dwEncodingType;
  5545. m_pbJavaTrust->guidZone = pbJavaTrust->guidZone;
  5546. m_pbJavaTrust->hVerify = pbJavaTrust->hVerify;
  5547. }
  5548. Exit:
  5549. DEBUG_LEAVE(hr);
  5550. return hr;
  5551. }
  5552. // ---------------------------------------------------------------------------
  5553. // %%Function: CCodeDownload::SetMainCABJavaTrustPermissions
  5554. // ---------------------------------------------------------------------------
  5555. PJAVA_TRUST CCodeDownload::GetJavaTrust()
  5556. {
  5557. DEBUG_ENTER((DBG_DOWNLOAD,
  5558. Pointer,
  5559. "CCodeDownload::GetJavaTrust",
  5560. "this=%#x",
  5561. this
  5562. ));
  5563. DEBUG_LEAVE(m_pbJavaTrust);
  5564. return m_pbJavaTrust;
  5565. }
  5566. HRESULT ProcessImplementation(IXMLElement *pConfig,
  5567. CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList,
  5568. LCID lcidOverride,
  5569. #ifdef WX86
  5570. CMultiArch *MultiArch,
  5571. #endif
  5572. LPWSTR szBaseURL)
  5573. {
  5574. #ifdef WX86
  5575. DEBUG_ENTER((DBG_DOWNLOAD,
  5576. Hresult,
  5577. "ProcessImplementation",
  5578. "%#x, %#x, %#x, %#x, %.80wq",
  5579. pConfig, pcbhList, lcidOverride, MultiArch, szBaseURL
  5580. ));
  5581. #else
  5582. DEBUG_ENTER((DBG_DOWNLOAD,
  5583. Hresult,
  5584. "ProcessImplementation",
  5585. "%#x, %#x, %#x, %.80wq",
  5586. pConfig, pcbhList, lcidOverride, szBaseURL
  5587. ));
  5588. #endif
  5589. int nLastChildTag = -1;
  5590. int nLastCodeBase = -1;
  5591. int nLastOS = -1;
  5592. int nLastProc = -1;
  5593. OSVERSIONINFO osvi;
  5594. BOOL fFoundAnyConfig = FALSE;
  5595. BOOL fFoundAnyOS = FALSE, fFoundMatchingOS = FALSE;
  5596. BOOL fFoundAnyProc = FALSE, fFoundMatchingProc = FALSE;
  5597. IXMLElement *pCodeBase = NULL, *pLang = NULL, *pOS = NULL;
  5598. IXMLElement *pOSVersion = NULL, *pProcessor = NULL;
  5599. HRESULT hr = S_FALSE; // default: failed configuration match
  5600. BOOL bSetMainCodeBase = FALSE;
  5601. #ifdef WX86
  5602. char *szPreferredArch;
  5603. char *szAlternateArch;
  5604. HRESULT hrArch;
  5605. #endif
  5606. union {
  5607. char szLang[MAX_PATH];
  5608. char szOS[MAX_PATH];
  5609. char szOSVersion[MAX_PATH];
  5610. char szProcessor[MAX_PATH];
  5611. };
  5612. if (pcbhList == NULL)
  5613. {
  5614. DEBUG_LEAVE(hr);
  5615. return E_INVALIDARG;
  5616. }
  5617. pcbhList->RemoveAll();
  5618. osvi.dwOSVersionInfoSize = sizeof(osvi);
  5619. GetVersionEx(&osvi);
  5620. // process LANGUAGES tag.
  5621. if (GetFirstChildTag(pConfig, DU_TAG_LANG, &pLang) == S_OK) {
  5622. if (SUCCEEDED(GetAttributeA(pLang, DU_ATTRIB_VALUE, szLang, MAX_PATH))) {
  5623. if (FAILED(CheckLanguage(lcidOverride, szLang))) {
  5624. if ((lcidOverride == g_lcidBrowser) ||
  5625. (FAILED(CheckLanguage(g_lcidBrowser, szLang)))) {
  5626. hr = S_FALSE;
  5627. goto Exit;
  5628. }
  5629. }
  5630. } else { // improperly formatted, skip it.
  5631. hr = S_FALSE;
  5632. goto Exit;
  5633. }
  5634. } // languages
  5635. // process OS tag
  5636. nLastOS = -1;
  5637. fFoundAnyOS = FALSE;
  5638. fFoundMatchingOS = FALSE;
  5639. while (GetNextChildTag(pConfig, DU_TAG_OS, &pOS, nLastOS) == S_OK) {
  5640. fFoundAnyOS = TRUE;
  5641. if (SUCCEEDED(GetAttributeA(pOS, DU_ATTRIB_VALUE, szOS, MAX_PATH))) {
  5642. if (lstrcmpi(szOS, (const char *) ((g_fRunningOnNT) ? szWinNT : szWin95)) == 0) {
  5643. if (GetFirstChildTag(pOS, DU_TAG_OSVERSION, &pOSVersion) == S_OK) {
  5644. if (SUCCEEDED(GetAttributeA(pOSVersion, DU_ATTRIB_VALUE, szOSVersion, MAX_PATH))) {
  5645. DWORD dwVersionMS = 0, dwVersionLS = 0;
  5646. if (SUCCEEDED(GetVersionFromString(szOSVersion, &dwVersionMS, &dwVersionLS))) {
  5647. if (!((osvi.dwMajorVersion < (dwVersionMS>>16)) || (osvi.dwMajorVersion == (dwVersionMS>>16) &&
  5648. (osvi.dwMinorVersion < (dwVersionMS & 0xFFFF))) )) {
  5649. fFoundMatchingOS = TRUE;
  5650. break;
  5651. }
  5652. } else {
  5653. hr = HRESULT_FROM_WIN32(GetLastError());
  5654. goto Exit;
  5655. }
  5656. }
  5657. } else {
  5658. // OS with no version
  5659. fFoundMatchingOS = TRUE;
  5660. break;
  5661. }
  5662. }
  5663. }
  5664. SAFERELEASE(pOS);
  5665. SAFERELEASE(pOSVersion);
  5666. }
  5667. if (fFoundAnyOS && !fFoundMatchingOS) {
  5668. hr = S_FALSE;
  5669. goto Exit;
  5670. }
  5671. // check PROCESSOR tag
  5672. nLastProc = -1;
  5673. fFoundAnyProc = FALSE;
  5674. fFoundMatchingProc = FALSE;
  5675. #ifdef WX86
  5676. MultiArch->SelectArchitecturePreferences(
  5677. g_szProcessorTypes[g_CPUType],
  5678. g_szProcessorTypes[PROCESSOR_ARCHITECTURE_INTEL],
  5679. &szPreferredArch,
  5680. &szAlternateArch);
  5681. #endif
  5682. while (GetNextChildTag(pConfig, DU_TAG_PROCESSOR, &pProcessor, nLastProc) == S_OK) {
  5683. fFoundAnyProc = TRUE;
  5684. if (SUCCEEDED(GetAttributeA(pProcessor, DU_ATTRIB_VALUE, szProcessor, MAX_PATH))) {
  5685. #ifdef WX86
  5686. if (lstrcmpi(szPreferredArch, szProcessor) == 0) {
  5687. hrArch = MultiArch->RequirePrimaryArch();
  5688. Assert(SUCCEEDED(hrArch));
  5689. fFoundMatchingProc = TRUE;
  5690. break;
  5691. } else if (szAlternateArch) {
  5692. if (lstrcmpi(szAlternateArch, szProcessor) == 0) {
  5693. hrArch = MultiArch->RequireAlternateArch();
  5694. Assert(SUCCEEDED(hrArch));
  5695. fFoundMatchingProc = TRUE;
  5696. break;
  5697. }
  5698. }
  5699. #else
  5700. if (lstrcmpi(g_szProcessorTypes[g_CPUType],szProcessor) == 0) {
  5701. fFoundMatchingProc = TRUE;
  5702. break;
  5703. }
  5704. #endif
  5705. }
  5706. SAFERELEASE(pProcessor);
  5707. }
  5708. if (fFoundAnyProc && !fFoundMatchingProc) {
  5709. hr = S_FALSE;
  5710. goto Exit;
  5711. }
  5712. // process CODEBASE tag.
  5713. nLastCodeBase = -1;
  5714. bSetMainCodeBase = FALSE;
  5715. while (GetNextChildTag(pConfig, DU_TAG_CODEBASE, &pCodeBase, nLastCodeBase) == S_OK) {
  5716. hr = ProcessCodeBaseList(pCodeBase, pcbhList, szBaseURL);
  5717. if (!bSetMainCodeBase) {
  5718. CCodeBaseHold *pcbhMain;
  5719. pcbhMain = pcbhList->GetHead();
  5720. if (pcbhMain) {
  5721. pcbhMain->dwFlags |= CBH_FLAGS_MAIN_CODEBASE;
  5722. bSetMainCodeBase = TRUE;
  5723. }
  5724. }
  5725. SAFERELEASE(pCodeBase);
  5726. }
  5727. //REVIEW: We could also extract ABSTRACT, TITLE here
  5728. // NEEDSTRUSTEDSOURCE & SYSTEM only apply to Java applets so they can be checked in
  5729. // addition to this by ProcessJavaManifest.
  5730. // we passed all configuration filter criteria
  5731. hr = S_OK;
  5732. Exit:
  5733. SAFERELEASE(pCodeBase);
  5734. SAFERELEASE(pLang);
  5735. SAFERELEASE(pOS);
  5736. SAFERELEASE(pOSVersion);
  5737. SAFERELEASE(pProcessor);
  5738. DEBUG_LEAVE(hr);
  5739. return hr;
  5740. }
  5741. HRESULT ProcessCodeBaseList(IXMLElement *pCodeBase,
  5742. CList<CCodeBaseHold *, CCodeBaseHold *> *pcbhList,
  5743. LPWSTR szBaseURL)
  5744. {
  5745. DEBUG_ENTER((DBG_DOWNLOAD,
  5746. Hresult,
  5747. "ProcessCodeBaseList",
  5748. "%#x, %#x, %.80wq",
  5749. pCodeBase, pcbhList, szBaseURL
  5750. ));
  5751. HRESULT hr = S_OK;
  5752. DWORD dwSize = 0;
  5753. CCodeBaseHold *pcbh = NULL;
  5754. CCodeBaseHold *pcbhCur = NULL;
  5755. LISTPOSITION lpos = 0;
  5756. LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo = NULL;
  5757. LPSTR szCodeBase = NULL;
  5758. BOOL bRandom = FALSE;
  5759. int iIndex = 0;
  5760. int iCount = 0;
  5761. int i;
  5762. int iLastIndexInCache;
  5763. char achBuffer[MAX_CACHE_ENTRY_INFO_SIZE];
  5764. char szRandom[MAX_PATH];
  5765. WCHAR szResult[INTERNET_MAX_URL_LENGTH];
  5766. union {
  5767. char szSize[MAX_PATH];
  5768. char szStyle[MAX_PATH];
  5769. };
  5770. if (!pcbhList) {
  5771. hr = E_INVALIDARG;
  5772. goto Exit;
  5773. }
  5774. pcbh = new CCodeBaseHold();
  5775. if (!pcbh) {
  5776. hr = E_OUTOFMEMORY;
  5777. goto Exit;
  5778. }
  5779. if (SUCCEEDED(hr = DupAttribute(pCodeBase, DU_ATTRIB_HREF, &pcbh->wszCodeBase))) {
  5780. pcbh->bHREF = TRUE;
  5781. if (szBaseURL) {
  5782. dwSize = INTERNET_MAX_PATH_LENGTH;
  5783. UrlCombineW(szBaseURL, pcbh->wszCodeBase, szResult, &dwSize, 0);
  5784. delete pcbh->wszCodeBase;
  5785. pcbh->wszCodeBase = new WCHAR[dwSize + 1];
  5786. if (pcbh->wszCodeBase == NULL) {
  5787. hr = E_OUTOFMEMORY;
  5788. SAFEDELETE(pcbh);
  5789. goto Exit;
  5790. }
  5791. StrCpyW(pcbh->wszCodeBase, szResult);
  5792. }
  5793. } else if (SUCCEEDED(hr = DupAttribute(pCodeBase, DU_ATTRIB_FILENAME, &pcbh->wszCodeBase))) {
  5794. pcbh->bHREF = FALSE;
  5795. } else {
  5796. SAFEDELETE(pcbh);
  5797. goto Exit;
  5798. }
  5799. bRandom = FALSE;
  5800. if (SUCCEEDED(GetAttributeA(pCodeBase, DU_ATTRIB_RANDOM, szRandom, MAX_PATH))) {
  5801. if (szRandom[0] == 'y' || szRandom[0] == 'Y') {
  5802. bRandom = TRUE;
  5803. }
  5804. }
  5805. pcbh->wszDLGroup = NULL;
  5806. pcbh->dwFlags &= ~CBH_FLAGS_DOWNLOADED;
  5807. DupAttribute(pCodeBase, DU_ATTRIB_DL_GROUP, &pcbh->wszDLGroup);
  5808. if (SUCCEEDED(GetAttributeA(pCodeBase, DU_ATTRIB_SIZE, szSize, MAX_PATH))) {
  5809. pcbh->dwSize = StrToIntA(szSize);
  5810. } else {
  5811. pcbh->dwSize = -1;
  5812. }
  5813. pcbh->dwFlags &= ~CBH_FLAGS_MAIN_CODEBASE;
  5814. // If the cache entry for this URL exists, put this at the head of the
  5815. // list.
  5816. lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO)achBuffer;
  5817. dwSize = MAX_CACHE_ENTRY_INFO_SIZE;
  5818. if (SUCCEEDED(hr = Unicode2Ansi(pcbh->wszCodeBase, &szCodeBase))) {
  5819. if (GetUrlCacheEntryInfo(szCodeBase, lpCacheEntryInfo,
  5820. &dwSize)) {
  5821. pcbhList->AddHead(pcbh);
  5822. goto Exit;
  5823. }
  5824. SAFEDELETE(szCodeBase);
  5825. } else {
  5826. goto Exit;
  5827. }
  5828. if (bRandom) {
  5829. // Set iLastIndexInCache to the last index in the linked list that
  5830. // contains a cache entry. The goal is to ensure all cache entries
  5831. // appear FIRST in the linked list.
  5832. iLastIndexInCache = -1;
  5833. lpos = pcbhList->GetHeadPosition();
  5834. i = 0;
  5835. while (lpos) {
  5836. pcbhCur = pcbhList->GetNext(lpos);
  5837. lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO)achBuffer;
  5838. dwSize = MAX_CACHE_ENTRY_INFO_SIZE;
  5839. if (pcbhCur != NULL) {
  5840. if (SUCCEEDED(Unicode2Ansi(pcbhCur->wszCodeBase,
  5841. &szCodeBase))) {
  5842. if (GetUrlCacheEntryInfo(szCodeBase, lpCacheEntryInfo,
  5843. &dwSize)) {
  5844. iLastIndexInCache = i;
  5845. }
  5846. SAFEDELETE(szCodeBase);
  5847. }
  5848. }
  5849. i++;
  5850. }
  5851. // Place codebase in list in a random order so that redundant codebases
  5852. // can traverse list in order yet still achieve randomness
  5853. iCount = pcbhList->GetCount();
  5854. if (iCount) {
  5855. // Generate random insertion index, x, in the range:
  5856. // (iLastIndexInCache + 1) <= x < iCount
  5857. if (iCount - iLastIndexInCache == 1) {
  5858. // must add at tail, since last list entry == last cache entry
  5859. pcbhList->AddTail(pcbh);
  5860. } else {
  5861. iIndex = (iLastIndexInCache + 1) + (randnum() % (iCount - iLastIndexInCache));
  5862. if (iIndex == iCount) {
  5863. pcbhList->AddTail(pcbh);
  5864. }
  5865. else {
  5866. lpos = pcbhList->FindIndex(iIndex);
  5867. pcbhList->InsertBefore(lpos, pcbh);
  5868. }
  5869. }
  5870. }
  5871. else {
  5872. pcbhList->AddTail(pcbh);
  5873. }
  5874. }
  5875. else {
  5876. // Not random, just ad as tail
  5877. pcbhList->AddTail(pcbh);
  5878. }
  5879. Exit:
  5880. SAFEDELETE(szCodeBase);
  5881. DEBUG_LEAVE(hr);
  5882. return hr;
  5883. }
  5884. #ifdef WX86
  5885. // ---------------------------------------------------------------------------
  5886. // %%Function: CMultiArch::RequirePrimaryArch
  5887. // ---------------------------------------------------------------------------
  5888. HRESULT CMultiArch::RequirePrimaryArch()
  5889. {
  5890. DEBUG_ENTER((DBG_DOWNLOAD,
  5891. Hresult,
  5892. "CMultiArch::RequirePrimaryArch",
  5893. "this=%#x",
  5894. this
  5895. ));
  5896. if (m_RequiredArch != PROCESSOR_ARCHITECTURE_UNKNOWN &&
  5897. m_RequiredArch != (DWORD)g_CPUType) {
  5898. //
  5899. // The required arch has already been set for this download.
  5900. // The download to change the required arch in the middle or
  5901. // else a control and its support pieces may end up getting
  5902. // different architectures.
  5903. //
  5904. DEBUG_LEAVE(E_FAIL);
  5905. return E_FAIL;
  5906. }
  5907. m_RequiredArch = (DWORD)g_CPUType;
  5908. DEBUG_LEAVE(S_OK);
  5909. return S_OK;
  5910. }
  5911. // ---------------------------------------------------------------------------
  5912. // %%Function: CMultiArch::RequireAlternateArch
  5913. // ---------------------------------------------------------------------------
  5914. HRESULT CMultiArch::RequireAlternateArch()
  5915. {
  5916. DEBUG_ENTER((DBG_DOWNLOAD,
  5917. Hresult,
  5918. "CMultiArch::RequireAlternateArch",
  5919. "this=%#x",
  5920. this
  5921. ));
  5922. if (m_RequiredArch != PROCESSOR_ARCHITECTURE_UNKNOWN &&
  5923. m_RequiredArch != PROCESSOR_ARCHITECTURE_INTEL) {
  5924. //
  5925. // The required arch has already been set for this download.
  5926. // The download to change the required arch in the middle or
  5927. // else a control and its support pieces may end up getting
  5928. // different architectures.
  5929. //
  5930. DEBUG_LEAVE(E_FAIL);
  5931. return E_FAIL;
  5932. }
  5933. m_RequiredArch = PROCESSOR_ARCHITECTURE_INTEL;
  5934. DEBUG_LEAVE(S_OK);
  5935. return S_OK;
  5936. }
  5937. // ---------------------------------------------------------------------------
  5938. // %%Function: CMultiArch::SelectArchitecturePreferences
  5939. // ---------------------------------------------------------------------------
  5940. VOID
  5941. CMultiArch::SelectArchitecturePreferences(
  5942. char *szNativeArch,
  5943. char *szIntelArch,
  5944. char **pszPreferredArch,
  5945. char **pszAlternateArch
  5946. )
  5947. {
  5948. DEBUG_ENTER((DBG_DOWNLOAD,
  5949. None,
  5950. "CMultiArch::SelectArchitecturePreferences",
  5951. "this=%#x, %.80q, %.80q, %#x, %#x",
  5952. this, szNativeArch, szIntelArch, pszPreferredArch, pszAlternateArch
  5953. ));
  5954. if (g_fWx86Present) {
  5955. switch (m_RequiredArch) {
  5956. case PROCESSOR_ARCHITECTURE_INTEL:
  5957. // An i386 binary has already been downloaded. Only download
  5958. // i386 binaries now.
  5959. *pszPreferredArch = szIntelArch;
  5960. *pszAlternateArch = NULL;
  5961. break;
  5962. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  5963. // No binaries downloaded so far. Prefer native and fallback
  5964. // to i386
  5965. *pszPreferredArch = szNativeArch;
  5966. *pszAlternateArch = szIntelArch;
  5967. break;
  5968. default:
  5969. // A native binary has already been downloaded. Only download
  5970. // native binaries now.
  5971. *pszPreferredArch = szNativeArch;
  5972. *pszAlternateArch = NULL;
  5973. }
  5974. } else {
  5975. // No Wx86
  5976. *pszPreferredArch = szNativeArch;
  5977. *pszAlternateArch = NULL;
  5978. }
  5979. DEBUG_LEAVE(0);
  5980. }
  5981. #endif