Source code of Windows XP (NT5)
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.

2882 lines
85 KiB

  1. // ===========================================================================
  2. // File: CDLAPI.CXX
  3. // The main code downloader api file.
  4. //
  5. #include <cdlpch.h>
  6. #include <mshtmhst.h>
  7. #include <shlwapi.h>
  8. #include <inseng.h>
  9. // globals for code downloader
  10. CMutexSem g_mxsCodeDownloadGlobals;
  11. LCID g_lcidBrowser = 0x409; // default to english
  12. char g_szBrowserLang[20];
  13. int g_lenBrowserLang = 20;
  14. char g_szBrowserPrimaryLang[20];
  15. int g_lenBrowserPrimaryLang = 20;
  16. // Use SetupApi by default!
  17. DWORD g_dwCodeDownloadSetupFlags = CDSF_USE_SETUPAPI;
  18. char g_szOCXCacheDir[MAX_PATH];
  19. char g_szOCXTempDir[MAX_PATH];
  20. int g_OCXCacheDirSize = 0;
  21. static BOOL g_fHaveCacheDir = FALSE;
  22. BOOL g_OSInfoInitialized = FALSE;
  23. int g_CPUType = PROCESSOR_ARCHITECTURE_UNKNOWN; // default
  24. BOOL g_fRunningOnNT = FALSE;
  25. BOOL g_bRunOnWin95 = FALSE;
  26. #ifdef WX86
  27. BOOL g_fWx86Present; // Set if running on RISC and Wx86 is installed
  28. #endif
  29. BOOL g_bLockedDown = FALSE;
  30. // New default name for ActiveX cache folder! We only use this if occache fails to set up the cache folder.
  31. // const static char *g_szOCXDir = "OCCACHE";
  32. const char *g_szOCXDir = "Downloaded Program Files";
  33. const char *g_szActiveXCache = "ActiveXCache";
  34. const char *g_szRegKeyActiveXCache = "ActiveX Cache";
  35. // This is the client platform specific location name that we look for in INF
  36. // and is built by concatenating g_szProcessorTypes at end of g_szLocPrefix
  37. char g_szPlatform[17]; // sizeof("file-win32-alpha"), (longest possible)
  38. static char *g_szLocPrefix="file-win32-";
  39. // directly indexed into with PROCESSOR_ARCH* returned by GetSystemInfo..
  40. // The "" ones are those we don't support.
  41. char *g_szProcessorTypes[] = {
  42. "x86",
  43. "",
  44. "",
  45. "",
  46. "",
  47. "",
  48. "ia64",
  49. "",
  50. "",
  51. "amd64"
  52. };
  53. // used for Accept Types doing http based platform independence
  54. // use alpha as the longest of possible g_szProcessorTypes strings
  55. static char *g_szCABAcceptPrefix = "application/x-cabinet-win32-";
  56. static char *g_szPEAcceptPrefix = "application/x-pe-win32-";
  57. // Name of dll that implements ActiveX control cache shell extension
  58. const char *g_szActiveXCacheDll = "occache.dll";
  59. // list that goes into accept types
  60. // this first 2 left null to substitue with strings for this platform (cab, pe)
  61. // the number of media types are are registering as Accept types for
  62. // HTTP based contente negotiation
  63. #ifdef WX86
  64. #define CDL_NUM_TYPES 7
  65. #else
  66. #define CDL_NUM_TYPES 5
  67. #endif
  68. LPSTR g_rgszMediaStr[CDL_NUM_TYPES] =
  69. {
  70. CFSTR_MIME_NULL,
  71. CFSTR_MIME_NULL,
  72. CFSTR_MIME_RAWDATASTRM,
  73. "application/x-setupscript",
  74. "*/*",
  75. #ifdef WX86
  76. CFSTR_MIME_NULL,
  77. CFSTR_MIME_NULL,
  78. #endif
  79. };
  80. CLIPFORMAT g_rgclFormat[CDL_NUM_TYPES];
  81. FORMATETC g_rgfmtetc[CDL_NUM_TYPES];
  82. IEnumFORMATETC *g_pEFmtETC;
  83. extern COleAutDll g_OleAutDll;
  84. typedef HRESULT (STDAPICALLTYPE *PFNCOINSTALL)(
  85. IBindCtx *pbc,
  86. DWORD dwFlags,
  87. uCLSSPEC *pClassSpec,
  88. QUERYCONTEXT *pQuery,
  89. LPWSTR pszCodeBase);
  90. PFNCOINSTALL g_pfnCoInstall=NULL;
  91. BOOL g_bCheckedForCoInstall=FALSE;
  92. HMODULE g_hOLE32 = 0;
  93. BOOL g_bUseOLECoInstall = FALSE;
  94. HRESULT GetClassFromExt(LPSTR pszExt, CLSID *pclsid);
  95. STDAPI
  96. WrapCoInstall (
  97. REFCLSID rCLASSID, // CLSID of object (may be NULL)
  98. LPCWSTR szCODE, // URL to code (may be NULL)
  99. DWORD dwFileVersionMS, // Version of primary object
  100. DWORD dwFileVersionLS, // Version of primary object
  101. LPCWSTR szTYPE, // MIME type (may be NULL)
  102. LPBINDCTX pBindCtx, // Bind ctx
  103. DWORD dwClsContext, // CLSCTX flags
  104. LPVOID pvReserved, // Must be NULL
  105. REFIID riid, // Usually IID_IClassFactory
  106. DWORD flags
  107. );
  108. #define WRAP_OLE32_COINSTALL
  109. STDAPI PrivateCoInstall(
  110. IBindCtx *pbc,
  111. DWORD dwFlags,
  112. uCLSSPEC *pClassSpec,
  113. QUERYCONTEXT *pQuery,
  114. LPWSTR pszCodeBase);
  115. /*
  116. * RegisterNewActiveXCacheFolder
  117. * change default ActiveX Cache path to lpszNewPath and properly
  118. * updates all registry entries
  119. */
  120. /*
  121. LONG RegisterNewActiveXCacheFolder(LPCTSTR lpszNewPath, DWORD dwPathLen)
  122. {
  123. Assert(lpszNewPath != NULL && lpszNewPath[0] != '\0');
  124. if (lpszNewPath == NULL || lpszNewPath[0] == '\0')
  125. return ERROR_BAD_ARGUMENTS;
  126. LONG lResult = ERROR_SUCCESS;
  127. HKEY hkeyIntSetting = NULL;
  128. HKEY hkeyActiveXCache = NULL;
  129. char szOldPath[MAX_PATH];
  130. char szPath[MAX_PATH];
  131. char szSubKey[MAX_PATH];
  132. DWORD dwLen = MAX_PATH;
  133. DWORD dwKeyLen = MAX_PATH;
  134. DWORD dwIndex = 0;
  135. BOOL fOldFound = FALSE;
  136. BOOL fNewFound = FALSE;
  137. BOOL fEqual = FALSE;
  138. LONG lValueIndex = -1;
  139. lResult = RegOpenKeyEx(
  140. HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS,
  141. 0, KEY_ALL_ACCESS, &hkeyIntSetting);
  142. if (lResult != ERROR_SUCCESS)
  143. goto Exit;
  144. // read ActiveXCache
  145. lResult = RegQueryValueEx(
  146. hkeyIntSetting, g_szActiveXCache, NULL, NULL,
  147. (LPBYTE)szOldPath, &dwLen);
  148. if (lResult != ERROR_SUCCESS)
  149. {
  150. fOldFound = TRUE;
  151. szOldPath[0] = '\0';
  152. }
  153. fEqual = (lstrcmpi(lpszNewPath, szOldPath) == 0);
  154. lResult = RegSetValueEx(
  155. hkeyIntSetting, g_szActiveXCache, 0, REG_SZ,
  156. (LPBYTE)lpszNewPath, dwPathLen);
  157. if (lResult != ERROR_SUCCESS)
  158. goto Exit;
  159. // Check to see if new path already exists in the list of paths under
  160. // HKLM\...\Windows\CurrentVersion\Internet Settings\ActiveX Cache\Paths.
  161. // If not, add it.
  162. lResult = RegCreateKey(
  163. hkeyIntSetting, g_szRegKeyActiveXCache,
  164. &hkeyActiveXCache);
  165. if (lResult != ERROR_SUCCESS)
  166. goto Exit;
  167. for (dwLen = dwKeyLen = MAX_PATH;
  168. lResult == ERROR_SUCCESS;
  169. dwLen = dwKeyLen = MAX_PATH)
  170. {
  171. lResult = RegEnumValue(
  172. hkeyActiveXCache, dwIndex++, szSubKey, &dwKeyLen,
  173. NULL, NULL, (LPBYTE)szPath, &dwLen);
  174. if (lResult == ERROR_SUCCESS)
  175. {
  176. // for find new unique value name later.
  177. lValueIndex = max(lValueIndex, atol(szSubKey));
  178. if (!fNewFound)
  179. fNewFound = (lstrcmpi(lpszNewPath, szPath) == 0);
  180. if (!fOldFound)
  181. fOldFound = (lstrcmpi(szOldPath, szPath) == 0);
  182. }
  183. }
  184. // something goes wrong!
  185. if (lResult != ERROR_NO_MORE_ITEMS)
  186. goto Exit;
  187. // Add lpszNewPath to the list of paths
  188. lResult = ERROR_SUCCESS;
  189. // keep registry intact
  190. if (!fOldFound && szOldPath[0] != '\0')
  191. {
  192. wsprintf(szSubKey, "%i", ++lValueIndex);
  193. lResult = RegSetValueEx(
  194. hkeyActiveXCache, szSubKey, 0, REG_SZ,
  195. (LPBYTE)szOldPath, lstrlen(szOldPath) + 1);
  196. }
  197. // add new path to list of paths
  198. if (lResult == ERROR_SUCCESS && !fNewFound && !fEqual)
  199. {
  200. wsprintf(szSubKey, "%i", ++lValueIndex);
  201. lResult = RegSetValueEx(
  202. hkeyActiveXCache, szSubKey, 0, REG_SZ,
  203. (LPBYTE)lpszNewPath, dwPathLen);
  204. }
  205. Exit:
  206. // restore old state if failed
  207. if (lResult != ERROR_SUCCESS)
  208. {
  209. if (szOldPath[0] == '\0')
  210. RegDeleteValue(hkeyIntSetting, g_szActiveXCache);
  211. else
  212. RegSetValueEx(
  213. hkeyIntSetting, g_szActiveXCache, 0, REG_SZ,
  214. (LPBYTE)lpszNewPath, dwPathLen);
  215. }
  216. if (hkeyActiveXCache != NULL)
  217. RegCloseKey(hkeyActiveXCache);
  218. if (hkeyIntSetting != NULL)
  219. RegCloseKey(hkeyIntSetting);
  220. return lResult;
  221. }
  222. LONG SwitchToNewCachePath(LPCSTR lpszNewPath, DWORD dwPathLen)
  223. {
  224. Assert(lpszNewPath != NULL);
  225. if (lpszNewPath == NULL)
  226. return ERROR_BAD_ARGUMENTS;
  227. LONG lResult = ERROR_SUCCESS;
  228. char szKey[MAX_PATH];
  229. char szPath[MAX_PATH];
  230. char *pCh = NULL;
  231. HKEY hkey = NULL;
  232. DWORD dwIndex = 0;
  233. DWORD dwLen = MAX_PATH;
  234. wsprintf(szKey, "%s\\%s", REGSTR_PATH_IE_SETTINGS, g_szRegKeyActiveXCache);
  235. lResult = RegOpenKeyEx(
  236. HKEY_LOCAL_MACHINE, szKey,
  237. 0, KEY_ALL_ACCESS, &hkey);
  238. for (; lResult == ERROR_SUCCESS; dwLen = MAX_PATH)
  239. {
  240. lResult = RegEnumValue(
  241. hkey, dwIndex++, szKey, &dwLen,
  242. NULL, NULL, (LPBYTE)szPath, &dwLen);
  243. if (lResult == ERROR_SUCCESS && lstrcmpi(szPath, lpszNewPath) == 0)
  244. break;
  245. }
  246. RegCloseKey(hkey);
  247. if (lResult != ERROR_SUCCESS)
  248. return RegisterNewActiveXCacheFolder(lpszNewPath, dwPathLen);
  249. // return fail to indicate that path has not been changed to
  250. // Downloaded ActiveX Controls
  251. return HRESULT_CODE(E_FAIL);
  252. }
  253. */
  254. HRESULT
  255. SetCoInstall()
  256. {
  257. DEBUG_ENTER((DBG_DOWNLOAD,
  258. Hresult,
  259. "SetCoInstall",
  260. NULL
  261. ));
  262. HKEY hKeyIESettings = 0;
  263. //execute entire function under critical section
  264. CLock lck(g_mxsCodeDownloadGlobals);
  265. if (!g_bCheckedForCoInstall && !g_pfnCoInstall)
  266. {
  267. // So we don't keep rechecking for this api.
  268. g_bCheckedForCoInstall = TRUE;
  269. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0,
  270. KEY_READ, &hKeyIESettings) == ERROR_SUCCESS) {
  271. if (RegQueryValueEx(hKeyIESettings, REGVAL_USE_COINSTALL, NULL,
  272. NULL, NULL, 0) != ERROR_SUCCESS) {
  273. g_bUseOLECoInstall = FALSE;
  274. g_pfnCoInstall = NULL;
  275. RegCloseKey(hKeyIESettings);
  276. DEBUG_LEAVE(S_OK);
  277. return S_OK;
  278. }
  279. RegCloseKey(hKeyIESettings);
  280. }
  281. // find CoInstall entry point in OLE32
  282. if (!g_hOLE32)
  283. {
  284. // BUGBUG: We never FreeLibrary on this. Realisticly, someone else will probably already be using this
  285. // and it will be in use throughout the life of the process, so we won't worry too much.
  286. g_hOLE32 = LoadLibraryA("ole32.dll");
  287. }
  288. if(g_hOLE32 != 0)
  289. {
  290. void *pfn = GetProcAddress(g_hOLE32, "CoInstall");
  291. if(pfn != NULL)
  292. {
  293. g_bUseOLECoInstall = TRUE;
  294. g_pfnCoInstall = (PFNCOINSTALL) pfn;
  295. }
  296. }
  297. }
  298. DEBUG_LEAVE(S_OK);
  299. return S_OK;
  300. }
  301. VOID
  302. DetermineOSAndCPUVersion()
  303. {
  304. DEBUG_ENTER((DBG_DOWNLOAD,
  305. None,
  306. "DetermineOSAndCPUVersion",
  307. NULL
  308. ));
  309. OSVERSIONINFO osvi;
  310. SYSTEM_INFO sysinfo;
  311. //execute entire function under critical section
  312. CLock lck(g_mxsCodeDownloadGlobals);
  313. if (g_OSInfoInitialized) {
  314. DEBUG_LEAVE(0);
  315. return;
  316. }
  317. // Determine which version of NT we're running on
  318. osvi.dwOSVersionInfoSize = sizeof(osvi);
  319. GetVersionEx(&osvi);
  320. g_fRunningOnNT = (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId);
  321. if (osvi.dwPlatformId & VER_PLATFORM_WIN32_WINDOWS &&
  322. osvi.dwMinorVersion == 0) {
  323. g_bRunOnWin95 = TRUE;
  324. }
  325. else {
  326. g_bRunOnWin95 = FALSE;
  327. }
  328. #ifdef WX86
  329. if (g_bNT5OrGreater) {
  330. //
  331. // The pre-alpha Wx86 that runs on NT 4.0 does not support
  332. // x86 ActiveX controls inside a RISC host. Only call Wx86
  333. // on NT 5.0 machines.
  334. //
  335. HKEY hKey;
  336. LONG Error;
  337. // Temp hack: allow users to disable Wx86 support in URLMON if this
  338. // key is present.
  339. // bugbug: probably rip this before ship.
  340. Error = ::RegOpenKeyW(HKEY_LOCAL_MACHINE,
  341. L"System\\CurrentControlSet\\Control\\Wx86\\DisableCDL",
  342. &hKey);
  343. if (Error == ERROR_SUCCESS) {
  344. ::RegCloseKey(hKey);
  345. } else {
  346. g_fWx86Present = TRUE;
  347. }
  348. }
  349. #endif // WX86
  350. GetSystemInfo(&sysinfo);
  351. switch(sysinfo.wProcessorArchitecture) {
  352. case PROCESSOR_ARCHITECTURE_INTEL:
  353. case PROCESSOR_ARCHITECTURE_AMD64:
  354. case PROCESSOR_ARCHITECTURE_IA64:
  355. g_CPUType = sysinfo.wProcessorArchitecture;
  356. break;
  357. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  358. default:
  359. g_CPUType = PROCESSOR_ARCHITECTURE_UNKNOWN;
  360. break;
  361. }
  362. g_OSInfoInitialized = TRUE;
  363. DEBUG_LEAVE(0);
  364. }
  365. /*
  366. * SetGlobals
  367. * set all the globals for the Code Downloader
  368. * called from AsyncGetClassBits. executes under a crit section
  369. */
  370. HRESULT
  371. SetGlobals()
  372. {
  373. DEBUG_ENTER((DBG_DOWNLOAD,
  374. Hresult,
  375. "SetGlobals",
  376. NULL
  377. ));
  378. SYSTEM_INFO sysinfo;
  379. int nCPUType;
  380. HRESULT hr = S_OK;
  381. DWORD lResult;
  382. // static const char szActiveXCache[] = "ActiveXCache";
  383. BOOL fRegActiveXCacheDll = FALSE; // do we need to register occache.dll?
  384. //execute entire function under critical section
  385. CLock lck(g_mxsCodeDownloadGlobals);
  386. if (!g_fHaveCacheDir) {
  387. // do some init: get ocx ccahe dir
  388. DWORD Size = MAX_PATH;
  389. DWORD dwType;
  390. HKEY hKeyIESettings = 0;
  391. char szOldCacheDir[MAX_PATH];
  392. int len = 0;
  393. int CdlNumTypes;
  394. lResult = ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0,
  395. KEY_READ, &hKeyIESettings );
  396. if (lResult != ERROR_SUCCESS) {
  397. hr = HRESULT_FROM_WIN32(lResult);
  398. goto Exit;
  399. }
  400. // Get Code Download flags
  401. dwType = REG_DWORD;
  402. Size = sizeof(DWORD);
  403. lResult = ::RegQueryValueEx(hKeyIESettings, "CodeDownloadFlags",
  404. NULL, &dwType, (unsigned char *)&g_dwCodeDownloadSetupFlags, &Size);
  405. Size = MAX_PATH;
  406. dwType = REG_SZ;
  407. // Get existing cache path from registry
  408. lResult = ::RegQueryValueEx(hKeyIESettings, g_szActiveXCache,
  409. NULL, &dwType, (unsigned char *)g_szOCXCacheDir, &Size);
  410. if (lResult != ERROR_SUCCESS ||
  411. !PathFileExists( g_szOCXCacheDir ) )
  412. {
  413. // OC Cache didn't set up the registry for us...
  414. // Load it to make sure it has done if regsvring work...
  415. HRESULT hr = E_FAIL;
  416. HINSTANCE h = LoadLibrary(g_szActiveXCacheDll);
  417. HRESULT (STDAPICALLTYPE *pfnReg)(void);
  418. HRESULT (STDAPICALLTYPE *pfnInst)(BOOL bInstall, LPCWSTR pszCmdLine);
  419. if (h != NULL)
  420. {
  421. (FARPROC&)pfnReg = GetProcAddress(h, "DllRegisterServer");
  422. if (pfnReg != NULL)
  423. hr = (*pfnReg)();
  424. // also need to call DllInstall to complete the wiring of the shell extension
  425. (FARPROC&)pfnInst = GetProcAddress(h, "DllInstall");
  426. if (pfnInst != NULL)
  427. hr = (*pfnInst)( TRUE, L"");
  428. FreeLibrary(h);
  429. }
  430. // Retry now that we're sure OCCACHE has had a shot at setting things up for us
  431. if ( SUCCEEDED(hr) )
  432. lResult = ::RegQueryValueEx(hKeyIESettings, g_szActiveXCache,
  433. NULL, &dwType, (unsigned char *)g_szOCXCacheDir, &Size);
  434. if ( lResult != ERROR_SUCCESS ) {
  435. // OC Cache is having a bad day. Don't let this stop code download.
  436. // Compose the default path and see if we need to change
  437. // old cache path to the new default path.
  438. if(!(len = GetWindowsDirectory(g_szOCXCacheDir, MAX_PATH)))
  439. g_szOCXCacheDir[0] = '\0';
  440. else
  441. {
  442. Assert(len <= MAX_PATH);
  443. if (g_szOCXCacheDir[len-1] != '\\')
  444. lstrcat(g_szOCXCacheDir, "\\");
  445. }
  446. StrNCat(g_szOCXCacheDir, g_szOCXDir,MAX_PATH-len-2);
  447. // OC Cache or not, remember our directory
  448. HKEY hkeyWriteIESettings;
  449. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS,0,
  450. KEY_ALL_ACCESS, &hkeyWriteIESettings ) == ERROR_SUCCESS) {
  451. RegSetValueEx(hkeyWriteIESettings,g_szActiveXCache,0,REG_SZ,
  452. (LPBYTE)g_szOCXCacheDir, lstrlen(g_szOCXCacheDir) + 1);
  453. RegCloseKey(hkeyWriteIESettings);
  454. }
  455. }
  456. // load oleaut32.dll
  457. lResult = g_OleAutDll.Init();
  458. } // if reg key not set up.
  459. if (hKeyIESettings) {
  460. RegCloseKey(hKeyIESettings);
  461. hKeyIESettings = 0;
  462. }
  463. DWORD dwAttr = GetFileAttributes(g_szOCXCacheDir);
  464. if (dwAttr == -1) {
  465. if (!CreateDirectory(g_szOCXCacheDir, NULL)) {
  466. hr = HRESULT_FROM_WIN32(GetLastError());
  467. goto Exit;
  468. }
  469. // if cache dir has just been created, we also need
  470. // to register occache shell extension
  471. fRegActiveXCacheDll = TRUE;
  472. } else {
  473. if ( (!(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) ||
  474. (dwAttr & FILE_ATTRIBUTE_READONLY)) {
  475. hr = OLE_E_NOCACHE; // closest we can get to!
  476. goto Exit;
  477. }
  478. }
  479. if (!GetTempPath(MAX_PATH, g_szOCXTempDir) ) {
  480. hr = HRESULT_FROM_WIN32(GetLastError());
  481. goto Exit;
  482. }
  483. // Set up g_bRunningOnNT, g_CpuType, and g_fWx86Present
  484. DetermineOSAndCPUVersion();
  485. // Record client architecture to make proper accept types
  486. // and to use in INF for platform independent CODE=URL
  487. LPSTR pBaseFileName = NULL;
  488. InitBrowserLangStrings();
  489. nCPUType = g_CPUType;
  490. if (g_CPUType == PROCESSOR_ARCHITECTURE_UNKNOWN) {
  491. nCPUType = PROCESSOR_ARCHITECTURE_INTEL;
  492. }
  493. lstrcpy(g_szPlatform, g_szLocPrefix);
  494. lstrcat(g_szPlatform, g_szProcessorTypes[nCPUType]);
  495. // Register the Media types
  496. // first build up the table of eight types we send out
  497. char szCABStr[MAX_PATH];
  498. char szPEStr[MAX_PATH];
  499. lstrcpy(szCABStr, g_szCABAcceptPrefix);
  500. lstrcat(szCABStr, g_szProcessorTypes[nCPUType]);
  501. lstrcpy(szPEStr, g_szPEAcceptPrefix);
  502. lstrcat(szPEStr, g_szProcessorTypes[nCPUType]);
  503. g_rgszMediaStr[0] = szCABStr;
  504. g_rgszMediaStr[1] = szPEStr;
  505. #ifdef WX86
  506. char szCABStrX86[MAX_PATH];
  507. char szPEStrX86[MAX_PATH];
  508. if (g_fWx86Present) {
  509. g_rgszMediaStr[6] = g_rgszMediaStr[4]; // move "*/*" to the end of the list
  510. lstrcpy(szCABStrX86, g_szCABAcceptPrefix);
  511. lstrcat(szCABStrX86, g_szProcessorTypes[PROCESSOR_ARCHITECTURE_INTEL]);
  512. lstrcpy(szPEStrX86, g_szPEAcceptPrefix);
  513. lstrcat(szPEStrX86, g_szProcessorTypes[PROCESSOR_ARCHITECTURE_INTEL]);
  514. g_rgszMediaStr[4] = szCABStrX86;
  515. g_rgszMediaStr[5] = szPEStrX86;
  516. CdlNumTypes = CDL_NUM_TYPES;
  517. } else {
  518. CdlNumTypes = CDL_NUM_TYPES-2;
  519. }
  520. #else
  521. CdlNumTypes = CDL_NUM_TYPES;
  522. #endif
  523. hr = RegisterMediaTypes(CdlNumTypes, (const LPCSTR *)g_rgszMediaStr, g_rgclFormat);
  524. if (FAILED(hr))
  525. goto Exit;
  526. // initialize the formatetc array
  527. for (int i=0; i< CdlNumTypes; i++) {
  528. g_rgfmtetc[i].cfFormat = g_rgclFormat[i];
  529. g_rgfmtetc[i].tymed = TYMED_NULL;
  530. g_rgfmtetc[i].dwAspect = DVASPECT_CONTENT;
  531. g_rgfmtetc[i].ptd = NULL;
  532. }
  533. // BUGBUG: leaked!
  534. hr = CreateFormatEnumerator(CdlNumTypes, g_rgfmtetc, &g_pEFmtETC);
  535. if (FAILED(hr))
  536. goto Exit;
  537. if (g_bNT5OrGreater) {
  538. HKEY hkeyLockedDown = 0;
  539. // Test for lock-down. If we cannot write to HKLM, then we are in
  540. // a locked-down environment, and should abort right away.
  541. if (RegCreateKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_NT5_LOCKDOWN_TEST,
  542. &hkeyLockedDown) != ERROR_SUCCESS) {
  543. // We are in lock-down mode; abort.
  544. g_bLockedDown = TRUE;
  545. }
  546. else {
  547. // Not locked-down. Delete the key, and continue
  548. RegCloseKey(hkeyLockedDown);
  549. RegDeleteKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_NT5_LOCKDOWN_TEST);
  550. g_bLockedDown = FALSE;
  551. }
  552. }
  553. g_fHaveCacheDir = TRUE;
  554. }
  555. Exit:
  556. if (FAILED(hr))
  557. {
  558. UrlMkDebugOut((DEB_CODEDL, "ERR CodeDownload failed to initialize: hr(%lx)\n", hr));
  559. }
  560. DEBUG_LEAVE(hr);
  561. return hr;
  562. }
  563. #define CLSID_ActiveXPlugin \
  564. {0x06DD38D3L,0xD187,0x11CF, \
  565. {0xA8,0x0D,0x00,0xC0,0x4F,0xD7,0x4A,0xD8}}
  566. //
  567. // FindPlugin - delegates this call to the plugin OCX
  568. //
  569. BOOL FindPlugin(char *szFileExt, char *szName, char *szMime)
  570. {
  571. DEBUG_ENTER((DBG_DOWNLOAD,
  572. Bool,
  573. "FindPlugin",
  574. "%.80q, %.80q, %.80q",
  575. szFileExt, szName, szMime
  576. ));
  577. typedef BOOL (WINAPI *LPFINDPLUGIN_API)(char *ext, char *name, char *mime);
  578. LPFINDPLUGIN_API pfnFindPlugin;
  579. BOOL fRet = FALSE;
  580. HMODULE hLib = LoadLibrary("plugin.ocx");
  581. if (hLib == NULL) {
  582. goto Exit;
  583. }
  584. pfnFindPlugin = (LPFINDPLUGIN_API)GetProcAddress(hLib, "FindPluginA");
  585. if (pfnFindPlugin == NULL) {
  586. goto Exit;
  587. }
  588. fRet = pfnFindPlugin(szFileExt, szName, szMime);
  589. Exit:
  590. if (hLib)
  591. FreeLibrary(hLib);
  592. DEBUG_LEAVE(fRet);
  593. return fRet;
  594. }
  595. // GetClsidFromExtOrMime
  596. // fills up clsidout with rCLASSID if not CLSID_NULL
  597. // or gets clsid from passed in ext or mime type
  598. // returns:
  599. // S_OK
  600. // S_FALSE: couldn't convert to a clsid
  601. HRESULT
  602. GetClsidFromExtOrMime(
  603. REFCLSID rclsid,
  604. CLSID &clsidout,
  605. LPCWSTR szExt,
  606. LPCWSTR szTYPE,
  607. LPSTR *ppFileName)
  608. {
  609. DEBUG_ENTER((DBG_DOWNLOAD,
  610. Hresult,
  611. "GetClsidFromExtOrMime",
  612. "%#x, %#x, %.80wq, %.80wq, %#x",
  613. &rclsid, &clsidout, szExt, szTYPE, ppFileName
  614. ));
  615. BOOL fNullClsid;
  616. HRESULT hr = S_OK;
  617. char szTypeA[MAX_PATH];
  618. char szExtA[MAX_PATH];
  619. LPSTR lpName = NULL;
  620. memcpy(&clsidout, &rclsid, sizeof(GUID));
  621. if ((fNullClsid = IsEqualGUID(rclsid , CLSID_NULL))) {
  622. if (!szTYPE && !szExt) {
  623. hr = S_FALSE;
  624. goto Exit;
  625. }
  626. if (szTYPE) {
  627. if (!WideCharToMultiByte(CP_ACP, 0 , szTYPE ,
  628. -1 ,szTypeA, MAX_PATH, NULL, NULL)) {
  629. hr = HRESULT_FROM_WIN32(GetLastError());
  630. goto Exit;
  631. }
  632. // convert the mime/type into a clsid
  633. if (SUCCEEDED((GetClassMime(szTypeA, &clsidout)))) {
  634. fNullClsid = FALSE;
  635. }
  636. } else { // szExt
  637. if (!WideCharToMultiByte(CP_ACP, 0 , szExt ,
  638. -1 ,szExtA, MAX_PATH, NULL, NULL)) {
  639. hr = HRESULT_FROM_WIN32(GetLastError());
  640. goto Exit;
  641. }
  642. if (SUCCEEDED(GetClassFromExt(szExtA, &clsidout))) {
  643. fNullClsid = FALSE;
  644. }
  645. }
  646. }
  647. Exit:
  648. if ((hr == S_OK) && fNullClsid) {
  649. // still no clsid
  650. char szName[MAX_PATH];
  651. BOOL bRet = FindPlugin(szExtA, szName, szTypeA);
  652. if (bRet) {
  653. // found a plugin, instantiate the plugin ocx
  654. CLSID plug = CLSID_ActiveXPlugin;
  655. clsidout = plug;
  656. if (ppFileName) {
  657. lpName = new char [lstrlen(szName) + 1];
  658. if (lpName)
  659. lstrcpy(lpName, szName);
  660. else
  661. hr = E_OUTOFMEMORY;
  662. }
  663. } else {
  664. // not a plugin either!
  665. hr = S_FALSE;
  666. }
  667. }
  668. if (ppFileName) {
  669. *ppFileName = lpName;
  670. }
  671. DEBUG_LEAVE(hr);
  672. return hr;
  673. }
  674. //BUGBUG this must be defined in a public header. Is currently in ole32\ih\ole2com.h.
  675. #if defined(_X86_)
  676. #define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_INTEL
  677. #elif defined(_AMD64_)
  678. #define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_AMD64
  679. #elif defined(_IA64_)
  680. #define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_IA64
  681. #else
  682. #define DEFAULT_ARCHITECTURE PROCESSOR_ARCHITECTURE_UNKNOWN
  683. #endif
  684. //+-------------------------------------------------------------------------
  685. //
  686. // Function: GetDefaultPlatform (internal)
  687. //
  688. // Synopsis: Gets the current platform
  689. //
  690. // Returns: none
  691. //
  692. //--------------------------------------------------------------------------
  693. void
  694. GetDefaultPlatform(CSPLATFORM *pPlatform)
  695. {
  696. DEBUG_ENTER((DBG_DOWNLOAD,
  697. None,
  698. "GetDefaultPlatform",
  699. "%#x",
  700. pPlatform
  701. ));
  702. OSVERSIONINFO VersionInformation;
  703. VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  704. GetVersionEx(&VersionInformation);
  705. pPlatform->dwPlatformId = VersionInformation.dwPlatformId;
  706. pPlatform->dwVersionHi = VersionInformation.dwMajorVersion;
  707. pPlatform->dwVersionLo = VersionInformation.dwMinorVersion;
  708. pPlatform->dwProcessorArch = DEFAULT_ARCHITECTURE;
  709. DEBUG_LEAVE(0);
  710. }
  711. //+-------------------------------------------------------------------------
  712. //
  713. // Function: GetActiveXSafetyProvider (internal)
  714. //
  715. // Synopsis: Gets the ActiveXSafetyProvider, if there is one installed.
  716. //
  717. // Returns: none
  718. //
  719. //--------------------------------------------------------------------------
  720. HRESULT
  721. GetActiveXSafetyProvider(IActiveXSafetyProvider **ppProvider)
  722. {
  723. DEBUG_ENTER((DBG_DOWNLOAD,
  724. Hresult,
  725. "GetActiveXSafetyProvider",
  726. "%#x",
  727. ppProvider
  728. ));
  729. HRESULT hr;
  730. LONG l;
  731. HKEY hKey;
  732. //
  733. // See if an IActiveXSafetyProvider is present by peeking into the
  734. // registry.
  735. //
  736. l = RegOpenKeyA(HKEY_CLASSES_ROOT,
  737. "CLSID\\{aaf8c6ce-f972-11d0-97eb-00aa00615333}",
  738. &hKey
  739. );
  740. if (l != ERROR_SUCCESS) {
  741. //
  742. // No ActiveXSafetyProvider installed.
  743. //
  744. *ppProvider = NULL;
  745. DEBUG_LEAVE(S_OK);
  746. return S_OK;
  747. }
  748. RegCloseKey(hKey);
  749. //
  750. // Call OLE to instantiate the ActiveXSafetyProvider.
  751. //
  752. hr = CoCreateInstance(CLSID_IActiveXSafetyProvider,
  753. NULL,
  754. CLSCTX_INPROC_SERVER,
  755. IID_IActiveXSafetyProvider,
  756. (void **)ppProvider
  757. );
  758. DEBUG_LEAVE(hr);
  759. return hr;
  760. }
  761. #ifdef WRAP_OLE32_COINSTALL
  762. // This currently breaks trident for unknown reasons.
  763. // For full class store integration (Darwin packages) this will need to be enabled!!!
  764. // ===========================================================================
  765. // CBSCCreateObject Implementation
  766. // ===========================================================================
  767. class CBSCCreateObject : public IServiceProvider,
  768. public IBindStatusCallback
  769. {
  770. private:
  771. DWORD m_cRef;
  772. CLSID m_clsid;
  773. LPWSTR m_szExt;
  774. LPWSTR m_szType;
  775. DWORD m_dwClsContext;
  776. IID m_riid;
  777. IBindStatusCallback* m_pclientbsc;
  778. //IBindCtx* m_pbc;
  779. CRITICAL_SECTION m_sect;
  780. LPVOID m_pvReserved;
  781. BOOL m_bObjectAvailableCalled;
  782. DWORD m_dwFlags;
  783. public:
  784. CBSCCreateObject(REFCLSID rclsid, LPCWSTR szType, LPCWSTR szExt, DWORD dwClsContext,
  785. LPVOID pvReserved, REFIID riid, IBindCtx* pbc, DWORD dwFlags, HRESULT &hr)
  786. {
  787. DEBUG_ENTER((DBG_DOWNLOAD,
  788. None,
  789. "CBSCCreateObject::CBSCCreateObject",
  790. "this=%#x, %#x, %.80wq, %.80wq, %#x, %#x, %#x, %#x, %#x, %#x",
  791. this, &rclsid, szType, szExt, dwClsContext, pvReserved, &riid, pbc, dwFlags, &hr
  792. ));
  793. InitializeCriticalSection(&m_sect);
  794. m_cRef=1;
  795. m_clsid=rclsid;
  796. m_dwClsContext=dwClsContext;
  797. m_pvReserved=pvReserved;
  798. m_riid=riid;
  799. //m_pbc=NULL;
  800. m_pclientbsc=NULL;
  801. m_bObjectAvailableCalled=FALSE;
  802. m_dwFlags = dwFlags;
  803. if ( szType != NULL )
  804. {
  805. m_szType = new WCHAR[lstrlenW(szType) + 1];
  806. if ( m_szType != NULL )
  807. StrCpyW( m_szType, szType );
  808. else
  809. hr = E_OUTOFMEMORY;
  810. }
  811. else
  812. m_szType = NULL;
  813. if ( szExt != NULL )
  814. {
  815. m_szExt = new WCHAR[lstrlenW(szExt) + 1];
  816. if ( m_szExt != NULL )
  817. StrCpyW( m_szExt, szExt );
  818. else
  819. hr = E_OUTOFMEMORY;
  820. }
  821. else
  822. m_szExt = NULL;
  823. if ( SUCCEEDED(hr) )
  824. {
  825. // Get client's BSC and store away for delegation
  826. hr=RegisterBindStatusCallback(pbc, (IBindStatusCallback*) this, &m_pclientbsc, NULL);
  827. if (SUCCEEDED(hr))
  828. {
  829. if (m_pclientbsc)
  830. {
  831. //m_pbc=pbc;
  832. //m_pbc->AddRef();
  833. }
  834. else
  835. {
  836. hr=E_INVALIDARG; // need BSC in bind context!
  837. }
  838. }
  839. }
  840. DEBUG_LEAVE(0);
  841. }
  842. ~CBSCCreateObject()
  843. {
  844. DEBUG_ENTER((DBG_DOWNLOAD,
  845. None,
  846. "CBSCCreateObject::~CBSCCreateObject",
  847. "this=%#x",
  848. this
  849. ));
  850. //RevokeFromBC();
  851. if ( m_szType != NULL )
  852. delete m_szType;
  853. if ( m_szExt != NULL )
  854. delete m_szExt;
  855. if (m_pclientbsc)
  856. {
  857. IBindStatusCallback* pclientbsc=m_pclientbsc;
  858. m_pclientbsc=NULL;
  859. pclientbsc->Release();
  860. }
  861. DeleteCriticalSection(&m_sect);
  862. DEBUG_LEAVE(0);
  863. }
  864. IBindStatusCallback* GetClientBSC()
  865. {
  866. DEBUG_ENTER((DBG_DOWNLOAD,
  867. Pointer,
  868. "CBSCCreateObject::GetClientBSC",
  869. "this=%#x",
  870. this
  871. ));
  872. EnterCriticalSection(&m_sect);
  873. IBindStatusCallback* pbsc=m_pclientbsc;
  874. LeaveCriticalSection(&m_sect);
  875. DEBUG_LEAVE(pbsc);
  876. return pbsc;
  877. }
  878. /* HRESULT RevokeFromBC()
  879. {
  880. // Remove from BSC and reestablish original BSC
  881. HRESULT hr=S_OK;
  882. EnterCriticalSection(&m_sect);
  883. if (m_pbc)
  884. {
  885. IBindCtx* pbc=m_pbc;
  886. IBindStatusCallback* pclientbsc=m_pclientbsc;
  887. m_pbc=NULL;
  888. m_pclientbsc=NULL;
  889. LeaveCriticalSection(&m_sect);
  890. hr=RegisterBindStatusCallback(pbc, pclientbsc, NULL, NULL);
  891. pbc->Release();
  892. if (pclientbsc)
  893. {
  894. pclientbsc->Release();
  895. }
  896. }
  897. else
  898. {
  899. LeaveCriticalSection(&m_sect);
  900. }
  901. return hr;
  902. }
  903. */
  904. STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
  905. {
  906. DEBUG_ENTER((DBG_DOWNLOAD,
  907. Hresult,
  908. "CBSCCreateObject::IUnknown::QueryInterface",
  909. "this=%#x, %#x, %#x",
  910. this, &riid, ppv
  911. ));
  912. HRESULT hr = S_OK;
  913. *ppv = NULL;
  914. if(IsEqualIID(riid, IID_IUnknown) ||
  915. IsEqualIID(riid, IID_IBindStatusCallback))
  916. {
  917. AddRef();
  918. *ppv = (IBindStatusCallback *) this;
  919. }
  920. else if(IsEqualIID(riid, IID_IServiceProvider))
  921. {
  922. AddRef();
  923. *ppv = (IServiceProvider *) this;
  924. }
  925. else
  926. {
  927. hr = E_NOINTERFACE;
  928. }
  929. DEBUG_LEAVE(hr);
  930. return hr;
  931. }
  932. STDMETHODIMP_(ULONG) AddRef()
  933. {
  934. DEBUG_ENTER((DBG_DOWNLOAD,
  935. Hresult,
  936. "CBSCCreateObject::IUnknown::AddRef",
  937. "this=%#x",
  938. this
  939. ));
  940. InterlockedIncrement((long *) &m_cRef);
  941. DEBUG_LEAVE(m_cRef);
  942. return m_cRef;
  943. }
  944. STDMETHODIMP_(ULONG) Release()
  945. {
  946. DEBUG_ENTER((DBG_DOWNLOAD,
  947. Hresult,
  948. "CBSCCreateObject::IUnknown::Release",
  949. "this=%#x",
  950. this
  951. ));
  952. LONG count = m_cRef - 1;
  953. if(0 == InterlockedDecrement((long *) &m_cRef))
  954. {
  955. delete this;
  956. count = 0;
  957. }
  958. DEBUG_LEAVE(count);
  959. return count;
  960. }
  961. // IBindStatusCallback/Holder
  962. STDMETHODIMP OnStartBinding(DWORD grfBSCOption, IBinding* pbinding)
  963. {
  964. DEBUG_ENTER((DBG_DOWNLOAD,
  965. Hresult,
  966. "CBSCCreateObject::IBindStatusCallback::OnStartBinding",
  967. "this=%#x, %#x, %#x",
  968. this, grfBSCOption, pbinding
  969. ));
  970. m_bObjectAvailableCalled=FALSE;
  971. IBindStatusCallback* pclientbsc=GetClientBSC();
  972. HRESULT hr = S_OK;
  973. if (pclientbsc)
  974. hr = pclientbsc->OnStartBinding(grfBSCOption, pbinding);
  975. DEBUG_LEAVE(hr);
  976. return hr;
  977. }
  978. STDMETHODIMP GetPriority(LONG* pnPriority)
  979. {
  980. DEBUG_ENTER((DBG_DOWNLOAD,
  981. Hresult,
  982. "CBSCCreateObject::IBindStatusCallback::GetPriority",
  983. "this=%#x, %#x",
  984. this, pnPriority
  985. ));
  986. IBindStatusCallback* pclientbsc=GetClientBSC();
  987. HRESULT hr = S_OK;
  988. if (pclientbsc)
  989. hr = pclientbsc->GetPriority(pnPriority);
  990. DEBUG_LEAVE(hr);
  991. return hr;
  992. }
  993. STDMETHODIMP OnLowResource(DWORD dwReserved)
  994. {
  995. DEBUG_ENTER((DBG_DOWNLOAD,
  996. Hresult,
  997. "CBSCCreateObject::IBindStatusCallback::OnLowResource",
  998. "this=%#x, %#x",
  999. this, dwReserved
  1000. ));
  1001. IBindStatusCallback* pclientbsc=GetClientBSC();
  1002. HRESULT hr = S_OK;
  1003. if (pclientbsc)
  1004. hr = pclientbsc->OnLowResource(dwReserved);
  1005. DEBUG_LEAVE(hr);
  1006. return hr;
  1007. }
  1008. STDMETHODIMP OnStopBinding(HRESULT hrStatus, LPCWSTR pszError)
  1009. {
  1010. DEBUG_ENTER((DBG_DOWNLOAD,
  1011. Hresult,
  1012. "CBSCCreateObject::IBindStatusCallback::OnStopBinding",
  1013. "this=%#x, %#x, %.80wq",
  1014. this, hrStatus, pszError
  1015. ));
  1016. HRESULT hr=S_OK;
  1017. // Save client BSC for last notification
  1018. IBindStatusCallback* pclientbsc=GetClientBSC();
  1019. if (!pclientbsc)
  1020. {
  1021. DEBUG_LEAVE(hr);
  1022. return hr;
  1023. }
  1024. pclientbsc->AddRef();
  1025. // We are done with this bind context! Unregister before caller unregisters it's IBSC
  1026. //hr=RevokeFromBC();
  1027. if (SUCCEEDED(hrStatus))
  1028. {
  1029. if (!m_bObjectAvailableCalled && (m_dwFlags & CD_FLAGS_NEED_CLASSFACTORY ) )
  1030. {
  1031. IUnknown* punk=NULL;
  1032. CLSID clsid;
  1033. hr = GetClsidFromExtOrMime( m_clsid, clsid, m_szExt, m_szType, NULL );
  1034. if ( SUCCEEDED(hr) )
  1035. hr = CoGetClassObject(clsid, m_dwClsContext, m_pvReserved, m_riid, (void**) &punk);
  1036. if (FAILED(hr))
  1037. {
  1038. hr = pclientbsc->OnStopBinding(hr, L"");
  1039. pclientbsc->Release();
  1040. DEBUG_LEAVE(hr);
  1041. return hr;
  1042. }
  1043. pclientbsc->OnObjectAvailable(m_riid, punk);
  1044. // release the IUnkown returned by CoGetClassObject
  1045. punk->Release();
  1046. m_bObjectAvailableCalled=TRUE;
  1047. }
  1048. }
  1049. hr=pclientbsc->OnStopBinding(hrStatus, pszError);
  1050. pclientbsc->Release();
  1051. DEBUG_LEAVE(hr);
  1052. return hr;
  1053. }
  1054. STDMETHODIMP GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
  1055. {
  1056. DEBUG_ENTER((DBG_DOWNLOAD,
  1057. Hresult,
  1058. "CBSCCreateObject::IBindStatusCallback::GetBindInfo",
  1059. "this=%#x, %#x, %#x",
  1060. this, pgrfBINDF, pbindInfo
  1061. ));
  1062. IBindStatusCallback* pclientbsc=GetClientBSC();
  1063. HRESULT hr = S_OK;
  1064. if (pclientbsc)
  1065. hr = pclientbsc->GetBindInfo(pgrfBINDF, pbindInfo);
  1066. DEBUG_LEAVE(hr);
  1067. return hr;
  1068. }
  1069. STDMETHODIMP OnDataAvailable(
  1070. DWORD grfBSCF,
  1071. DWORD dwSize,
  1072. FORMATETC* pfmtetc,
  1073. STGMEDIUM* pstgmed)
  1074. {
  1075. DEBUG_ENTER((DBG_DOWNLOAD,
  1076. Hresult,
  1077. "CBSCCreateObject::IBindStatusCallback::OnDataAvailable",
  1078. "this=%#x, %#x, %#x, %#x, %#x",
  1079. this, grfBSCF, dwSize, pfmtetc, pstgmed
  1080. ));
  1081. IBindStatusCallback* pclientbsc=GetClientBSC();
  1082. HRESULT hr = S_OK;
  1083. if (pclientbsc)
  1084. hr = pclientbsc->OnDataAvailable(grfBSCF, dwSize, pfmtetc, pstgmed);
  1085. DEBUG_LEAVE(hr);
  1086. return hr;
  1087. }
  1088. STDMETHODIMP OnObjectAvailable(REFIID riid, IUnknown* punk)
  1089. {
  1090. DEBUG_ENTER((DBG_DOWNLOAD,
  1091. Hresult,
  1092. "CBSCCreateObject::IBindStatusCallback::OnObjectAvailable",
  1093. "this=%#x, %#x, %#x",
  1094. this, &riid, punk
  1095. ));
  1096. HRESULT hr=S_OK;
  1097. // Save client BSC
  1098. IBindStatusCallback* pclientbsc=GetClientBSC();
  1099. if (pclientbsc) {
  1100. pclientbsc->AddRef();
  1101. hr=pclientbsc->OnObjectAvailable(riid, punk);
  1102. pclientbsc->Release();
  1103. m_bObjectAvailableCalled=TRUE;
  1104. }
  1105. DEBUG_LEAVE(hr);
  1106. return hr;
  1107. }
  1108. STDMETHODIMP OnProgress
  1109. (
  1110. ULONG ulProgress,
  1111. ULONG ulProgressMax,
  1112. ULONG ulStatusCode,
  1113. LPCWSTR pwzStatusText
  1114. )
  1115. {
  1116. DEBUG_ENTER((DBG_DOWNLOAD,
  1117. Hresult,
  1118. "CBSCCreateObject::IBindStatusCallback::OnProgress",
  1119. "this=%#x, %#x, %#x, %#x, %.80wq",
  1120. this, ulProgress, ulProgressMax, ulStatusCode, pwzStatusText
  1121. ));
  1122. IBindStatusCallback* pclientbsc=GetClientBSC();
  1123. HRESULT hr = S_OK;
  1124. if (pclientbsc)
  1125. hr = pclientbsc->OnProgress(ulProgress, ulProgressMax, ulStatusCode, pwzStatusText);
  1126. DEBUG_LEAVE(hr);
  1127. return hr;
  1128. }
  1129. // IServiceProvider, chains all other interfaces
  1130. STDMETHODIMP QueryService(
  1131. REFGUID rsid,
  1132. REFIID iid,
  1133. void **ppvObj)
  1134. {
  1135. DEBUG_ENTER((DBG_DOWNLOAD,
  1136. Hresult,
  1137. "CBSCCreateObject::IserviceProvider::QueryService",
  1138. "this=%#x, %#x, %#x, %#x",
  1139. this, &rsid, &iid, ppvObj
  1140. ));
  1141. HRESULT hr=S_OK;
  1142. IServiceProvider* pclientsp=NULL;
  1143. hr=m_pclientbsc->QueryInterface(IID_IServiceProvider, (void**) &pclientsp);
  1144. if (SUCCEEDED(hr))
  1145. {
  1146. hr=pclientsp->QueryService(rsid, iid, ppvObj);
  1147. pclientsp->Release();
  1148. if (SUCCEEDED(hr))
  1149. {
  1150. DEBUG_LEAVE(hr);
  1151. return hr;
  1152. }
  1153. }
  1154. IBindStatusCallback* pclientbsc=GetClientBSC();
  1155. if (pclientbsc)
  1156. hr = pclientbsc->QueryInterface(iid, ppvObj);
  1157. else
  1158. hr = QueryInterface(iid, ppvObj);
  1159. DEBUG_LEAVE(hr);
  1160. return hr;
  1161. }
  1162. };
  1163. #endif // WRAP_OLE32_COINSTALL
  1164. /*
  1165. * CoGetClassObjectFromURL
  1166. *
  1167. * This is the exposed entry point into the Code Downloader.
  1168. *
  1169. * It takes parameters closely matching the INSERT tag
  1170. * REFCLSID rCLASSID, // CLSID of object (may be NULL)
  1171. * LPCWSTR szCODE, // URL to code (may be NULL)
  1172. * DWORD dwFileVersionMS, // Version of primary object
  1173. * DWORD dwFileVersionLS, // Version of primary object
  1174. * LPCWSTR szTYPE, // MIME type (may be NULL)
  1175. * LPBINDCTX pBindCtx, // Bind ctx
  1176. * DWORD dwClsContext, // CLSCTX flags
  1177. * LPVOID pvReserved, // Must be NULL
  1178. * REFIID riid, // Usually IID_IClassFactory
  1179. * LPVOID * ppv // Ret - usually IClassFactory *
  1180. */
  1181. STDAPI
  1182. CoGetClassObjectFromURL (
  1183. REFCLSID rCLASSID, // CLSID of object (may be NULL)
  1184. LPCWSTR szCODE, // URL to code (may be NULL)
  1185. DWORD dwFileVersionMS, // Version of primary object
  1186. DWORD dwFileVersionLS, // Version of primary object
  1187. LPCWSTR szTYPE, // MIME type (may be NULL)
  1188. LPBINDCTX pBindCtx, // Bind ctx
  1189. DWORD dwClsContext, // CLSCTX flags
  1190. LPVOID pvReserved, // Must be NULL
  1191. REFIID riid, // Usually IID_IClassFactory
  1192. LPVOID * ppv // Ret - usually IClassFactory *
  1193. )
  1194. {
  1195. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1196. Hresult,
  1197. "CoGetClassObjectFromURL",
  1198. "%#x, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x",
  1199. &rCLASSID, szCODE, dwFileVersionMS, dwFileVersionLS, szTYPE, pBindCtx,
  1200. dwClsContext, pvReserved, &riid, ppv
  1201. ));
  1202. HRESULT hr = NO_ERROR;
  1203. CLSID myclsid;
  1204. int nForceDownload = 0;
  1205. CDLDebugLog * pdlog = NULL;
  1206. CodeDownloadData cdd;
  1207. LPWSTR pwszClsid = NULL;
  1208. WCHAR szCleanCODE[INTERNET_MAX_URL_LENGTH];
  1209. LPSTR szTmp = NULL;
  1210. LPWSTR wzPtr = NULL;
  1211. LPSTR szBuf = NULL;
  1212. cdd.szDistUnit = NULL;
  1213. cdd.szClassString = NULL;
  1214. cdd.szURL = NULL;
  1215. cdd.szExtension = NULL;
  1216. cdd.szMimeType = szTYPE;
  1217. cdd.szDll = NULL;
  1218. cdd.dwFileVersionMS = dwFileVersionMS;
  1219. cdd.dwFileVersionLS = dwFileVersionLS;
  1220. cdd.dwFlags = CD_FLAGS_NEED_CLASSFACTORY;
  1221. if (szCODE) {
  1222. StrCpyNW(szCleanCODE, szCODE, INTERNET_MAX_URL_LENGTH);
  1223. wzPtr = szCleanCODE;
  1224. while (*wzPtr && *wzPtr != L'#') {
  1225. wzPtr++;
  1226. }
  1227. *wzPtr = L'\0';
  1228. cdd.szURL = szCleanCODE;
  1229. if (FAILED(Unicode2Ansi(szCODE, &szBuf))) {
  1230. goto Exit;
  1231. }
  1232. szTmp = szBuf;
  1233. }
  1234. if (szTmp) {
  1235. while (*szTmp && *szTmp != L'#') {
  1236. szTmp++;
  1237. }
  1238. if (*szTmp == L'#') {
  1239. // Actual codebase ends here. Anchor with NULL char.
  1240. *szTmp = L'\0';
  1241. szTmp++;
  1242. // parsing code
  1243. // Only allow: CODEBASE=http://foo.com#VERSION=1,0,0,0
  1244. // or: CODEBASE=http://foo.com#EXACTVERSION=1,0,0,0
  1245. LPSTR szStart = szTmp;
  1246. while (*szTmp && *szTmp != '=') {
  1247. szTmp++;
  1248. }
  1249. if (*szTmp) {
  1250. // Found '=' delimiter. Anchor NULL
  1251. *szTmp = '\0';
  1252. szTmp++;
  1253. if (!StrCmpI(szStart, "version")) {
  1254. GetVersionFromString(szTmp, &dwFileVersionMS, &dwFileVersionLS, ',');
  1255. cdd.dwFileVersionMS = dwFileVersionMS;
  1256. cdd.dwFileVersionLS = dwFileVersionLS;
  1257. }
  1258. else if (!StrCmpI(szStart, ("exactversion"))) {
  1259. cdd.dwFlags |= CD_FLAGS_EXACT_VERSION;
  1260. GetVersionFromString(szTmp, &dwFileVersionMS, &dwFileVersionLS, ',');
  1261. cdd.dwFileVersionMS = dwFileVersionMS;
  1262. cdd.dwFileVersionLS = dwFileVersionLS;
  1263. }
  1264. }
  1265. }
  1266. }
  1267. hr = StringFromCLSID(rCLASSID, &pwszClsid);
  1268. if(FAILED(hr))
  1269. pwszClsid = NULL;
  1270. // Prepare the debuglog for this download
  1271. pdlog = CDLDebugLog::MakeDebugLog();
  1272. if(pdlog)
  1273. {
  1274. pdlog->AddRef();
  1275. // If there is some way to name the debug log, go ahead and initialize it
  1276. if(pdlog->Init(pwszClsid, cdd.szMimeType, cdd.szExtension, cdd.szURL) != FALSE)
  1277. {
  1278. CDLDebugLog::AddDebugLog(pdlog);
  1279. }
  1280. else
  1281. {
  1282. pdlog->Release();
  1283. pdlog = NULL;
  1284. }
  1285. }
  1286. UrlMkDebugOut((DEB_CODEDL, "IN CoGetClassObjectFromURL CLASSID: %lx, TYPE=%ws...szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n",
  1287. rCLASSID.Data1, cdd.szMimeType, cdd.szURL, cdd.dwFileVersionMS, cdd.dwFileVersionLS));
  1288. forcedownload:
  1289. // Note about pvReserved: this is used by DCOM to get in the remote server
  1290. // name and other info. If not NULL, then the caller wants us to use
  1291. // dcom. if (pvReserved) just call CoGetClassObject.
  1292. // call AsyncGetClassBits to do the real work
  1293. if (pvReserved == NULL && (nForceDownload <= 1) )
  1294. hr = AsyncGetClassBitsEx(rCLASSID, &cdd,
  1295. pBindCtx, dwClsContext, pvReserved, riid);
  1296. if (SUCCEEDED(hr) && (hr != MK_S_ASYNCHRONOUS)) {
  1297. hr = GetClsidFromExtOrMime( rCLASSID, myclsid, cdd.szExtension, cdd.szMimeType, NULL);
  1298. Assert(hr == S_OK);
  1299. if (hr != S_OK)
  1300. {
  1301. hr = E_UNEXPECTED;
  1302. if(pdlog)
  1303. pdlog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FAILED_CONVERT_CLSID, cdd.szExtension, cdd.szMimeType);
  1304. goto Exit;
  1305. }
  1306. DEBUG_ENTER((DBG_DOWNLOAD,
  1307. Hresult,
  1308. "EXTERNAL::CoGetClassObject",
  1309. "%#x, %#x, %#x, %#x, %#x",
  1310. &myclsid, dwClsContext, pvReserved, &riid, ppv
  1311. ));
  1312. hr = CoGetClassObject(myclsid, dwClsContext, pvReserved, riid, ppv);
  1313. DEBUG_LEAVE(hr);
  1314. // BUGBUG: move this policy into the client with a CodeInstallProblem?
  1315. // this hack is easier than reprocessing INF from previous download
  1316. // if we're not using dcom, and the api thinks we're good to go (didn't need to
  1317. // install), yet for these reasons we couldn't get the class object, force a download
  1318. // If there's some other error, or the get class objct was successful, quit.
  1319. if ( !pvReserved && ((hr == HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)) ||
  1320. (hr == REGDB_E_CLASSNOTREG) ||
  1321. (hr == HRESULT_FROM_WIN32(ERROR_DLL_NOT_FOUND))) ) {
  1322. if (hr == REGDB_E_CLASSNOTREG) {
  1323. // if its a hack GUID that is not a COM object but just to
  1324. // get the OBJECT tag to automatically slam a reg key or
  1325. // install some software (like java vm) then don't
  1326. // force an install
  1327. if (!AdviseForceDownload(&myclsid, dwClsContext))
  1328. goto Exit;
  1329. }
  1330. UrlMkDebugOut((DEB_CODEDL, "WRN CoGetClassObjectFromURL hr:%lx%s, CLASSID: %lx..., szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n",
  1331. hr,": dependent dll probably missing, forcing download!",myclsid.Data1, cdd.szURL, cdd.dwFileVersionMS, cdd.dwFileVersionLS));
  1332. cdd.dwFlags |= CD_FLAGS_FORCE_DOWNLOAD;
  1333. nForceDownload++;
  1334. goto forcedownload;
  1335. }
  1336. // falling through to exit
  1337. }
  1338. Exit:
  1339. // If we had some problem, dump the debuglog
  1340. if(FAILED(hr) && pdlog)
  1341. {
  1342. pdlog->DumpDebugLog(NULL, 0, NULL, hr);
  1343. }
  1344. if(pwszClsid)
  1345. delete pwszClsid;
  1346. UrlMkDebugOut((DEB_CODEDL, "OUT CoGetClassObjectFromURL hr:%lx%s, CLASSID: %lx, TYPE=%ws..., szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n",
  1347. hr,(hr == MK_S_ASYNCHRONOUS)?"(PENDING)":(hr == S_OK)?"(SUCCESS)":"",rCLASSID.Data1, cdd.szMimeType, cdd.szURL, cdd.dwFileVersionMS, cdd.dwFileVersionLS));
  1348. if(pdlog)
  1349. {
  1350. CDLDebugLog::RemoveDebugLog(pdlog);
  1351. pdlog->Release();
  1352. pdlog = NULL;
  1353. }
  1354. if (szBuf) {
  1355. delete [] szBuf;
  1356. }
  1357. DEBUG_LEAVE_API(hr);
  1358. return hr;
  1359. }
  1360. /*
  1361. * SetCodeDownloadTLSVars
  1362. *
  1363. * sets up a bunch of tls variables
  1364. * eg, setup cookie, trust cookie list, code download list and
  1365. * the CDLPacket list
  1366. * since TLS vars are HeapAllocated rather than using the new operator
  1367. * the constructors for classes won't get run automatically
  1368. * which is why we have all pointers and the actual classes get allocated
  1369. * here
  1370. */
  1371. HRESULT SetCodeDownloadTLSVars()
  1372. {
  1373. DEBUG_ENTER((DBG_DOWNLOAD,
  1374. Hresult,
  1375. "SetCodeDownloadTLSVars",
  1376. NULL
  1377. ));
  1378. HRESULT hr = NO_ERROR;
  1379. CUrlMkTls tls(hr); // hr passed by reference!
  1380. if (FAILED(hr)) // if tls ctor failed above
  1381. goto Exit;
  1382. if (!tls->pSetupCookie) {
  1383. tls->pSetupCookie = new CCookie<CCodeDownload *>(CODE_DOWNLOAD_SETUP);
  1384. if (!tls->pSetupCookie) {
  1385. hr = E_OUTOFMEMORY;
  1386. goto Exit;
  1387. }
  1388. }
  1389. if (!tls->pTrustCookie) {
  1390. tls->pTrustCookie = new CCookie<CDownload *>(CODE_DOWNLOAD_TRUST_PIECE);
  1391. if (!tls->pTrustCookie) {
  1392. hr = E_OUTOFMEMORY;
  1393. goto Exit;
  1394. }
  1395. }
  1396. if (!tls->pCodeDownloadList) {
  1397. tls->pCodeDownloadList = new CList<CCodeDownload *, CCodeDownload *>;
  1398. if (!tls->pCodeDownloadList) {
  1399. hr = E_OUTOFMEMORY;
  1400. goto Exit;
  1401. }
  1402. }
  1403. if (!tls->pRejectedFeaturesList) {
  1404. tls->pRejectedFeaturesList= new CList<LPCWSTR , LPCWSTR >;
  1405. if (!tls->pRejectedFeaturesList) {
  1406. hr = E_OUTOFMEMORY;
  1407. goto Exit;
  1408. }
  1409. }
  1410. if (!tls->pCDLPacketMgr) {
  1411. tls->pCDLPacketMgr = new CCDLPacketMgr();
  1412. if (!tls->pCDLPacketMgr) {
  1413. hr = E_OUTOFMEMORY;
  1414. goto Exit;
  1415. }
  1416. }
  1417. Exit:
  1418. DEBUG_LEAVE(hr);
  1419. return hr;
  1420. }
  1421. /*
  1422. * CoInstall
  1423. *
  1424. *
  1425. * CoInstall() is a public API, also used by CoGetClassObjectFromUrl
  1426. *
  1427. * It's primary implementation is in OLE32.
  1428. */
  1429. STDAPI CoInstall(
  1430. IBindCtx *pbc,
  1431. DWORD dwFlags,
  1432. uCLSSPEC *pClassSpec,
  1433. QUERYCONTEXT *pQuery,
  1434. LPWSTR pszCodeBase)
  1435. {
  1436. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1437. Hresult,
  1438. "CoInstall",
  1439. "%#x, %#x, %#x, %#x, %.80wq",
  1440. pbc, dwFlags, pClassSpec, pQuery, pszCodeBase
  1441. ));
  1442. HRESULT hr;
  1443. // BUGBUG: The real CoInstall needs this always set for now. MSICD/PrivateCoInstall shouldn't,
  1444. // so we'll only set it in the case where we're calling NT5 OLE.
  1445. // Setting this flag unconditionally may have bad side effects on offline mode.
  1446. dwFlags = dwFlags | CD_FLAGS_FORCE_INTERNET_DOWNLOAD;
  1447. #ifndef WRAP_OLE32_COINSTALL
  1448. dwFlags = dwFlags | CD_FLAGS_NEED_CLASSFACTORY;
  1449. #else
  1450. dwFlags = dwFlags & (~CD_FLAGS_NEED_CLASSFACTORY);
  1451. #endif
  1452. hr = SetCoInstall();
  1453. if ( SUCCEEDED(hr) )
  1454. {
  1455. if ( g_bUseOLECoInstall )
  1456. hr = (*g_pfnCoInstall)(pbc, dwFlags, pClassSpec, pQuery, pszCodeBase);
  1457. else
  1458. hr = PrivateCoInstall(pbc, dwFlags, pClassSpec, pQuery, pszCodeBase);
  1459. }
  1460. DEBUG_LEAVE_API(hr);
  1461. return hr;
  1462. };
  1463. /*
  1464. * AsyncInstallDistUnit
  1465. *
  1466. *
  1467. * AsyncInstallDistributionUnit() the entry into the Code downloader creates this obj
  1468. * for the given CODE, DistUnit, FileVersion, BSC (from BindCtx)
  1469. *
  1470. * The CodeDownload obj once created is asked to perform its function
  1471. * thru CCodeDownload::DoCodeDownload().
  1472. */
  1473. STDAPI
  1474. AsyncInstallDistributionUnitEx(
  1475. CodeDownloadData * pcdd, // Contains requested object's descriptors
  1476. IBindCtx *pbc, // bind ctx
  1477. REFIID riid,
  1478. IUnknown **ppUnk,
  1479. LPVOID pvReserved) // Must be NULL
  1480. {
  1481. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1482. Hresult,
  1483. "AsyncInstallDistributionUnitEx",
  1484. "%#x, %#x, %#x, %#x, %#x",
  1485. pcdd, pbc, &riid, ppUnk, pvReserved
  1486. ));
  1487. LPCWSTR szClientID = NULL;
  1488. pcdd->dwFlags &= (CD_FLAGS_EXTERNAL_MASK | CD_FLAGS_EXACT_VERSION);
  1489. HRESULT hr = AsyncGetClassBits2Ex(szClientID, pcdd, pbc, 0, NULL, riid, ppUnk);
  1490. DEBUG_LEAVE_API(hr);
  1491. return hr;
  1492. }
  1493. // backwards compatability (no dll name parameter)
  1494. STDAPI
  1495. AsyncInstallDistributionUnit(
  1496. LPCWSTR szDistUnit,
  1497. LPCWSTR szTYPE,
  1498. LPCWSTR szExt,
  1499. DWORD dwFileVersionMS, // CODEBASE=http://foo#Version=a,b,c,d
  1500. DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
  1501. LPCWSTR szURL, // CODEBASE
  1502. IBindCtx *pbc, // bind ctx
  1503. LPVOID pvReserved, // Must be NULL
  1504. DWORD flags)
  1505. {
  1506. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1507. Hresult,
  1508. "AsyncInstallDistributionUnit",
  1509. "%.80wq, %.80wq, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x",
  1510. szDistUnit, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, szURL, pbc, pvReserved, flags
  1511. ));
  1512. CodeDownloadData cdd;
  1513. cdd.szDistUnit = szDistUnit;
  1514. cdd.szClassString = szDistUnit; // best choice we've got
  1515. cdd.szURL = szURL;
  1516. cdd.szMimeType = szTYPE;
  1517. cdd.szExtension = szExt;
  1518. cdd.szDll = NULL;
  1519. cdd.dwFileVersionMS = dwFileVersionMS;
  1520. cdd.dwFileVersionLS = dwFileVersionLS;
  1521. cdd.dwFlags = flags;
  1522. HRESULT hr = AsyncInstallDistributionUnitEx(&cdd, pbc, IID_IUnknown, NULL, pvReserved);
  1523. DEBUG_LEAVE_API(hr);
  1524. return hr;
  1525. }
  1526. /*
  1527. * AsyncGetClassBits
  1528. *
  1529. *
  1530. * AsyncGetClassBits() the entry into the Code downloader creates this obj
  1531. * for the given CODE, CLSID, FileVersion, BSC (from BindCtx)
  1532. * we do not check to see if a code download is already in progress
  1533. * in the system at a given moment. Nor we do we keep track of individual
  1534. * downloads and possible clashes between various silmultaneous code
  1535. * downloads system wide. We leave it to URL moniker (above us) to ensure
  1536. * that duplicate calls are not made into AsynGetClassBits. The second
  1537. * problem of different code downloads trying to bring down a common
  1538. * dependent DLL is POSTPONED to version 2 implementation.
  1539. *
  1540. * The CodeDownload obj once created is asked to perform its function
  1541. * thru CCodeDownload::DoCodeDownload().
  1542. */
  1543. STDAPI
  1544. AsyncGetClassBits(
  1545. REFCLSID rclsid, // CLSID
  1546. LPCWSTR szTYPE,
  1547. LPCWSTR szExt,
  1548. DWORD dwFileVersionMS, // CODE=http://foo#Version=a,b,c,d
  1549. DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
  1550. LPCWSTR szURL, // CODE= in INSERT tag
  1551. IBindCtx *pbc, // bind ctx
  1552. DWORD dwClsContext, // CLSCTX flags
  1553. LPVOID pvReserved, // Must be NULL
  1554. REFIID riid, // Usually IID_IClassFactory
  1555. DWORD flags)
  1556. {
  1557. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1558. Hresult,
  1559. "AsyncGetClassBits",
  1560. "%#x, %.80wq, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x",
  1561. &rclsid, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, szURL, pbc, dwClsContext, pvReserved, &riid, flags
  1562. ));
  1563. CodeDownloadData cdd;
  1564. cdd.szDistUnit = NULL;
  1565. cdd.szClassString = NULL;
  1566. cdd.szURL = szURL;
  1567. cdd.szMimeType = szTYPE;
  1568. cdd.szExtension = szExt;
  1569. cdd.szDll = NULL;
  1570. cdd.dwFileVersionMS = dwFileVersionMS;
  1571. cdd.dwFileVersionLS = dwFileVersionLS;
  1572. cdd.dwFlags = flags;
  1573. HRESULT hr = AsyncGetClassBitsEx(rclsid, &cdd, pbc, dwClsContext, pvReserved, riid);
  1574. DEBUG_LEAVE_API(hr);
  1575. return hr;
  1576. }
  1577. STDAPI
  1578. AsyncGetClassBitsEx(
  1579. REFCLSID rclsid, // CLSID
  1580. CodeDownloadData *pcdd,
  1581. IBindCtx *pbc, // bind ctx
  1582. DWORD dwClsContext, // CLSCTX flags
  1583. LPVOID pvReserved, // Must be NULL
  1584. REFIID riid) // Usually IID_IClassFactory
  1585. {
  1586. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1587. Hresult,
  1588. "AsyncGetClassBitsEx",
  1589. "%#x, %#x, %#x, %#x, %#x, %#x",
  1590. &rclsid, pcdd, pbc, dwClsContext, pvReserved, &riid
  1591. ));
  1592. LPOLESTR pwcsClsid = NULL;
  1593. LPCWSTR szClientID = NULL;
  1594. HRESULT hr=S_OK;
  1595. pcdd->dwFlags &= (CD_FLAGS_EXTERNAL_MASK | CD_FLAGS_EXACT_VERSION);
  1596. CDLDebugLog * pdlog = NULL;
  1597. // return if we can't get a valid string representation of the CLSID
  1598. if (!IsEqualGUID(rclsid , CLSID_NULL) &&
  1599. (FAILED((hr=StringFromCLSID(rclsid, &pwcsClsid)))) )
  1600. {
  1601. pdlog = CDLDebugLog::GetDebugLog(NULL, pcdd->szMimeType,
  1602. pcdd->szExtension, pcdd->szURL);
  1603. if(pdlog)
  1604. {
  1605. pdlog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FAILED_STRING_FROM_CLSID);
  1606. }
  1607. goto Exit;
  1608. }
  1609. pcdd->szDistUnit = pwcsClsid;
  1610. pcdd->szClassString = pwcsClsid; // dist unit and clsid are the same from this entry point
  1611. #ifndef WRAP_OLE32_COINSTALL
  1612. // Work around a problem with OLE32's CoInstall (until wrappers are enabled or OLE calls PrivateCoInstall):
  1613. // since CoInstall doesn't known the IID,
  1614. // it calls AsyncGetClassBits with IID_IUnknown (instead of IID_IClassFactory)
  1615. if ((pcdd->dwFlags & CD_FLAGS_FORCE_INTERNET_DOWNLOAD) && IsEqualGUID(riid, IID_IUnknown))
  1616. {
  1617. hr = AsyncGetClassBits2Ex(szClientID, pcdd,
  1618. pbc,dwClsContext,pvReserved,IID_IClassFactory,NULL);
  1619. }
  1620. else
  1621. {
  1622. #endif
  1623. hr = AsyncGetClassBits2Ex(szClientID, pcdd,
  1624. pbc,dwClsContext,pvReserved,riid,NULL);
  1625. #ifndef WRAP_OLE32_COINSTALL
  1626. }
  1627. #endif
  1628. Exit:
  1629. if (pwcsClsid != NULL)
  1630. delete pwcsClsid;
  1631. DEBUG_LEAVE_API(hr);
  1632. return hr;
  1633. }
  1634. HRESULT GetIEFeatureVersion(
  1635. LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
  1636. LPCWSTR szTYPE,
  1637. CLSID clsid,
  1638. QUERYCONTEXT *pqc)
  1639. {
  1640. DEBUG_ENTER((DBG_DOWNLOAD,
  1641. Hresult,
  1642. "GetIEFeatureVersion",
  1643. "%.80wq, %.80wq, %#x, %#x",
  1644. szDistUnit, szTYPE, &clsid, pqc
  1645. ));
  1646. HRESULT hr = S_OK;
  1647. memset(pqc, 0, sizeof(QUERYCONTEXT));
  1648. if (!IsEqualGUID(clsid, CLSID_NULL)) {
  1649. hr = GetIEFeatureFromClass(NULL, clsid, pqc);
  1650. } else if (szTYPE) {
  1651. hr = GetIEFeatureFromMime(NULL, szTYPE, pqc);
  1652. } else {
  1653. // not an IE feature
  1654. hr = S_FALSE;
  1655. goto Exit;
  1656. }
  1657. Exit:
  1658. DEBUG_LEAVE(hr);
  1659. return hr;
  1660. }
  1661. HRESULT InstallIEFeature(
  1662. LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
  1663. LPCWSTR szTYPE,
  1664. CLSID clsid,
  1665. IBindCtx *pbc,
  1666. DWORD dwFileVersionMS,
  1667. DWORD dwFileVersionLS,
  1668. DWORD dwFlags,
  1669. BOOL bIEVersion
  1670. )
  1671. {
  1672. DEBUG_ENTER((DBG_DOWNLOAD,
  1673. Hresult,
  1674. "InstallIEFeature",
  1675. "%.80wq, %.80wq, %#x, %#x, %#x, %#x, %#x, %B",
  1676. szDistUnit, szTYPE, &clsid, pbc, dwFileVersionMS, dwFileVersionLS, dwFlags, bIEVersion
  1677. ));
  1678. HRESULT hr = S_OK;
  1679. uCLSSPEC classpec;
  1680. IWindowForBindingUI *pWindowForBindingUI = NULL;
  1681. IBindStatusCallback *pclientbsc = NULL;
  1682. HWND hWnd = NULL;
  1683. REFGUID rguidReason = IID_ICodeInstall;
  1684. QUERYCONTEXT qc;
  1685. DWORD dwJITFlags = 0;
  1686. memset(&qc, 0, sizeof(qc));
  1687. qc.dwVersionHi = dwFileVersionMS;
  1688. qc.dwVersionLo = dwFileVersionLS;
  1689. if (!IsEqualGUID(clsid, CLSID_NULL)) {
  1690. classpec.tyspec=TYSPEC_CLSID;
  1691. classpec.tagged_union.clsid=clsid;
  1692. } else if (szTYPE) {
  1693. classpec.tyspec=TYSPEC_MIMETYPE;
  1694. classpec.tagged_union.pMimeType=(LPWSTR)szTYPE;
  1695. } else {
  1696. // not an IE feature
  1697. hr = S_FALSE;
  1698. goto Exit;
  1699. }
  1700. hr = FaultInIEFeature(hWnd, &classpec, &qc, (bIEVersion?0:FIEF_FLAG_CHECK_CIFVERSION)|FIEF_FLAG_PEEK);
  1701. if ( hr == HRESULT_FROM_WIN32(ERROR_UNKNOWN_REVISION) ||
  1702. hr == E_ACCESSDENIED) {
  1703. // the version in the CIF will not satisfy the requested version
  1704. // or the admin has turned off JIT or the user has turned off
  1705. // JIT in Inetcpl: if they wanted to turn off code download
  1706. // they should do it per-zone activex signed/unsigned policy.
  1707. // fall thru to code download from the CODEBASE
  1708. hr = S_FALSE;
  1709. }
  1710. if (hr == S_OK) {
  1711. // We always come in here from code downloader at a point
  1712. // where looking at the com branch and DU key, something is
  1713. // busted and so needs code download. We can't at this point
  1714. // succeed. Likely the AS keys are just orphaned and it looks
  1715. // installed, but is not.
  1716. // However, to account for cases where JIT could be right
  1717. // we will only force JIT download when instrcuted to
  1718. if (dwFlags & CD_FLAGS_FORCE_DOWNLOAD) {
  1719. hr = HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED);
  1720. dwJITFlags |= FIEF_FLAG_SKIP_INSTALLED_VERSION_CHECK;
  1721. }
  1722. }
  1723. if (hr != HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED)) {
  1724. goto Exit;
  1725. }
  1726. // must really install now, get an hwnd
  1727. hr = pbc->GetObjectParam(REG_BSCB_HOLDER, (IUnknown **)&pclientbsc);
  1728. if (FAILED(hr))
  1729. goto Exit;
  1730. // don't JIT if web crawling
  1731. {
  1732. DWORD grfBINDF = 0;
  1733. BINDINFO bindInfo;
  1734. memset(&bindInfo, 0, sizeof(BINDINFO));
  1735. bindInfo.cbSize = sizeof(BINDINFO);
  1736. pclientbsc->GetBindInfo(&grfBINDF, &bindInfo);
  1737. ReleaseBindInfo(&bindInfo);
  1738. if (grfBINDF & BINDF_SILENTOPERATION)
  1739. {
  1740. hr = MK_E_MUSTBOTHERUSER;
  1741. goto Exit;
  1742. }
  1743. }
  1744. // Get IWindowForBindingUI ptr
  1745. hr = pclientbsc->QueryInterface(IID_IWindowForBindingUI,
  1746. (LPVOID *)&pWindowForBindingUI);
  1747. if (FAILED(hr)) {
  1748. IServiceProvider *pServProv;
  1749. hr = pclientbsc->QueryInterface(IID_IServiceProvider,
  1750. (LPVOID *)&pServProv);
  1751. if (hr == NOERROR) {
  1752. pServProv->QueryService(IID_IWindowForBindingUI,IID_IWindowForBindingUI,
  1753. (LPVOID *)&pWindowForBindingUI);
  1754. pServProv->Release();
  1755. }
  1756. }
  1757. // get hWnd
  1758. if (pWindowForBindingUI) {
  1759. pWindowForBindingUI->GetWindow(rguidReason, &hWnd);
  1760. pWindowForBindingUI->Release();
  1761. memset(&qc, 0, sizeof(qc)); // reset, peek state modifies this with
  1762. // currently installed version info!
  1763. qc.dwVersionHi = dwFileVersionMS;
  1764. qc.dwVersionLo = dwFileVersionLS;
  1765. hr = FaultInIEFeature(hWnd, &classpec, &qc, dwJITFlags);
  1766. }
  1767. else {
  1768. hr = MK_E_MUSTBOTHERUSER;
  1769. // fallthru to Exit
  1770. // goto Exit;
  1771. }
  1772. Exit:
  1773. if (pclientbsc)
  1774. pclientbsc->Release();
  1775. DEBUG_LEAVE(hr);
  1776. return hr;
  1777. }
  1778. // if both signed and unsigned activex is disallowed then return failure
  1779. // so we can avoid downloading the CAB altogether
  1780. HRESULT
  1781. CheckActiveXDownloadEnabled(
  1782. IInternetHostSecurityManager *pHostSecurityManager,
  1783. LPCWSTR szCodebase,
  1784. IBindStatusCallback* pBSC)
  1785. {
  1786. DEBUG_ENTER((DBG_DOWNLOAD,
  1787. Hresult,
  1788. "CheckActiveXDownloadEnabled",
  1789. "%#x, %.80wq",
  1790. pHostSecurityManager, szCodebase
  1791. ));
  1792. HRESULT hr = S_OK;
  1793. DWORD dwPolicy;
  1794. DWORD grfBINDF = 0;
  1795. BINDINFO bindInfo;
  1796. memset(&bindInfo, 0, sizeof(BINDINFO));
  1797. bindInfo.cbSize = sizeof(BINDINFO);
  1798. BOOL fEnforceRestricted = FALSE;
  1799. hr = pBSC->GetBindInfo(&grfBINDF, &bindInfo);
  1800. if (SUCCEEDED(hr))
  1801. {
  1802. ReleaseBindInfo(&bindInfo);
  1803. if (grfBINDF & BINDF_ENFORCERESTRICTED)
  1804. fEnforceRestricted = TRUE;
  1805. }
  1806. hr = GetActivePolicy(pHostSecurityManager, szCodebase,
  1807. URLACTION_DOWNLOAD_SIGNED_ACTIVEX, dwPolicy, fEnforceRestricted);
  1808. if (FAILED(hr)) {
  1809. hr = GetActivePolicy(pHostSecurityManager, szCodebase,
  1810. URLACTION_DOWNLOAD_UNSIGNED_ACTIVEX, dwPolicy, fEnforceRestricted);
  1811. }
  1812. DEBUG_LEAVE(hr);
  1813. return hr;
  1814. }
  1815. // backwards compatability
  1816. STDAPI
  1817. AsyncGetClassBits2(
  1818. LPCWSTR szClientID, // client ID, root object if NULL
  1819. LPCWSTR szDistUnit, // CLSID, can be an arbit unique str
  1820. LPCWSTR szTYPE,
  1821. LPCWSTR szExt,
  1822. DWORD dwFileVersionMS, // CODE=http://foo#Version=a,b,c,d
  1823. DWORD dwFileVersionLS, // MAKEDWORD(c,b) of above
  1824. LPCWSTR szURL, // CODE= in INSERT tag
  1825. IBindCtx *pbc, // bind ctx
  1826. DWORD dwClsContext, // CLSCTX flags
  1827. LPVOID pvReserved, // Must be NULL
  1828. REFIID riid, // Usually IID_IClassFactory
  1829. DWORD flags)
  1830. {
  1831. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1832. Hresult,
  1833. "AsyncGetClassBits2",
  1834. "%.80wq, %.80wq, %.80wq, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x",
  1835. szClientID, szDistUnit, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, szURL, pbc, dwClsContext, pvReserved, &riid, flags
  1836. ));
  1837. CodeDownloadData cdd;
  1838. cdd.szDistUnit = szDistUnit;
  1839. cdd.szClassString = szDistUnit; // best choice we've got
  1840. cdd.szURL = szURL;
  1841. cdd.szMimeType = szTYPE;
  1842. cdd.szExtension = szExt;
  1843. cdd.szDll = NULL;
  1844. cdd.dwFileVersionMS = dwFileVersionMS;
  1845. cdd.dwFileVersionLS = dwFileVersionLS;
  1846. cdd.dwFlags = flags;
  1847. HRESULT hr = AsyncGetClassBits2Ex(szClientID,&cdd,pbc,dwClsContext,
  1848. pvReserved,riid,NULL);
  1849. DEBUG_LEAVE_API(hr);
  1850. return hr;
  1851. }
  1852. STDAPI
  1853. AsyncGetClassBits2Ex(
  1854. LPCWSTR szClientID, // client ID, root object if NULL
  1855. CodeDownloadData * pcdd,
  1856. IBindCtx *pbc, // bind ctx
  1857. DWORD dwClsContext, // CLSCTX flags
  1858. LPVOID pvReserved, // Must be NULL
  1859. REFIID riid, // Usually IID_IClassFactory
  1860. IUnknown **ppUnk) // pass back pUnk for synchronous case
  1861. {
  1862. DEBUG_ENTER_API((DBG_DOWNLOAD,
  1863. Hresult,
  1864. "AsyncGetClassBits2Ex",
  1865. "%.80wq, %#x, %#x, %#x, %#x, %#x, %#x",
  1866. szClientID, pcdd, pbc, dwClsContext, pvReserved, &riid, ppUnk
  1867. ));
  1868. LPCWSTR szDistUnit = pcdd->szDistUnit; // Name of dist unit, may be a clsid
  1869. LPCWSTR szClassString = pcdd->szClassString; // Clsid to call com with/get object on
  1870. LPCWSTR szTYPE = pcdd->szMimeType;
  1871. LPCWSTR szExt = pcdd->szExtension;
  1872. DWORD dwFileVersionMS = pcdd->dwFileVersionMS; // CODE=http://foo#Version=a,b,c,d
  1873. DWORD dwFileVersionLS = pcdd->dwFileVersionLS; // MAKEDWORD(c,b) of above
  1874. LPCWSTR szURL = pcdd->szURL; // CODE= in INSERT tag
  1875. LPCWSTR szDll = pcdd->szDll; // Dll name for zero impact (can be NULL)
  1876. DWORD flags = pcdd->dwFlags;
  1877. CCodeDownload* pcdl = NULL;
  1878. HRESULT hr = NO_ERROR;
  1879. IBindStatusCallback *pclientbsc = NULL;
  1880. LISTPOSITION pos;
  1881. CClBinding *pClientbinding;
  1882. char szExistingBuf[MAX_PATH];
  1883. DWORD cExistingSize = MAX_PATH;
  1884. char *pBaseExistingName = NULL;
  1885. HKEY hKeyIESettings = 0;
  1886. LONG lResult;
  1887. CLSID myclsid;
  1888. CLSID inclsid = CLSID_NULL;
  1889. LPSTR pPluginFileName = NULL;
  1890. BOOL bHintActiveX = (flags & CD_FLAGS_HINT_ACTIVEX)?TRUE:FALSE;
  1891. BOOL bHintJava = (flags & CD_FLAGS_HINT_JAVA)?TRUE:FALSE;
  1892. BOOL bNullClsid;
  1893. BOOL bIEVersion = FALSE;
  1894. CLocalComponentInfo* plci = NULL;
  1895. IInternetHostSecurityManager *pHostSecurityManager = NULL;
  1896. CDLDebugLog * pdlog = NULL;
  1897. CUrlMkTls tls(hr); // hr passed by reference!
  1898. if (FAILED(hr)) // if tls ctor failed above
  1899. goto AGCB_Exit;
  1900. pdlog = CDLDebugLog::GetDebugLog(szDistUnit, szTYPE, szExt, szURL);
  1901. if(pdlog)
  1902. pdlog->AddRef();
  1903. plci = new CLocalComponentInfo();
  1904. if(!plci) {
  1905. hr = E_OUTOFMEMORY;
  1906. goto AGCB_Exit;
  1907. }
  1908. if(szClassString)
  1909. CLSIDFromString((LPOLESTR)szClassString, &inclsid);// if fails szClassString is not clsid
  1910. // Fill myclsid with inclsid (if not null-clsid), the clsid corresponding
  1911. // to the mime type in szTYPE (if not NULL), the clsid corresponding
  1912. // to the file extension in szExt (if not NULL), or the clsid for the
  1913. // plugin corresponging to the mime type or extension (if not NULL),
  1914. // in that order of preference
  1915. hr = GetClsidFromExtOrMime( inclsid, myclsid, szExt, szTYPE,
  1916. &pPluginFileName);
  1917. // hr = S_OK: mapped to a clsid
  1918. // hr = S_FALSE: don't know what it is
  1919. // hr error, fail
  1920. if (FAILED(hr))
  1921. {
  1922. if(pdlog)
  1923. {
  1924. pdlog->DebugOut(DEB_CODEDL, TRUE, ID_CDLDBG_FAILED_CONVERT_CLSID, szExt, szTYPE);
  1925. }
  1926. goto AGCB_Exit;
  1927. }
  1928. hr = S_OK; //reset
  1929. if (!(dwFileVersionMS | dwFileVersionLS)) {
  1930. // maybe this is an IE feature like Java
  1931. // that may require that a matching version
  1932. // that is later than one currently installed
  1933. // is needed
  1934. if (!g_bNT5OrGreater) {
  1935. QUERYCONTEXT qc;
  1936. hr = GetIEFeatureVersion(szDistUnit, szTYPE, inclsid, &qc);
  1937. if (FAILED(hr))
  1938. goto AGCB_Exit;
  1939. dwFileVersionMS = qc.dwVersionHi;
  1940. dwFileVersionLS = qc.dwVersionLo;
  1941. if (dwFileVersionMS | dwFileVersionLS) {
  1942. bIEVersion = TRUE;
  1943. }
  1944. }
  1945. }
  1946. bNullClsid = IsEqualGUID(myclsid, CLSID_NULL);
  1947. if (szDistUnit || !bNullClsid ) {
  1948. // manage to map to a clsid or has a distunit name
  1949. CLSID pluginclsid = CLSID_ActiveXPlugin;
  1950. if (!IsEqualGUID(myclsid , pluginclsid)) {
  1951. // mark that we now have a clsid throw away TYPE, Ext
  1952. szTYPE = NULL;
  1953. szExt = NULL;
  1954. }
  1955. // check to see if locally installed.
  1956. HRESULT hrExact;
  1957. HRESULT hrAny;
  1958. if (FAILED((hrAny = IsControlLocallyInstalled(pPluginFileName,
  1959. (pPluginFileName)?(LPCLSID)&inclsid:&myclsid, szDistUnit,
  1960. dwFileVersionMS, dwFileVersionLS, plci, NULL, FALSE)))) {
  1961. goto AGCB_Exit;
  1962. }
  1963. if (pcdd->dwFlags & CD_FLAGS_EXACT_VERSION) {
  1964. if (FAILED((hrExact = IsControlLocallyInstalled(pPluginFileName,
  1965. (pPluginFileName)?(LPCLSID)&inclsid:&myclsid, szDistUnit,
  1966. dwFileVersionMS, dwFileVersionLS, plci, NULL, TRUE)))) {
  1967. goto AGCB_Exit;
  1968. }
  1969. if (hrAny != S_OK) {
  1970. // Don't have at least the requested version. Do the download.
  1971. hr = hrAny;
  1972. }
  1973. else if (hrAny == S_OK && hrExact == S_FALSE) {
  1974. // Newer control installed, must downgrade
  1975. // Check if this is a system control, and disallow if it is
  1976. BOOL bIsDPFComponent = FALSE;
  1977. HKEY hKeyIESettings = 0;
  1978. CHAR szOCXCacheDirSFN[MAX_PATH];
  1979. CHAR szFNameSFN[MAX_PATH];
  1980. DWORD dwType;
  1981. DWORD Size;
  1982. Size = MAX_PATH;
  1983. dwType = REG_SZ;
  1984. if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_IE_SETTINGS, 0,
  1985. KEY_READ, &hKeyIESettings))) {
  1986. if (SUCCEEDED(RegQueryValueEx(hKeyIESettings, g_szActiveXCache,
  1987. NULL, &dwType, (unsigned char *)g_szOCXCacheDir, &Size))) {
  1988. if (plci->szExistingFileName[0]) {
  1989. GetShortPathName(plci->szExistingFileName, szFNameSFN, MAX_PATH);
  1990. GetShortPathName(g_szOCXCacheDir, szOCXCacheDirSFN, MAX_PATH);
  1991. if (StrStrI(szFNameSFN, szOCXCacheDirSFN)) {
  1992. bIsDPFComponent = TRUE;
  1993. }
  1994. }
  1995. RegCloseKey(hKeyIESettings);
  1996. }
  1997. }
  1998. if (!bIsDPFComponent) {
  1999. // Trying to do a downgrade of a non-DPF component.
  2000. // Cut this off, and just act as if the existing (newer)
  2001. // version is already good enough. No download/install.
  2002. hr = S_OK;
  2003. }
  2004. else {
  2005. // Do the download
  2006. hr = hrExact;
  2007. }
  2008. }
  2009. else {
  2010. // hrAny == hrExact == S_OK, so we're done
  2011. Assert(hrAny == S_OK && hrExact == S_OK);
  2012. hr = hrAny;
  2013. }
  2014. }
  2015. else {
  2016. // Continue as before
  2017. hr = hrAny;
  2018. }
  2019. if ( hr == S_OK) { // local version OK
  2020. if (!(flags & CD_FLAGS_FORCE_DOWNLOAD)) {
  2021. // check here is a new version has been
  2022. // advertised for this DU. If so, force a -1 or Get Latest
  2023. if (!((plci->dwAvailMS > plci->dwLocFVMS) ||
  2024. ((plci->dwAvailMS == plci->dwLocFVMS) &&
  2025. (plci->dwAvailLS > plci->dwLocFVLS))) ) {
  2026. // Code Download thinks the
  2027. // current version is good enough
  2028. goto AGCB_Exit;
  2029. }
  2030. dwFileVersionMS = 0xffffffff;
  2031. dwFileVersionLS = 0xffffffff;
  2032. }
  2033. // force download flag! Fall thru and Do it!
  2034. }
  2035. } else {
  2036. // couldn't map to a clsid
  2037. // just have ext or mime type
  2038. }
  2039. // here if we are going to do a code download.
  2040. if ((flags & CD_FLAGS_NEED_CLASSFACTORY) &&
  2041. (dwFileVersionMS == 0) && (dwFileVersionLS == 0)) {
  2042. HRESULT hrResult = S_OK;
  2043. IUnknown *punk = NULL;
  2044. // We don't care about the version. Check if someone registered
  2045. // themselves with COM via CoRegisterClassObject, and if it
  2046. // succeeds, we don't need to download.
  2047. hrResult = CoGetClassObject(((pPluginFileName) ? (inclsid) : (myclsid)),
  2048. dwClsContext, pvReserved, riid, (void**)&punk);
  2049. if (SUCCEEDED(hrResult)) {
  2050. punk->Release();
  2051. hr = S_OK;
  2052. goto AGCB_Exit;
  2053. }
  2054. }
  2055. if (flags & CD_FLAGS_PEEK_STATE) {
  2056. hr = S_FALSE;
  2057. goto AGCB_Exit;
  2058. }
  2059. // check language being right version
  2060. if (plci->bForceLangGetLatest) {
  2061. dwFileVersionMS = 0xffffffff;
  2062. dwFileVersionLS = 0xffffffff;
  2063. } else if ((dwFileVersionMS != 0xffffffff) && (dwFileVersionLS != 0xffffffff)) {
  2064. // try the JIT API first before code download
  2065. hr = InstallIEFeature(szDistUnit, szTYPE, inclsid, pbc, dwFileVersionMS, dwFileVersionLS, flags, bIEVersion);
  2066. if (hr != S_FALSE)
  2067. goto AGCB_Exit;
  2068. }
  2069. hr = SetCoInstall();
  2070. if ( FAILED(hr) )
  2071. goto AGCB_Exit;
  2072. if ( g_bUseOLECoInstall && !(flags & CD_FLAGS_FORCE_INTERNET_DOWNLOAD) )
  2073. {
  2074. CLSID inclsid;
  2075. CLSIDFromString((LPOLESTR)szDistUnit, &inclsid);
  2076. hr = WrapCoInstall( inclsid, szURL, dwFileVersionMS, dwFileVersionLS, szTYPE, pbc,
  2077. dwClsContext,pvReserved, riid, flags);
  2078. if ( SUCCEEDED(hr) )
  2079. goto AGCB_Exit;
  2080. }
  2081. hr = SetCodeDownloadTLSVars();
  2082. if (FAILED(hr))
  2083. goto AGCB_Exit;
  2084. hr = SetGlobals();
  2085. if (FAILED(hr))
  2086. goto AGCB_Exit;
  2087. if (g_bLockedDown) {
  2088. hr = E_ACCESSDENIED;
  2089. goto AGCB_Exit;
  2090. }
  2091. hr = pbc->GetObjectParam(REG_BSCB_HOLDER, (IUnknown **)&pclientbsc);
  2092. if (FAILED(hr))
  2093. goto AGCB_Exit;
  2094. pbc->AddRef(); // pbc gets saved in the CClBinding and gets released in
  2095. // ~CClBinding()
  2096. // after this point if a CClBinding does not get
  2097. // created, we will leak the client BC and BSC
  2098. // check appropriately and release client
  2099. // check to see if a code download is in progress for this CLSID
  2100. // Note, this only checks for top level objects now.
  2101. pHostSecurityManager = GetHostSecurityManager(pclientbsc);
  2102. hr = CCodeDownload::HandleDuplicateCodeDownloads(szURL, szTYPE, szExt,
  2103. myclsid, szDistUnit, dwClsContext, pvReserved, riid, pbc, pclientbsc, flags, pHostSecurityManager);
  2104. // if it was a dulplicate request and got piggybacked to
  2105. // a CodeDownload in progress we will get back MK_S_ASYNCHRONOUS
  2106. // return of S_OK means that no DUP was found and we are to issue
  2107. // fresh code download
  2108. if (FAILED(hr)) {
  2109. // release client here
  2110. pclientbsc->Release();
  2111. pbc->Release();
  2112. goto AGCB_Exit;
  2113. }
  2114. if (hr == MK_S_ASYNCHRONOUS)
  2115. goto AGCB_Exit;
  2116. pcdl = new CCodeDownload(szDistUnit, szURL, szTYPE, szExt, dwFileVersionMS, dwFileVersionLS, &hr);
  2117. if (FAILED(hr)) {
  2118. // constructor failed!
  2119. pcdl->Release();
  2120. }
  2121. if (!pcdl) {
  2122. hr = E_OUTOFMEMORY;
  2123. }
  2124. if (FAILED(hr)) {
  2125. // release client here
  2126. pclientbsc->Release();
  2127. pbc->Release();
  2128. goto AGCB_Exit;
  2129. }
  2130. // Pass off the debug log to the ccodedownload
  2131. if(pdlog)
  2132. {
  2133. pcdl->SetDebugLog(pdlog);
  2134. }
  2135. pcdl->SetExactVersion((pcdd->dwFlags & CD_FLAGS_EXACT_VERSION) != 0);
  2136. CClBinding *pClientBinding;
  2137. hr = pcdl->CreateClientBinding( &pClientBinding, pbc, pclientbsc,
  2138. inclsid, dwClsContext, pvReserved, riid,
  2139. TRUE /* fAddHead */, pHostSecurityManager);
  2140. if (FAILED(hr)) {
  2141. // release client here
  2142. pclientbsc->Release();
  2143. pbc->Release();
  2144. pcdl->Release();
  2145. goto AGCB_Exit;
  2146. }
  2147. pClientBinding->SetClassString(szClassString);
  2148. // check if our current security settings allow us to do a code download
  2149. // this is a quick out to avoid doing a download when all activex is
  2150. // disabled and we think this is ActiveX.
  2151. if (bHintActiveX || (!bNullClsid && !bHintJava)) {
  2152. // get the zone mgr and check for policy on signed and unsigned
  2153. // activex controls. If both are disabled then stop here
  2154. // otherwise proceed to download main CAB and WVT will determine the
  2155. // policy based on the appropriate urlaction (singed/unsigned)
  2156. hr = CheckActiveXDownloadEnabled(pHostSecurityManager, szURL, pclientbsc);
  2157. if (FAILED(hr)) {
  2158. pcdl->Release();
  2159. goto AGCB_Exit;
  2160. }
  2161. }
  2162. // chain this CodeDownload to the list of downloads in this thread
  2163. pos = tls->pCodeDownloadList->AddHead(pcdl);
  2164. pcdl->SetListCookie(pos);
  2165. hr = pcdl->DoCodeDownload(plci, flags);
  2166. plci = NULL;
  2167. pcdl->Release(); // if async binding OnStartBinding would have addref'ed
  2168. AGCB_Exit:
  2169. if (pPluginFileName)
  2170. delete pPluginFileName;
  2171. if(pdlog)
  2172. pdlog->Release();
  2173. SAFEDELETE(plci);
  2174. SAFERELEASE(pHostSecurityManager);
  2175. DEBUG_LEAVE_API(hr);
  2176. return hr;
  2177. }
  2178. STDAPI
  2179. WrapCoInstall (
  2180. REFCLSID rCLASSID, // CLSID of object (may be NULL)
  2181. LPCWSTR szCODE, // URL to code (may be NULL)
  2182. DWORD dwFileVersionMS, // Version of primary object
  2183. DWORD dwFileVersionLS, // Version of primary object
  2184. LPCWSTR szTYPE, // MIME type (may be NULL)
  2185. LPBINDCTX pBindCtx, // Bind ctx
  2186. DWORD dwClsContext, // CLSCTX flags
  2187. LPVOID pvReserved, // Must be NULL
  2188. REFIID riid, // Usually IID_IClassFactory
  2189. DWORD flags
  2190. )
  2191. {
  2192. DEBUG_ENTER_API((DBG_DOWNLOAD,
  2193. Hresult,
  2194. "WrapCoInstall",
  2195. "%#x, %.80wq, %#x, %#x, %.80wq, %#x, %#x, %#x, %#x, %#x",
  2196. &rCLASSID, szCODE, dwFileVersionMS, dwFileVersionLS, szTYPE, pBindCtx, dwClsContext, pvReserved, &riid, flags
  2197. ));
  2198. HRESULT hr = NO_ERROR;
  2199. // DWORD flags = 0; // CD_FLAGS_NEED_CLASSFACTORY;
  2200. WCHAR *szExt = NULL;
  2201. #ifdef WRAP_OLE32_COINSTALL
  2202. CBSCCreateObject* pobjectbsc=NULL;
  2203. #endif
  2204. UrlMkDebugOut((DEB_CODEDL, "IN WrapCoInstall CLASSID: %lx, TYPE=%ws...szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n", rCLASSID.Data1, szTYPE, szCODE, dwFileVersionMS, dwFileVersionLS));
  2205. // Note about pvReserved: this is used by DCOM to get in the remote server
  2206. // name and other info. If not NULL, then the caller wants us to use
  2207. // dcom. if (pvReserved) just call CoGetClassObject.
  2208. // call AsyncGetClassBits to do the real work
  2209. if (pvReserved == NULL)
  2210. {
  2211. // Set up CoInstall parameters
  2212. uCLSSPEC classpec;
  2213. QUERYCONTEXT query;
  2214. if (!IsEqualGUID(rCLASSID, CLSID_NULL))
  2215. {
  2216. classpec.tyspec=TYSPEC_CLSID;
  2217. classpec.tagged_union.clsid=rCLASSID; // use original class ID so that MIME can still be processed
  2218. }
  2219. else if (szTYPE && *szTYPE)
  2220. {
  2221. classpec.tyspec=TYSPEC_MIMETYPE;
  2222. classpec.tagged_union.pMimeType=(LPWSTR) szTYPE; // BUGBUG uCLSSPEC::pMimeType should be declared const!
  2223. }
  2224. else
  2225. {
  2226. hr=E_INVALIDARG;
  2227. goto Exit;
  2228. }
  2229. query.dwContext = dwClsContext;
  2230. GetDefaultPlatform(&query.Platform);
  2231. query.Locale = GetThreadLocale();
  2232. query.dwVersionHi = dwFileVersionMS;
  2233. query.dwVersionLo = dwFileVersionLS;
  2234. #ifdef WRAP_OLE32_COINSTALL
  2235. // Override the client's BSC with a BSC that will create the object when it receives a successful OnStopBinding
  2236. // CBSCCreateObject registers itself in the bind context and saves a pointer to the client's BSC
  2237. // it unregisters itself upon OnStopBinding
  2238. pobjectbsc=new CBSCCreateObject(rCLASSID, szTYPE, szExt, dwClsContext, pvReserved, riid, pBindCtx, flags, hr); // hr by reference!
  2239. if (!pobjectbsc)
  2240. {
  2241. hr = E_OUTOFMEMORY;
  2242. goto Exit;
  2243. }
  2244. if (FAILED(hr))
  2245. {
  2246. goto Exit;
  2247. }
  2248. #endif
  2249. hr=CoInstall(pBindCtx, flags, &classpec, &query, (LPWSTR) szCODE); //BUGBUG CoInstall szCodeBase should be const!
  2250. if (hr!=MK_S_ASYNCHRONOUS)
  2251. {
  2252. // clean up the bind context for synchronous and failure case
  2253. // in asynchronous case pobjectbsc revokes itself in OnStopBinding!
  2254. //pobjectbsc->RevokeFromBC();
  2255. }
  2256. //hr = AsyncGetClassBits( rCLASSID,
  2257. // szTYPE, szExt,
  2258. // dwFileVersionMS, dwFileVersionLS, szCODE,
  2259. // pBindCtx, dwClsContext, pvReserved, riid, flags);
  2260. #ifdef WRAP_OLE32_COINSTALL
  2261. pobjectbsc->Release();
  2262. pobjectbsc=NULL;
  2263. #endif
  2264. }
  2265. Exit:
  2266. #ifdef WRAP_OLE32_COINSTALL
  2267. if (pobjectbsc)
  2268. {
  2269. pobjectbsc->Release();
  2270. pobjectbsc=NULL;
  2271. }
  2272. #endif
  2273. UrlMkDebugOut((DEB_CODEDL, "OUT WrapCoInstall hr:%lx%s, CLASSID: %lx, TYPE=%ws..., szCODE:(%ws), VersionMS:%lx, VersionLS:%lx\n",
  2274. hr,(hr == MK_S_ASYNCHRONOUS)?"(PENDING)":(hr == S_OK)?"(SUCCESS)":"",
  2275. rCLASSID.Data1, szTYPE, szCODE, dwFileVersionMS, dwFileVersionLS));
  2276. DEBUG_LEAVE_API(hr);
  2277. return hr;
  2278. }
  2279. STDAPI PrivateCoInstall(
  2280. IBindCtx *pbc,
  2281. DWORD dwFlags,
  2282. uCLSSPEC *pClassSpec,
  2283. QUERYCONTEXT *pQuery,
  2284. LPWSTR pszCodeBase)
  2285. {
  2286. DEBUG_ENTER_API((DBG_DOWNLOAD,
  2287. Hresult,
  2288. "PrivateCoInstall",
  2289. "%#x, %#x, %#x, %#x, %.80wq",
  2290. pbc, dwFlags, pClassSpec, pQuery, pszCodeBase
  2291. ));
  2292. HRESULT hr = NO_ERROR;
  2293. CLSID inclsid = CLSID_NULL;
  2294. LPCWSTR pszDistUnit=NULL;
  2295. LPCWSTR pszFileExt=NULL;
  2296. LPCWSTR pszMimeType=NULL;
  2297. QUERYCONTEXT query;
  2298. // "Parse" the parameters from the CLSSPEC and QUERYCONTEXT
  2299. // Get the class spec.
  2300. if(pClassSpec != NULL)
  2301. {
  2302. switch(pClassSpec->tyspec)
  2303. {
  2304. case TYSPEC_CLSID:
  2305. inclsid = pClassSpec->tagged_union.clsid;
  2306. break;
  2307. case TYSPEC_MIMETYPE:
  2308. pszMimeType = (LPCWSTR) pClassSpec->tagged_union.pMimeType;
  2309. break;
  2310. case TYSPEC_FILEEXT:
  2311. pszFileExt = (LPCWSTR) pClassSpec->tagged_union.pFileExt;
  2312. break;
  2313. case TYSPEC_FILENAME:
  2314. pszDistUnit= (LPCWSTR) pClassSpec->tagged_union.pFileName; // clean-up: this is the only case where we assign existing mem to pszDistUnit!
  2315. // BUGBUG: need to do this in OLE's CoInstall as well!
  2316. CLSIDFromString((LPOLESTR)pszDistUnit, &inclsid);// if fails szDistUnit is not clsid
  2317. break;
  2318. default:
  2319. break;
  2320. }
  2321. }
  2322. //Get the query context.
  2323. if(pQuery != NULL)
  2324. {
  2325. query = *pQuery;
  2326. }
  2327. else
  2328. {
  2329. query.dwContext = CLSCTX_ALL;
  2330. GetDefaultPlatform(&query.Platform);
  2331. query.Locale = GetThreadLocale();
  2332. query.dwVersionHi = (DWORD) -1;
  2333. query.dwVersionLo = (DWORD) -1;
  2334. }
  2335. hr = AsyncInstallDistributionUnit( pszDistUnit,
  2336. pszMimeType,
  2337. pszFileExt,
  2338. query.dwVersionHi, query.dwVersionLo,
  2339. pszCodeBase,
  2340. pbc,
  2341. NULL,
  2342. dwFlags | CD_FLAGS_FORCE_INTERNET_DOWNLOAD // ensure no mutual recursion
  2343. );
  2344. DEBUG_LEAVE_API(hr);
  2345. return hr;
  2346. }