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.

2066 lines
67 KiB

  1. #include <fusenetincludes.h>
  2. #include <bits.h>
  3. #include <assemblycache.h>
  4. #include "dialog.h"
  5. #include <assemblydownload.h>
  6. #include <msxml2.h>
  7. #include <manifestimport.h>
  8. #include <patchingutil.h>
  9. #include <sxsapi.h>
  10. #include ".\patchapi.h"
  11. // Update services
  12. #include "server.h"
  13. #include "fusion.h"
  14. #include <shellapi.h>
  15. #include "regdb.h"
  16. #include "macros.h"
  17. IBackgroundCopyManager* g_pBITSManager = NULL;
  18. // ---------------------------------------------------------------------------
  19. // CreateAssemblyDownload
  20. // ---------------------------------------------------------------------------
  21. STDAPI CreateAssemblyDownload(IAssemblyDownload** ppDownload, CDebugLog *pDbgLog, DWORD dwFlags)
  22. {
  23. HRESULT hr = S_OK;
  24. MAKE_ERROR_MACROS_STATIC(hr);
  25. CAssemblyDownload *pDownload = NULL;
  26. IF_ALLOC_FAILED_EXIT( pDownload = new(CAssemblyDownload ));
  27. IF_FAILED_EXIT(pDownload->_hr);
  28. IF_FAILED_EXIT(pDownload->Init((CDebugLog *) pDbgLog));
  29. *ppDownload = (IAssemblyDownload*) pDownload;
  30. pDownload = NULL;
  31. #ifdef DEVMODE
  32. if (dwFlags == DOWNLOAD_DEVMODE)
  33. ((CAssemblyDownload *)*ppDownload)->_bIsDevMode = TRUE;
  34. #endif
  35. exit:
  36. SAFERELEASE(pDownload);
  37. return hr;
  38. }
  39. HRESULT CAssemblyDownload::Init( CDebugLog * pDbgLog)
  40. {
  41. _pDbgLog = pDbgLog;
  42. if(pDbgLog)
  43. {
  44. pDbgLog->AddRef();
  45. }
  46. else
  47. {
  48. _bLocalLog = TRUE;
  49. IF_FAILED_EXIT(CreateLogObject(&_pDbgLog, NULL));
  50. }
  51. exit :
  52. return _hr;
  53. }
  54. // ---------------------------------------------------------------------------
  55. // ctor
  56. // ---------------------------------------------------------------------------
  57. CAssemblyDownload::CAssemblyDownload()
  58. : _dwSig('DLND'), _cRef(1), _hr(S_OK), _hrError(S_OK), _pRootEmit(NULL), _pBindSink(NULL),
  59. _pJob(NULL), _pDlg(NULL), _pPatchingInfo(NULL), _bAbort(FALSE),
  60. #ifdef DEVMODE
  61. _bIsDevMode(FALSE),
  62. #endif
  63. _bAbortFromBindSink(FALSE), _bErrorHandled(FALSE), _pDbgLog(NULL), _bLocalLog(FALSE)
  64. {
  65. __try
  66. {
  67. InitializeCriticalSection(&_cs);
  68. }
  69. __except (GetExceptionCode() == STATUS_NO_MEMORY ?
  70. EXCEPTION_EXECUTE_HANDLER :
  71. EXCEPTION_CONTINUE_SEARCH )
  72. {
  73. _hr = E_OUTOFMEMORY;
  74. }
  75. return;
  76. }
  77. // ---------------------------------------------------------------------------
  78. // dtor
  79. // ---------------------------------------------------------------------------
  80. CAssemblyDownload::~CAssemblyDownload()
  81. {
  82. if(_pDbgLog && _bLocalLog)
  83. {
  84. DUMPDEBUGLOG(_pDbgLog, -1, _hr);
  85. }
  86. SAFERELEASE(_pPatchingInfo);
  87. SAFERELEASE(_pRootEmit);
  88. SAFEDELETE(_pDlg);
  89. SAFERELEASE(_pJob);
  90. SAFERELEASE(_pDbgLog);
  91. DeleteCriticalSection(&_cs);
  92. return;
  93. }
  94. // IAssemblyDownload methods
  95. // ---------------------------------------------------------------------------
  96. // DownloadManifestAndDependencies
  97. // ---------------------------------------------------------------------------
  98. HRESULT CAssemblyDownload::DownloadManifestAndDependencies(
  99. LPWSTR pwzManifestUrl, IAssemblyBindSink *pBindSink, DWORD dwFlags)
  100. {
  101. LPWSTR pwz = NULL;
  102. CString sRemoteUrl;
  103. CString sLocalName;
  104. IBackgroundCopyJob *pJob = NULL;
  105. IF_FAILED_EXIT(_pDbgLog->SetDownloadType(dwFlags));
  106. // Create temporary manifest path from url.
  107. IF_FAILED_EXIT(sRemoteUrl.Assign(pwzManifestUrl));
  108. IF_FAILED_EXIT(MakeTempManifestLocation(sRemoteUrl, sLocalName));
  109. // Init dialog object with job
  110. if (dwFlags & DOWNLOAD_FLAGS_PROGRESS_UI)
  111. IF_FAILED_EXIT(CreateDialogObject(&_pDlg));
  112. // set named event if specified.
  113. if (dwFlags & DOWNLOAD_FLAGS_NOTIFY_BINDSINK)
  114. _pBindSink = pBindSink;
  115. // Create new job. Display name is url.
  116. IF_FAILED_EXIT(CreateNewBITSJob(&pJob, sRemoteUrl));
  117. // add this job to reg.
  118. IF_FAILED_EXIT(AddJobToRegistry(sRemoteUrl._pwz, sLocalName._pwz, pJob, 0));
  119. // Add single app or subscription manifest to job.
  120. IF_FAILED_EXIT(pJob->AddFile(sRemoteUrl._pwz, sLocalName._pwz));
  121. // Submit the job.
  122. IF_FAILED_EXIT(pJob->Resume());
  123. // Release the job; BITS keeps own refcount.
  124. SAFERELEASE(pJob);
  125. // Pump messages if progress ui specified.
  126. if (dwFlags & DOWNLOAD_FLAGS_PROGRESS_UI)
  127. {
  128. MSG msg;
  129. BOOL bRet;
  130. DWORD dwError;
  131. while((bRet = GetMessage( &msg, _pDlg->_hwndDlg, 0, 0 )))
  132. {
  133. DWORD dwLow = LOWORD(msg.message);
  134. if (dwLow == WM_CANCEL_DOWNLOAD)
  135. {
  136. // Signal abort; hide progress UI.
  137. CancelDownload();
  138. }
  139. else if (dwLow == WM_FINISH_DOWNLOAD)
  140. {
  141. // Terminates progress UI.
  142. FinishDownload();
  143. break;
  144. }
  145. if (!IsDialogMessage(_pDlg->_hwndDlg, &msg))
  146. {
  147. TranslateMessage( &msg );
  148. DispatchMessage( &msg );
  149. }
  150. }
  151. }
  152. exit:
  153. // If aborted by bindsink, return S_OK. // We should return hrError instead of _hr.
  154. return ((_hr == E_ABORT) && _bAbortFromBindSink) ? S_OK : ( FAILED(_hr) ? _hr : _hrError) ;
  155. }
  156. // ---------------------------------------------------------------------------
  157. // CancelDownload
  158. //
  159. // Do not attempt to obtain the object critical section _cs in this method - in abort cases it
  160. // can be called by a non-callback client thread under the same critical section protecting a
  161. // global list of downloads which the bindsink must itself acquire, resulting in classic deadlock.
  162. // ---------------------------------------------------------------------------
  163. HRESULT CAssemblyDownload::CancelDownload()
  164. {
  165. // Signal abort; async the cancel. The download will be cancelled
  166. // by the callback thread when it checks the _bAbort flag.
  167. SignalAbort();
  168. if (_pDlg)
  169. ShowWindow(_pDlg->_hwndDlg, SW_HIDE);
  170. _hr = S_OK;
  171. DEBUGOUT(_pDbgLog, 0, L"LOG: User Canceled. Aborting Download ...... ");
  172. return _hr;
  173. }
  174. // ---------------------------------------------------------------------------
  175. // DoCacheUpdate
  176. // ---------------------------------------------------------------------------
  177. HRESULT CAssemblyDownload::DoCacheUpdate(IBackgroundCopyJob *pJob)
  178. {
  179. DWORD nCount = 0;
  180. BOOL bIsManifestFile = FALSE;
  181. IEnumBackgroundCopyFiles *pEnumFiles = NULL;
  182. IBackgroundCopyFile *pFile = NULL;
  183. IBackgroundCopyJob *pChildJob = NULL;
  184. // Commit files to disk
  185. IF_FAILED_EXIT(pJob->Complete());
  186. // Remove in-progress status for job.
  187. IF_FAILED_EXIT(RemoveJobFromRegistry(_pJob, NULL, SHREGDEL_HKCU, 0));
  188. // Decrement _pJob's refcount because
  189. // BITS mysteriously won't release the
  190. // CBitsCallback if _pJob has an additional refcount
  191. SetJobObject(NULL);
  192. // Get the file enumerator.
  193. IF_FAILED_EXIT(pJob->EnumFiles(&pEnumFiles));
  194. IF_FAILED_EXIT(pEnumFiles->GetCount(&nCount));
  195. // Enumerate the files in the job.
  196. for (DWORD i = 0; i < nCount; i++)
  197. {
  198. IF_FAILED_EXIT(pEnumFiles->Next(1, &pFile, NULL));
  199. // Process manifest file or normal/patch file.
  200. IF_FAILED_EXIT(IsManifestFile(pFile, &bIsManifestFile));
  201. if (bIsManifestFile)
  202. IF_FAILED_EXIT(HandleManifest(pFile, &pChildJob));
  203. else
  204. IF_FAILED_EXIT(HandleFile(pFile));
  205. SAFERELEASE(pFile);
  206. }
  207. // If a additional dependencies were found.
  208. if (pChildJob)
  209. {
  210. // Also update dialog with new job
  211. if (_pDlg)
  212. _pDlg->SetJobObject(pChildJob);
  213. // Submit new job.
  214. IF_FAILED_EXIT(pChildJob->Resume());
  215. goto exit;
  216. }
  217. // ** Commit/Signal/Return***
  218. // Done. Do all necessary cleanup
  219. // before committing application to cache.
  220. // If patching was used during the download ensure
  221. // the patching temp directory is deleted.
  222. if (_pPatchingInfo)
  223. IF_FAILED_EXIT(CleanUpPatchDir());
  224. // If any assemblies were marked for
  225. // global cach install, install them now.
  226. if (_ListGlobalCacheInstall.GetCount())
  227. IF_FAILED_EXIT(InstallGlobalAssemblies());
  228. // Commit application.
  229. if (_pRootEmit)
  230. IF_FAILED_EXIT(_pRootEmit->Commit(0));
  231. // registration hack if avalon app.
  232. IF_FAILED_EXIT(DoEvilAvalonRegistrationHack());
  233. // If progress ui terminate it.
  234. if (_pDlg)
  235. _pDlg->SetDlgState(DOWNLOADDLG_STATE_ALL_DONE);
  236. // If callback signal.
  237. if (_pBindSink)
  238. {
  239. IF_FAILED_EXIT(_pBindSink->OnProgress(ASM_NOTIFICATION_DONE, S_OK, NULL, 0, 0, NULL));
  240. // Ensure this is last notification bindsink receives resulting from
  241. // subsequent JobModified notifications.
  242. // DO NOT free the bindsink here.
  243. _pBindSink = NULL;
  244. }
  245. exit:
  246. SAFERELEASE(pEnumFiles);
  247. SAFERELEASE(pChildJob);
  248. SAFERELEASE(pFile);
  249. return _hr;
  250. }
  251. // ---------------------------------------------------------------------------
  252. // HandleManifest
  253. // ---------------------------------------------------------------------------
  254. HRESULT CAssemblyDownload::HandleManifest(IBackgroundCopyFile *pFile,
  255. IBackgroundCopyJob **ppJob)
  256. {
  257. LPWSTR pwz = NULL;
  258. DWORD dwManifestType = MANIFEST_TYPE_UNKNOWN;
  259. CString sLocalName(CString::COM_Allocator);
  260. CString sRemoteName(CString::COM_Allocator);
  261. IAssemblyManifestImport *pManifestImport = NULL;
  262. // Get local manifest file name.
  263. IF_FAILED_EXIT(pFile->GetLocalName(&pwz));
  264. IF_FAILED_EXIT(sLocalName.TakeOwnership(pwz));
  265. // Get remote manifest url
  266. IF_FAILED_EXIT(pFile->GetRemoteName(&pwz));
  267. IF_FAILED_EXIT(sRemoteName.TakeOwnership(pwz));
  268. // Instance a manifest import interface.
  269. IF_FAILED_EXIT(CreateAssemblyManifestImport(&pManifestImport, sLocalName._pwz, _pDbgLog, 0));
  270. // Get the manifest type.
  271. IF_FAILED_EXIT(pManifestImport->ReportManifestType(&dwManifestType));
  272. // Handle either subscription or application manifest
  273. if (dwManifestType == MANIFEST_TYPE_SUBSCRIPTION)
  274. {
  275. DEBUGOUT1(_pDbgLog, 1, L" LOG: Got subscription manifest from %s ", sRemoteName._pwz);
  276. IF_FAILED_EXIT(HandleSubscriptionManifest(pManifestImport, sLocalName, sRemoteName, ppJob));
  277. }
  278. else if (dwManifestType == MANIFEST_TYPE_APPLICATION)
  279. {
  280. DEBUGOUT1(_pDbgLog, 1, L" LOG: Got App manifest from %s ", sRemoteName._pwz);
  281. IF_FAILED_EXIT(HandleApplicationManifest(pManifestImport, sLocalName, sRemoteName, ppJob));
  282. }
  283. else if (dwManifestType == MANIFEST_TYPE_COMPONENT)
  284. {
  285. DEBUGOUT1(_pDbgLog, 1, L" LOG: Got component manifest from %s ", sRemoteName._pwz);
  286. IF_FAILED_EXIT(HandleComponentManifest(pManifestImport, sLocalName, sRemoteName, ppJob));
  287. }
  288. else
  289. {
  290. DEBUGOUT1(_pDbgLog, 0, L" ERR: UNknown manifest type in File %s \n",
  291. sRemoteName._pwz);
  292. _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
  293. goto exit;
  294. }
  295. // Cleanup manifest temp dir.
  296. SAFERELEASE(pManifestImport);
  297. IF_WIN32_FALSE_EXIT(::DeleteFile(sLocalName._pwz));
  298. IF_FAILED_EXIT(sLocalName.RemoveLastElement());
  299. IF_FAILED_EXIT(RemoveDirectoryAndChildren(sLocalName._pwz));
  300. _hr = S_OK;
  301. exit:
  302. SAFERELEASE(pManifestImport);
  303. return _hr;
  304. }
  305. // ---------------------------------------------------------------------------
  306. // HandleSubscriptionManifest
  307. // ---------------------------------------------------------------------------
  308. HRESULT CAssemblyDownload::HandleSubscriptionManifest(
  309. IAssemblyManifestImport *pManifestImport, CString &sLocalName,
  310. CString &sRemoteName, IBackgroundCopyJob **ppJob)
  311. {
  312. IManifestInfo *pAppAssemblyInfo = NULL;
  313. IAssemblyIdentity *pAppId = NULL;
  314. // If callback signal.
  315. if (_pBindSink)
  316. {
  317. // BUGBUG: fill in progress?
  318. _hr = _pBindSink->OnProgress(ASM_NOTIFICATION_SUBSCRIPTION_MANIFEST, _hr, sRemoteName._pwz, 0, 0, pManifestImport);
  319. // Bindsink communicates abort via return value.
  320. if (_hr == E_ABORT)
  321. _bAbortFromBindSink = TRUE;
  322. // Catches E_ABORT case.
  323. IF_FAILED_EXIT(_hr);
  324. }
  325. // If foreground download reset dialog and queue up dependency
  326. if (_pDlg)
  327. {
  328. _pDlg->InitDialog(_pDlg->_hwndDlg);
  329. _pDlg->SetDlgState(DOWNLOADDLG_STATE_GETTING_APP_MANIFEST);
  330. IF_FAILED_EXIT(EnqueueDependencies(pManifestImport, sRemoteName, ppJob));
  331. }
  332. // Otherwise background download. Don't submit request if app already
  333. // cached or download is in progress.
  334. else
  335. {
  336. DWORD cb = 0, dwFlag = 0;
  337. // Get the dependent (application) assembly info (0th index)
  338. IF_FAILED_EXIT(pManifestImport->GetNextAssembly(0, &pAppAssemblyInfo));
  339. // Get dependent (application) assembly identity
  340. IF_FAILED_EXIT(pAppAssemblyInfo->Get(MAN_INFO_DEPENDENT_ASM_ID, (LPVOID *)&pAppId, &cb, &dwFlag));
  341. IF_FAILED_EXIT(CAssemblyCache::IsCached(pAppId));
  342. if (_hr == S_FALSE)
  343. IF_FAILED_EXIT(EnqueueDependencies(pManifestImport, sRemoteName, ppJob));
  344. }
  345. exit:
  346. SAFERELEASE(pAppId);
  347. SAFERELEASE(pAppAssemblyInfo);
  348. return _hr;
  349. }
  350. // ---------------------------------------------------------------------------
  351. // HandleApplicationManifest
  352. // ---------------------------------------------------------------------------
  353. HRESULT CAssemblyDownload::HandleApplicationManifest(
  354. IAssemblyManifestImport *pManifestImport, CString &sLocalName,
  355. CString &sRemoteName, IBackgroundCopyJob **ppJob)
  356. {
  357. // If callback signal.
  358. if (_pBindSink)
  359. {
  360. // BUGBUG: fill in progress?
  361. _hr = _pBindSink->OnProgress(ASM_NOTIFICATION_APPLICATION_MANIFEST, _hr, sRemoteName._pwz, 0, 0, pManifestImport);
  362. // Bindsink communicates abort via return value.
  363. if (_hr == E_ABORT)
  364. _bAbortFromBindSink = TRUE;
  365. // Catches E_ABORT case.
  366. IF_FAILED_EXIT(_hr);
  367. }
  368. // This is the one location where we know the RemoteUrl is the appbase/app.manifest.
  369. // save off the app base.
  370. IF_FAILED_EXIT(_sAppBase.Assign(sRemoteName));
  371. IF_FAILED_EXIT(_sAppBase.RemoveLastElement());
  372. IF_FAILED_EXIT(_sAppBase.Append(L"/"));
  373. // App manifest generically handled by component manifest handler.
  374. IF_FAILED_EXIT(HandleComponentManifest(pManifestImport, sLocalName, sRemoteName, ppJob));
  375. exit:
  376. return _hr;
  377. }
  378. // ---------------------------------------------------------------------------
  379. // HandleComponentManifest
  380. // ---------------------------------------------------------------------------
  381. HRESULT CAssemblyDownload::HandleComponentManifest(
  382. IAssemblyManifestImport *pManifestImport, CString &sLocalName, CString &sRemoteName,
  383. IBackgroundCopyJob **ppJob)
  384. {
  385. LPWSTR pwz = NULL; DWORD cb = 0, cc= 0;
  386. CString sManifestFileName;
  387. CString sRelativePath;
  388. IAssemblyIdentity *pIdentity = NULL;
  389. IAssemblyCacheEmit *pCacheEmit = NULL;
  390. IAssemblyCacheImport *pCacheImport = NULL;
  391. IManifestInfo *pAppInfo = NULL;
  392. // Reset dialog for now.
  393. if (_pDlg)
  394. {
  395. _pDlg->InitDialog(_pDlg->_hwndDlg);
  396. _pDlg->SetDlgState(DOWNLOADDLG_STATE_GETTING_OTHER_FILES);
  397. }
  398. // Generate the cache entry (assemblydir/manifest/<dirs>)
  399. // First callbac, _pRootEmit = NULL;
  400. IF_FAILED_EXIT(CreateAssemblyCacheEmit(&pCacheEmit, _pRootEmit, 0));
  401. // If this is first cache entry created, save as root.
  402. if (!_pRootEmit)
  403. {
  404. _pRootEmit = pCacheEmit;
  405. _pRootEmit->AddRef();
  406. }
  407. // Get the manifest file name from local (staging) path.
  408. IF_FAILED_EXIT(sLocalName.LastElement(sManifestFileName));
  409. // double check its in the app dir.
  410. IF_FAILED_EXIT((sRemoteName.StartsWith(_sAppBase._pwz)));
  411. IF_FALSE_EXIT((_hr == S_OK), E_INVALIDARG);
  412. // Index into remote url for relative path.
  413. pwz = sRemoteName._pwz + _sAppBase._cc -1;
  414. IF_FAILED_EXIT(sRelativePath.Assign(pwz));
  415. // Create the cache entry.
  416. // (x86_foo_1.0.0.0_en-us/foo.manifest/<+extra dirs>)
  417. //BugBug, temporary hack to distinguish between application and component manifests
  418. if (_pRootEmit == pCacheEmit)
  419. IF_FAILED_EXIT(pCacheEmit->CopyFile(sLocalName._pwz, sRelativePath._pwz, MANIFEST));
  420. else
  421. IF_FAILED_EXIT(pCacheEmit->CopyFile(sLocalName._pwz, sRelativePath._pwz, MANIFEST |COMPONENT));
  422. // displayname is not set until after a copyfile() call
  423. if(_sAppDisplayName._cc == 0)
  424. {
  425. // _pRootEmit == pCacheEmit
  426. IF_FAILED_EXIT(_pRootEmit->GetDisplayName(&pwz, &cc));
  427. IF_FAILED_EXIT(_sAppDisplayName.TakeOwnership(pwz, cc));
  428. IF_FAILED_EXIT(_pDbgLog->SetAppName(pwz));
  429. // must be an application manifest...
  430. if (_pDlg)
  431. {
  432. DWORD dwFlag = 0;
  433. IF_FAILED_EXIT(pManifestImport->GetManifestApplicationInfo(&pAppInfo));
  434. IF_FALSE_EXIT((_hr == S_OK), E_INVALIDARG);
  435. IF_FAILED_EXIT(pAppInfo->Get(MAN_INFO_APPLICATION_FRIENDLYNAME, (LPVOID *)&pwz, &cb, &dwFlag));
  436. if (SUCCEEDED(_hr) && pwz)
  437. {
  438. // set progress ui title (set once per download)
  439. IF_FAILED_EXIT(_pDlg->SetDlgTitle(pwz));
  440. SAFEDELETEARRAY(pwz);
  441. }
  442. }
  443. }
  444. // QI for the import interface.
  445. IF_FAILED_EXIT(pCacheEmit->QueryInterface(IID_IAssemblyCacheImport, (LPVOID*) &pCacheImport));
  446. // Check if the assembly can be cached globally
  447. // bugbug - same hack to distinguish application/component manifest
  448. if (_pRootEmit != pCacheEmit)
  449. {
  450. //BUGBUG - verify not an xml manifest for gac install.
  451. IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pIdentity));
  452. // Known assembly?
  453. BOOL bIsAvalon = FALSE;
  454. IF_FAILED_EXIT(IsAvalonAssembly(pIdentity, &bIsAvalon));
  455. if (bIsAvalon)
  456. {
  457. // notenote: assume no same assembly already in the list for add-ref-ing
  458. // add to the list of assemblies to be installed
  459. CGlobalCacheInstallEntry* pGACInstallEntry = new CGlobalCacheInstallEntry();
  460. IF_ALLOC_FAILED_EXIT(pGACInstallEntry);
  461. pGACInstallEntry->_pICacheImport = pCacheImport;
  462. pCacheImport->AddRef();
  463. _ListGlobalCacheInstall.AddHead(pGACInstallEntry);
  464. }
  465. }
  466. // Line up it's dependencies for download and fire them off.
  467. // We pass the cache import interface for app manifests.
  468. IF_FAILED_EXIT(EnqueueDependencies(pCacheImport, sRemoteName, ppJob));
  469. exit:
  470. SAFERELEASE(pIdentity);
  471. SAFERELEASE(pCacheEmit);
  472. SAFERELEASE(pCacheImport);
  473. SAFERELEASE(pAppInfo);
  474. return _hr;
  475. }
  476. // ---------------------------------------------------------------------------
  477. // HandleFile
  478. // ---------------------------------------------------------------------------
  479. HRESULT CAssemblyDownload::HandleFile(IBackgroundCopyFile *pFile)
  480. {
  481. DWORD cb = 0, dwFlag = 0;
  482. LPWSTR pwz = NULL;
  483. CString sLocalName(CString::COM_Allocator);
  484. CString sPatchTempDirectory;
  485. // Get local manifest file name.
  486. IF_FAILED_EXIT(pFile->GetLocalName(&pwz));
  487. IF_FAILED_EXIT(sLocalName.TakeOwnership(pwz));
  488. // Begin patch file handling
  489. // if file was a patch file, find the source and target, apply patch to source and move result to target
  490. if (_pPatchingInfo)
  491. {
  492. // Grab temp file directory
  493. // "C:\Program Files\Application Store\x86_foo_X.X.X.X\PATCH_DIRECTORY\"
  494. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_TEMP_DIR, (LPVOID *)&pwz, &cb, &dwFlag));
  495. IF_FAILED_EXIT(sPatchTempDirectory.TakeOwnership(pwz));
  496. // if local file begins with the manifests patch direcotry, file is a patch file
  497. IF_FAILED_EXIT(sLocalName.StartsWith(sPatchTempDirectory._pwz));
  498. if (_hr== S_OK)
  499. {
  500. IF_FAILED_EXIT(ApplyPatchFile (sLocalName._pwz));
  501. }
  502. }
  503. else
  504. {
  505. // Otherwise no action; assert regular file.
  506. }
  507. exit:
  508. return _hr;
  509. }
  510. // ---------------------------------------------------------------------------
  511. // EnqueueDependencies
  512. // ---------------------------------------------------------------------------
  513. HRESULT CAssemblyDownload::EnqueueDependencies(IUnknown* pUnk,
  514. CString &sRemoteName, IBackgroundCopyJob **ppJob)
  515. {
  516. DWORD cc = 0, dwManifestType = MANIFEST_TYPE_UNKNOWN;
  517. LPWSTR pwz = NULL;
  518. CString sDisplayName;
  519. IAssemblyIdentity *pIdentity = NULL;
  520. IAssemblyManifestImport *pManifestImport = NULL;
  521. IAssemblyCacheImport *pCacheImport = NULL;
  522. // Get either manifest import or cache import passed in.
  523. _hr = pUnk->QueryInterface(IID_IAssemblyCacheImport, (LPVOID*) &pCacheImport);
  524. if ((_hr == S_OK) && pCacheImport)
  525. IF_FAILED_EXIT(pCacheImport->GetManifestImport(&pManifestImport));
  526. else
  527. IF_FAILED_EXIT(pUnk->QueryInterface(IID_IAssemblyManifestImport, (LPVOID*) &pManifestImport));
  528. // Get the display name for the job.
  529. if (!_sAppDisplayName._cc)
  530. {
  531. IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pIdentity));
  532. IF_FAILED_EXIT(pIdentity->GetDisplayName(0, &pwz, &cc));
  533. IF_FAILED_EXIT(_pDbgLog->SetAppName(pwz));
  534. IF_FAILED_EXIT(sDisplayName.TakeOwnership(pwz, cc));
  535. }
  536. else
  537. IF_FAILED_EXIT(sDisplayName.Assign(_sAppDisplayName));
  538. // Get the manifest type.
  539. IF_FAILED_EXIT(pManifestImport->ReportManifestType(&dwManifestType));
  540. // Handle either subscription or application manifest
  541. if (dwManifestType == MANIFEST_TYPE_SUBSCRIPTION)
  542. IF_FAILED_EXIT(EnqueueSubscriptionDependencies(pManifestImport, _sAppBase, sDisplayName, ppJob));
  543. else if (dwManifestType == MANIFEST_TYPE_APPLICATION)
  544. IF_FAILED_EXIT(EnqueueApplicationDependencies(pCacheImport, sRemoteName, sDisplayName, ppJob));
  545. else if (dwManifestType == MANIFEST_TYPE_COMPONENT)
  546. IF_FAILED_EXIT(EnqueueComponentDependencies(pCacheImport, sRemoteName, sDisplayName, FALSE, ppJob));
  547. else
  548. {
  549. DEBUGOUT1(_pDbgLog, 0, L" ERR: Unknown manifest type in File %s \n",
  550. sRemoteName._pwz);
  551. _hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
  552. }
  553. exit:
  554. SAFERELEASE(pCacheImport);
  555. SAFERELEASE(pManifestImport);
  556. SAFERELEASE(pIdentity);
  557. return _hr;
  558. }
  559. // ---------------------------------------------------------------------------
  560. // EnqueueSubscriptionDependencies
  561. // ---------------------------------------------------------------------------
  562. HRESULT CAssemblyDownload::EnqueueSubscriptionDependencies(
  563. IAssemblyManifestImport *pManifestImport, CString &sCodebase, CString &sDisplayName,
  564. IBackgroundCopyJob **ppJob)
  565. {
  566. DWORD dwFlag = 0, cb = 0, cc = 0;
  567. LPWSTR pwz = NULL;
  568. CString sAssemblyName;
  569. CString sLocalFilePath;
  570. CString sRemoteUrl;
  571. IAssemblyIdentity *pIdentity = NULL;
  572. IManifestInfo *pDependAsm = NULL;
  573. // Get the single dependency
  574. IF_FAILED_EXIT(pManifestImport->GetNextAssembly(0, &pDependAsm));
  575. // Form local cache name (in staging area)....
  576. IF_FAILED_EXIT(pDependAsm->Get(MAN_INFO_DEPENDENT_ASM_ID, (LPVOID *)&pIdentity, &cb, &dwFlag));
  577. // Get the identity name
  578. IF_FAILED_EXIT(pIdentity->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwz, &cc));
  579. sAssemblyName.TakeOwnership(pwz, cc);
  580. // Get codebase from dependency info, if any specified
  581. IF_FAILED_EXIT(pDependAsm->Get(MAN_INFO_DEPENDENT_ASM_CODEBASE, (LPVOID *)&pwz, &cb, &dwFlag));
  582. IF_NULL_EXIT(pwz, E_INVALIDARG);
  583. IF_FAILED_EXIT(sRemoteUrl.TakeOwnership(pwz));
  584. #ifdef DEVMODE
  585. {
  586. DWORD *pdw = NULL;
  587. // is it devMode?
  588. IF_FAILED_EXIT(pDependAsm->Get(MAN_INFO_DEPENDENT_ASM_TYPE, (LPVOID *)&pdw, &cb, &dwFlag));
  589. IF_FALSE_EXIT(pdw != NULL, E_UNEXPECTED);
  590. if (*pdw == DEPENDENT_ASM_INSTALL_TYPE_DEVSYNC)
  591. _bIsDevMode = TRUE;
  592. SAFEDELETEARRAY(pdw);
  593. }
  594. #endif
  595. // Form local cache path from download url.
  596. IF_FAILED_EXIT(MakeTempManifestLocation(sRemoteUrl, sLocalFilePath));
  597. // Create new job if necessary.
  598. if (!*ppJob)
  599. {
  600. IF_FAILED_EXIT(_hr = CreateNewBITSJob(ppJob, sDisplayName));
  601. // add this job to reg.
  602. IF_FAILED_EXIT( _hr = AddJobToRegistry(sRemoteUrl._pwz, sLocalFilePath._pwz, *ppJob, 0));
  603. }
  604. // Submit the job.
  605. IF_FAILED_EXIT((*ppJob)->AddFile(sRemoteUrl._pwz, sLocalFilePath._pwz));
  606. exit:
  607. SAFERELEASE(pIdentity);
  608. SAFERELEASE(pDependAsm);
  609. return _hr;
  610. }
  611. // ---------------------------------------------------------------------------
  612. // EnqueueApplicationDependencies
  613. // ---------------------------------------------------------------------------
  614. HRESULT CAssemblyDownload::EnqueueApplicationDependencies(IAssemblyCacheImport *pCacheImport,
  615. CString &sCodebase, CString &sDisplayName, IBackgroundCopyJob **ppJob)
  616. {
  617. // App dependencies handled generically by component handler.
  618. return EnqueueComponentDependencies(pCacheImport, sCodebase, sDisplayName, TRUE, ppJob);
  619. }
  620. // ---------------------------------------------------------------------------
  621. // EnqueueComponentDependencies
  622. // ---------------------------------------------------------------------------
  623. HRESULT CAssemblyDownload::EnqueueComponentDependencies(IAssemblyCacheImport *pCacheImport,
  624. CString &sCodebase, CString &sDisplayName, BOOL fRecurse, IBackgroundCopyJob **ppJob)
  625. {
  626. DWORD n = 0, cb = 0, cc = 0, dwFlag = 0;
  627. LPWSTR pwz = NULL;
  628. IAssemblyIdentity *pIdentity = NULL;
  629. IAssemblyIdentity *pDepIdentity = NULL;
  630. IAssemblyManifestImport *pManifestImport = NULL;
  631. IAssemblyCacheImport *pMaxCachedImport = NULL;
  632. IAssemblyCacheEmit *pCacheEmit = NULL;
  633. IManifestInfo *pAssemblyFile = NULL;
  634. IManifestInfo *pDependAsm = NULL;
  635. // Obtain any patching info present in manifest.
  636. // This sets _pPatchingInfo on this object.
  637. if (fRecurse)
  638. IF_FAILED_EXIT(LookupPatchInfo(pCacheImport));
  639. // Obtain the ManifestImport interface.
  640. IF_FAILED_EXIT(pCacheImport->GetManifestImport(&pManifestImport));
  641. // Get the asm Id
  642. IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pIdentity));
  643. // Obtain the cache emit interface
  644. IF_FAILED_EXIT(pCacheImport->QueryInterface(IID_IAssemblyCacheEmit, (LPVOID*) &pCacheEmit));
  645. // Find max completed version, if any
  646. // Init newly created cache import with the highest completed version
  647. // else S_FALSE or E_* and pMaxCachedImport == NULL - no completed version
  648. IF_FAILED_EXIT(CreateAssemblyCacheImport(&pMaxCachedImport, pIdentity, CACHEIMP_CREATE_RETRIEVE_MAX));
  649. ///////////////////////////////////////////////////////////////////////////
  650. //
  651. // File enumeration loop
  652. //
  653. ///////////////////////////////////////////////////////////////////////////
  654. // Submit files directly into their target dirs.
  655. n = 0;
  656. while(1)
  657. {
  658. CString sFileName;
  659. CString sLocalFilePath;
  660. CString sRemoteUrl;
  661. BOOL bSkipFile = FALSE;
  662. _hr = pManifestImport->GetNextFile(n++, &pAssemblyFile);
  663. // BUGBUG: xml and clr manifest imports return different values at end of enum.
  664. if ((_hr == S_FALSE) || (_hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)))
  665. break;
  666. IF_FAILED_EXIT(_hr);
  667. // File name parsed from manifest.
  668. IF_FAILED_EXIT(pAssemblyFile->Get(MAN_INFO_ASM_FILE_NAME, (LPVOID*) &pwz, &cb, &dwFlag));
  669. IF_FAILED_EXIT(sFileName.TakeOwnership(pwz));
  670. // DemoHack------------------------------------------------------------------------------
  671. if (_pDlg)
  672. {
  673. CString sFindingFileMsg;
  674. IF_FAILED_EXIT(sFindingFileMsg.Assign(L"Finding Files: "));
  675. IF_FAILED_EXIT(sFindingFileMsg.Append(sFileName));
  676. _pDlg->UpdateDialog(_pDlg->_hwndDlg, sFindingFileMsg._pwz);
  677. }
  678. // DemoHack------------------------------------------------------------------------------
  679. // Check if file found in max comitted version.
  680. if (pMaxCachedImport)
  681. {
  682. LPWSTR pwzPath = NULL;
  683. IF_FAILED_EXIT(pMaxCachedImport->FindExistMatching(pAssemblyFile, &pwzPath));
  684. if ((_hr == S_OK))
  685. {
  686. // Copy from existing cached copy to the new location
  687. // (Non-manifest files)
  688. IF_FAILED_EXIT(pCacheEmit->CopyFile(pwzPath, sFileName._pwz, OTHERFILES));
  689. bSkipFile = TRUE;
  690. SAFEDELETEARRAY(pwzPath);
  691. }
  692. }
  693. // No previous file found; download.
  694. if (!bSkipFile)
  695. {
  696. // Form local file path...
  697. // Manifest cache directory
  698. IF_FAILED_EXIT(pCacheImport->GetManifestFileDir(&pwz, &cc));
  699. IF_FAILED_EXIT(sLocalFilePath.TakeOwnership(pwz, cc));
  700. // If patchinginfo was found, check if patch file
  701. // should be submitted. sLocalFilePath will be
  702. // updated in this case.
  703. if (_pPatchingInfo)
  704. IF_FAILED_EXIT(ResolveFile(sFileName, sLocalFilePath));
  705. // Form local file path by appending filename.
  706. IF_FAILED_EXIT(sLocalFilePath.Append(sFileName));
  707. IF_FAILED_EXIT(sLocalFilePath.PathNormalize());
  708. // Form remote name
  709. IF_FAILED_EXIT(sRemoteUrl.Assign(sCodebase)); // remote name of manifes
  710. IF_FAILED_EXIT(sRemoteUrl.RemoveLastElement()); // remove manifest file name
  711. IF_FAILED_EXIT(sRemoteUrl.Append(L"/")); // add separator
  712. IF_FAILED_EXIT(sRemoteUrl.Append(sFileName)); // add module file name
  713. // Create new job if necessary.
  714. if (!*ppJob)
  715. {
  716. IF_FAILED_EXIT(CreateNewBITSJob(ppJob, sDisplayName));
  717. DWORD cc = 0;
  718. LPWSTR pwz = NULL;
  719. // Form local file path...
  720. // Manifest cache directory
  721. IF_FAILED_EXIT(pCacheImport->GetManifestFileDir(&pwz, &cc));
  722. // add this job to reg.
  723. IF_FAILED_EXIT(AddJobToRegistry(sCodebase._pwz, pwz, *ppJob, 0));
  724. }
  725. // add the file to the job.
  726. IF_FAILED_EXIT((*ppJob)->AddFile(sRemoteUrl._pwz, sLocalFilePath._pwz));
  727. }
  728. SAFERELEASE(pAssemblyFile);
  729. }
  730. ///////////////////////////////////////////////////////////////////////////
  731. //
  732. // Dependent assembly enumeration loop
  733. //
  734. ///////////////////////////////////////////////////////////////////////////
  735. // Submit assembly manifests into staging area
  736. // Note - we should also get assembly codebase and
  737. // use this instead or adjunctly to display name.
  738. // As is, there is a problem if the ref is partial.
  739. n = 0;
  740. while (fRecurse)
  741. {
  742. CString sAssemblyName;
  743. CString sLocalFilePath;
  744. CString sRemoteUrl;
  745. _hr = pManifestImport->GetNextAssembly(n++, &pDependAsm);
  746. // BUGBUG: xml and clr manifest imports return different values at end of enum.
  747. if ((_hr == S_FALSE) || (_hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)))
  748. break;
  749. IF_FAILED_EXIT(_hr);
  750. // Form local name (in staging area)....
  751. IF_FAILED_EXIT(pDependAsm->Get(MAN_INFO_DEPENDENT_ASM_ID, (LPVOID *)&pDepIdentity, &cb, &dwFlag));
  752. BOOL bIsAvalon = FALSE;
  753. IF_FAILED_EXIT(IsAvalonAssembly(pDepIdentity, &bIsAvalon));
  754. #ifdef DEVMODE
  755. if (bIsAvalon && !_bIsDevMode) // download and reinstall anyway if devMode
  756. #else
  757. if (bIsAvalon)
  758. #endif
  759. {
  760. CString sCurrentAssemblyPath;
  761. IF_FAILED_EXIT(CAssemblyCache::GlobalCacheLookup(pDepIdentity, sCurrentAssemblyPath));
  762. if (_hr == S_OK)
  763. {
  764. // add to the list of assemblies to be add-ref-ed
  765. CGlobalCacheInstallEntry* pGACInstallEntry = new CGlobalCacheInstallEntry();
  766. IF_ALLOC_FAILED_EXIT(pGACInstallEntry);
  767. IF_FAILED_EXIT((pGACInstallEntry->_sCurrentAssemblyPath).Assign(sCurrentAssemblyPath));
  768. _ListGlobalCacheInstall.AddHead(pGACInstallEntry);
  769. SAFERELEASE(pDepIdentity);
  770. SAFERELEASE(pDependAsm);
  771. continue;
  772. }
  773. }
  774. // Get the identity name
  775. IF_FAILED_EXIT(pDepIdentity->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwz, &cc));
  776. IF_FAILED_EXIT(sAssemblyName.TakeOwnership(pwz, cc));
  777. // Get dependent asm codebase if any. NOTE - this codebase
  778. // is relative to the appbase
  779. IF_FAILED_EXIT(pDependAsm->Get(MAN_INFO_DEPENDENT_ASM_CODEBASE, (LPVOID *)&pwz, &cb, &dwFlag));
  780. IF_NULL_EXIT(pwz, E_INVALIDARG);
  781. IF_FAILED_EXIT(sRemoteUrl.Assign(sCodebase));
  782. IF_FAILED_EXIT(sRemoteUrl.RemoveLastElement()); // remove manifest file name
  783. IF_FAILED_EXIT(sRemoteUrl.Append(L"/")); // add separator
  784. IF_FAILED_EXIT(sRemoteUrl.Append(pwz));
  785. // Form local cache path from identity name.
  786. IF_FAILED_EXIT(MakeTempManifestLocation(sRemoteUrl, sLocalFilePath));
  787. // Create new job if necessary
  788. if (!*ppJob)
  789. {
  790. IF_FAILED_EXIT(CreateNewBITSJob(ppJob, sDisplayName));
  791. DWORD cc = 0;
  792. LPWSTR pwz = NULL;
  793. // Form local file path...
  794. // Manifest cache directory
  795. IF_FAILED_EXIT(pCacheImport->GetManifestFileDir(&pwz, &cc));
  796. // add this job to reg.
  797. IF_FAILED_EXIT(AddJobToRegistry(sCodebase._pwz, pwz, *ppJob, 0));
  798. }
  799. // Add file to job.
  800. IF_FAILED_EXIT((*ppJob)->AddFile(sRemoteUrl._pwz, sLocalFilePath._pwz));
  801. SAFERELEASE(pDepIdentity);
  802. SAFERELEASE(pDependAsm);
  803. }
  804. _hr = S_OK;
  805. exit:
  806. SAFERELEASE(pIdentity);
  807. SAFERELEASE(pManifestImport);
  808. SAFERELEASE(pCacheEmit);
  809. SAFERELEASE(pMaxCachedImport);
  810. SAFERELEASE(pDepIdentity);
  811. SAFERELEASE(pDependAsm);
  812. return _hr;
  813. }
  814. // ---------------------------------------------------------------------------
  815. // LookupPatchInfo
  816. // ---------------------------------------------------------------------------
  817. HRESULT CAssemblyDownload::LookupPatchInfo(IAssemblyCacheImport *pCacheImport)
  818. {
  819. IManifestInfo *pPatchingInfo = NULL;
  820. CAssemblyManifestImport *pCManifestImport = NULL;
  821. IAssemblyManifestImport *pManifestImport = NULL;
  822. IAssemblyIdentity *pIdentity = NULL;
  823. IXMLDOMDocument2 *pXMLDoc = NULL;
  824. // Get the manifest import.
  825. IF_FAILED_EXIT(pCacheImport->GetManifestImport(&pManifestImport));
  826. // Get the asm Id
  827. IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pIdentity));
  828. // Cast IManifestImport to CManifestImport so we can grab the XMLDocument
  829. pCManifestImport = static_cast<CAssemblyManifestImport*> (pManifestImport);
  830. IF_NULL_EXIT(pCManifestImport, E_NOINTERFACE);
  831. pManifestImport->AddRef();
  832. // Retrieve the top-level xml dom document
  833. IF_FAILED_EXIT(pCManifestImport->GetXMLDoc (&pXMLDoc));
  834. IF_FALSE_EXIT((_hr == S_OK), E_INVALIDARG);
  835. //Get patching data if any is available
  836. IF_FAILED_EXIT(CPatchingUtil::CreatePatchingInfo(pXMLDoc, pCacheImport, &pPatchingInfo));
  837. // BUGBUG: CreatePatchingInfo appears to always return S_FALSE, so how did this work?
  838. if (_hr == S_OK)
  839. {
  840. _pPatchingInfo = pPatchingInfo;
  841. _pPatchingInfo->AddRef();
  842. }
  843. exit:
  844. SAFERELEASE(pPatchingInfo);
  845. SAFERELEASE(pXMLDoc);
  846. SAFERELEASE(pCManifestImport);
  847. SAFERELEASE(pManifestImport);
  848. SAFERELEASE(pIdentity);
  849. return _hr;
  850. }
  851. // ---------------------------------------------------------------------------
  852. //ApplyPatchFile
  853. // ---------------------------------------------------------------------------
  854. HRESULT CAssemblyDownload::ApplyPatchFile (LPWSTR pwzPatchFilePath)
  855. {
  856. int i = 0;
  857. LPWSTR pwzBuf;
  858. DWORD ccBuf, cbBuf, dwFlag;
  859. CString sPatchLocalName;
  860. CString sPatchDisplayName;
  861. CString sManifestDir, sPatchManifestDir;
  862. CString sSourcePath, sTargetPath, sPatchPath;
  863. CString sSourceFile, sTargetFile;
  864. IManifestInfo *pPatchFileInfo=NULL;
  865. IPatchingUtil *pPatchingUtil=NULL;
  866. IAssemblyIdentity *pSourceAssemblyId = NULL;
  867. IF_NULL_EXIT(_pPatchingInfo, E_INVALIDARG);
  868. // get patchingutil from patchInfo
  869. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_PATCH_UTIL, (LPVOID *)&pPatchingUtil, &cbBuf, &dwFlag));
  870. // get the manifest Directory
  871. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_INSTALL_DIR, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  872. IF_FAILED_EXIT(sManifestDir.TakeOwnership (pwzBuf));
  873. // get the source assembly directory
  874. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_DIR, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  875. IF_FAILED_EXIT(sPatchManifestDir.TakeOwnership (pwzBuf));
  876. // get SourceAssembly Id from patchInfo
  877. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_ID, (LPVOID *)&pSourceAssemblyId, &cbBuf, &dwFlag));
  878. // Get DisplayName of the Source Assembly
  879. IF_FAILED_EXIT(pSourceAssemblyId->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &ccBuf));
  880. IF_FAILED_EXIT(sPatchDisplayName.TakeOwnership(pwzBuf, ccBuf));
  881. //Parse out the local file path from the full file path of the patch file
  882. pwzBuf= StrStr(pwzPatchFilePath, sPatchDisplayName._pwz);
  883. IF_NULL_EXIT(pwzBuf, E_FAIL);
  884. pwzBuf = StrChr(pwzBuf, L'\\');
  885. IF_NULL_EXIT(pwzBuf, E_FAIL);
  886. pwzBuf++;
  887. IF_FAILED_EXIT(sPatchLocalName.Assign(pwzBuf));
  888. IF_FAILED_EXIT(pPatchingUtil->MatchPatch(sPatchLocalName._pwz, &pPatchFileInfo));
  889. IF_FAILED_EXIT(pPatchFileInfo->Get(MAN_INFO_PATCH_INFO_SOURCE, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  890. IF_FAILED_EXIT(sSourceFile.TakeOwnership(pwzBuf));
  891. IF_FAILED_EXIT(pPatchFileInfo->Get(MAN_INFO_PATCH_INFO_TARGET, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  892. IF_FAILED_EXIT(sTargetFile.TakeOwnership(pwzBuf));
  893. IF_FAILED_EXIT(sSourcePath.Append(sPatchManifestDir));
  894. IF_FAILED_EXIT(sSourcePath.Append(sSourceFile));
  895. // set up Target path
  896. IF_FAILED_EXIT(sTargetPath.Assign(sManifestDir));
  897. IF_FAILED_EXIT(sTargetPath.Append(sTargetFile));
  898. // set up Patch path
  899. IF_FAILED_EXIT(sPatchPath.Assign(pwzPatchFilePath));
  900. //Apply patchfile to sSource (grab from patch directory) and copy to path specified by sTarget
  901. IF_WIN32_FALSE_EXIT(ApplyPatchToFile((LPCWSTR)sPatchPath._pwz, (LPCWSTR)sSourcePath._pwz, (LPCWSTR)sTargetPath._pwz, 0));
  902. exit:
  903. SAFERELEASE(pPatchFileInfo);
  904. SAFERELEASE(pSourceAssemblyId);
  905. SAFERELEASE(pPatchingUtil);
  906. return _hr;
  907. }
  908. // ---------------------------------------------------------------------------
  909. // ResolveFile
  910. // ---------------------------------------------------------------------------
  911. HRESULT CAssemblyDownload::ResolveFile(CString &sFileName, CString &sLocalFilePath)
  912. {
  913. LPWSTR pwzBuf;
  914. DWORD cbBuf, dwFlag;
  915. IPatchingUtil *pPatchingUtil=NULL;
  916. IManifestInfo *pPatchFileInfo=NULL;
  917. CString sPatchFileName;
  918. CString sTempDirectoryPath;
  919. IF_NULL_EXIT(_pPatchingInfo, E_INVALIDARG);
  920. //grab the patchingUtil from the _pPatchingInfo
  921. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_PATCH_UTIL, (LPVOID *)&pPatchingUtil, &cbBuf, &dwFlag));
  922. //Check to see if the file referenced by sFileName has an available patch
  923. // if it does, download the patch by overriding sFileName with the patchFile name
  924. // and override the sLocalFilePath with the temporary directory to store the patch file
  925. IF_FAILED_EXIT(pPatchingUtil->MatchTarget(sFileName._pwz, &pPatchFileInfo));
  926. // BUGBUG- want to exit but not break out in debugger here.
  927. IF_FALSE_EXIT((_hr == S_OK), S_FALSE);
  928. IF_FAILED_EXIT(pPatchFileInfo->Get(MAN_INFO_PATCH_INFO_PATCH, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  929. IF_FAILED_EXIT(sPatchFileName.TakeOwnership(pwzBuf));
  930. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_TEMP_DIR, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  931. IF_FAILED_EXIT(sTempDirectoryPath.TakeOwnership(pwzBuf));
  932. IF_FAILED_EXIT(sFileName.Assign (sPatchFileName));
  933. // Assign the patch directory to local file path
  934. IF_FAILED_EXIT( sLocalFilePath.Assign(sTempDirectoryPath));
  935. IF_FAILED_EXIT(::CreateDirectoryHierarchy(sLocalFilePath._pwz, sFileName._pwz));
  936. exit:
  937. SAFERELEASE(pPatchFileInfo);
  938. SAFERELEASE(pPatchingUtil);
  939. return _hr;
  940. }
  941. // ---------------------------------------------------------------------------
  942. // CleanUpPatchDir
  943. // ---------------------------------------------------------------------------
  944. HRESULT CAssemblyDownload::CleanUpPatchDir()
  945. {
  946. LPWSTR pwz = NULL;
  947. DWORD cb = 0, dwFlag = 0;
  948. CString sTempPatchDirectory;
  949. IF_NULL_EXIT(_pPatchingInfo, E_INVALIDARG);
  950. IF_FAILED_EXIT(_pPatchingInfo->Get(MAN_INFO_SOURCE_ASM_TEMP_DIR, (LPVOID *)&pwz, &cb, &dwFlag));
  951. IF_NULL_EXIT(pwz, E_INVALIDARG);
  952. IF_FAILED_EXIT(sTempPatchDirectory.TakeOwnership(pwz));
  953. IF_FAILED_EXIT(sTempPatchDirectory.RemoveLastElement());
  954. IF_FAILED_EXIT(sTempPatchDirectory.RemoveLastElement());
  955. IF_FAILED_EXIT(RemoveDirectoryAndChildren(sTempPatchDirectory._pwz));
  956. exit:
  957. return _hr;
  958. }
  959. // ---------------------------------------------------------------------------
  960. // CreateNewBITSJob
  961. // ---------------------------------------------------------------------------
  962. HRESULT CAssemblyDownload::CreateNewBITSJob(IBackgroundCopyJob **ppJob,
  963. CString &sDisplayName)
  964. {
  965. GUID guid = {0};
  966. // Connect to BITS if not already connected.
  967. IF_FAILED_EXIT(InitBITS());
  968. // Create the job.
  969. IF_FAILED_EXIT(g_pBITSManager->CreateJob(sDisplayName._pwz, BG_JOB_TYPE_DOWNLOAD, &guid, ppJob));
  970. // Set job in dialog object.
  971. // Note - potential race condition if job methods are called before the
  972. // dialog references it since we can immediately begin to get
  973. // callbacks
  974. if (_pDlg)
  975. _pDlg->SetJobObject(*ppJob);
  976. // Construct and pass in callback object.
  977. CBitsCallback *pBCB = new CBitsCallback(this);
  978. IF_ALLOC_FAILED_EXIT(pBCB);
  979. IF_FAILED_EXIT((*ppJob)->SetNotifyInterface(static_cast<IBackgroundCopyCallback*> (pBCB)));
  980. pBCB->Release();
  981. // Set job config info.
  982. IF_FAILED_EXIT((*ppJob)->SetNotifyFlags(BG_NOTIFY_JOB_MODIFICATION
  983. | BG_NOTIFY_JOB_TRANSFERRED
  984. | BG_NOTIFY_JOB_ERROR));
  985. //The default priority level for a job is BG_JOB_PRIORITY_NORMAL (background).
  986. if (_pDlg)
  987. IF_FAILED_EXIT((*ppJob)->SetPriority(BG_JOB_PRIORITY_FOREGROUND));
  988. SetJobObject(*ppJob);
  989. exit:
  990. return _hr;
  991. }
  992. // ---------------------------------------------------------------------------
  993. // MakeTempManifestLocation
  994. // ALL manifests are first downloaded to a location generated in this method.
  995. // ---------------------------------------------------------------------------
  996. HRESULT CAssemblyDownload::MakeTempManifestLocation(CString &sRemoteUrlName,
  997. CString& sManifestFilePath)
  998. {
  999. WCHAR wzRandom[8+1]={0};
  1000. CString sRelativePath;
  1001. CString sTempDirPath;
  1002. /* C:\Documents and Settings\<user>\Local Settings\My Programs\__temp__\__manifests__\ */
  1003. IF_FAILED_EXIT(CAssemblyCache::GetCacheRootDir(sManifestFilePath, CAssemblyCache::Manifests));
  1004. // Create a randomized directory name.
  1005. // sRelativePath is simply the manifest file name
  1006. // in the case that no appbase is available (Subscription manifest case).
  1007. // \_temp__\__manifests__\xyz123\subscription.manifest
  1008. // if (!_sAppBase._pwz) // ******* Relative path Dir is to be done in Dest dir and not in temp-man-location
  1009. IF_FAILED_EXIT(sRemoteUrlName.LastElement(sRelativePath));
  1010. // Otherwise we extract the relative path based on the appbase.
  1011. // This is important because sManifestFilePath is persisted in the BITS
  1012. // job and the relative path is extracted from this and used for commit
  1013. // to cache.
  1014. // \_temp__\__manifests__\xyz123\foo.manifest
  1015. // \_temp__\__manifests__\xyz123\bar\bar.dll
  1016. // ^^^^^^^
  1017. /*
  1018. else
  1019. {
  1020. // http://foo/appbase/
  1021. // http://foo/appbase/bar/bar.dll
  1022. // ^^^^^^^
  1023. IF_FAILED_EXIT(sRemoteUrlName.StartsWith(_sAppBase._pwz));
  1024. IF_FALSE_EXIT((_hr==S_OK), E_INVALIDARG);
  1025. pwzBuf = sRemoteUrlName._pwz + _sAppBase._cc - 1;
  1026. IF_FAILED_EXIT(sRelativePath.Assign(pwzBuf));
  1027. }
  1028. */
  1029. IF_FAILED_EXIT(CreateRandomDir(sManifestFilePath._pwz, wzRandom, 8));
  1030. IF_FAILED_EXIT(sManifestFilePath.Append(wzRandom));
  1031. IF_FAILED_EXIT(sManifestFilePath.Append(L"\\"));
  1032. IF_FAILED_EXIT(sManifestFilePath.Append(sRelativePath));
  1033. IF_FAILED_EXIT(sManifestFilePath.PathNormalize());
  1034. IF_FAILED_EXIT(::CreateDirectoryHierarchy(NULL, sManifestFilePath._pwz));
  1035. exit:
  1036. return _hr;
  1037. }
  1038. // ---------------------------------------------------------------------------
  1039. // IsManifestFile
  1040. //
  1041. // This is somewhat hacky - we rely on the local target path
  1042. // ---------------------------------------------------------------------------
  1043. HRESULT CAssemblyDownload::IsManifestFile(IBackgroundCopyFile *pFile, BOOL *pbIsManifestFile)
  1044. {
  1045. LPWSTR pwz = NULL;
  1046. CString sManifestStagingDir;
  1047. CString sLocalName(CString::COM_Allocator);
  1048. // Get local manifest file name.
  1049. IF_FAILED_EXIT(pFile->GetLocalName(&pwz));
  1050. IF_FAILED_EXIT(sLocalName.TakeOwnership(pwz));
  1051. IF_FAILED_EXIT(CAssemblyCache::GetCacheRootDir(sManifestStagingDir, CAssemblyCache::Manifests));
  1052. IF_FAILED_EXIT(sLocalName.StartsWith(sManifestStagingDir._pwz));
  1053. if (_hr == S_OK)
  1054. *pbIsManifestFile = TRUE;
  1055. else if (_hr == S_FALSE)
  1056. *pbIsManifestFile = FALSE;
  1057. exit:
  1058. return _hr;
  1059. }
  1060. // ---------------------------------------------------------------------------
  1061. // InstallGlobalAssemblies
  1062. // ---------------------------------------------------------------------------
  1063. HRESULT CAssemblyDownload::InstallGlobalAssemblies()
  1064. {
  1065. // Needed for template list.
  1066. LISTNODE pos;
  1067. CGlobalCacheInstallEntry *pEntry = NULL;
  1068. LPWSTR pwz = NULL;
  1069. DWORD cc = 0;
  1070. // Walk list; install each assembly.
  1071. pos = _ListGlobalCacheInstall.GetHeadPosition();
  1072. while (pos && (pEntry = _ListGlobalCacheInstall.GetNext(pos)))
  1073. {
  1074. CString sManifestFilePath;
  1075. // Install/addref each assembly. If the ICacheImport is available, it means
  1076. // that install take place from appbase, else addref using current GAC assembly path.
  1077. IF_FAILED_EXIT(CAssemblyCache::GlobalCacheInstall(pEntry->_pICacheImport,
  1078. pEntry->_sCurrentAssemblyPath, _sAppDisplayName));
  1079. // Get the assembly path if under the appbase.
  1080. if (pEntry->_pICacheImport != NULL)
  1081. {
  1082. IF_FAILED_EXIT(pEntry->_pICacheImport->GetManifestFilePath(&pwz, &cc));
  1083. IF_FAILED_EXIT(sManifestFilePath.TakeOwnership(pwz));
  1084. }
  1085. // this releases interface pointers
  1086. delete pEntry;
  1087. // we should call delete only after releasing interfaces....
  1088. if(sManifestFilePath._cc > 1)
  1089. IF_FAILED_EXIT(CAssemblyCache::DeleteAssemblyAndModules(sManifestFilePath._pwz));
  1090. }
  1091. exit:
  1092. // Free all the list nodes.
  1093. _ListGlobalCacheInstall.RemoveAll();
  1094. return _hr;
  1095. }
  1096. // ---------------------------------------------------------------------------
  1097. // SetJobObject
  1098. // ---------------------------------------------------------------------------
  1099. VOID CAssemblyDownload::SetJobObject(IBackgroundCopyJob *pJob)
  1100. {
  1101. SAFERELEASE(_pJob);
  1102. if (pJob)
  1103. {
  1104. _pJob = pJob;
  1105. _pJob->AddRef();
  1106. }
  1107. }
  1108. // ---------------------------------------------------------------------------
  1109. // FinishDownload
  1110. // ---------------------------------------------------------------------------
  1111. HRESULT CAssemblyDownload::FinishDownload()
  1112. {
  1113. KillTimer(_pDlg->_hwndDlg, 0);
  1114. DestroyWindow(_pDlg->_hwndDlg);
  1115. return S_OK;
  1116. }
  1117. // ---------------------------------------------------------------------------
  1118. // SignalAbort
  1119. // ---------------------------------------------------------------------------
  1120. HRESULT CAssemblyDownload::SignalAbort()
  1121. {
  1122. InterlockedIncrement((LONG*) &_bAbort);
  1123. return S_OK;
  1124. }
  1125. // ---------------------------------------------------------------------------
  1126. // DoEvilAvalonRegistrationHack
  1127. // ---------------------------------------------------------------------------
  1128. HRESULT CAssemblyDownload::DoEvilAvalonRegistrationHack()
  1129. {
  1130. HINSTANCE hInst = 0;
  1131. INT iCompare = 0;
  1132. LPWSTR pwz = NULL;
  1133. DWORD cc = 0;
  1134. IAssemblyManifestImport *pManifestImport = NULL;
  1135. IAssemblyIdentity *pAppIdentity = NULL;
  1136. CString sAppName, sBatchFilePath, sDisplayName, sAppDir;
  1137. if (!_pRootEmit)
  1138. goto exit;
  1139. IF_FAILED_EXIT(_pRootEmit->GetManifestImport(&pManifestImport));
  1140. IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pAppIdentity));
  1141. IF_FAILED_EXIT(pAppIdentity->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwz, &cc));
  1142. IF_FAILED_EXIT(sAppName.TakeOwnership(pwz));
  1143. iCompare = CompareString(LOCALE_USER_DEFAULT, 0,
  1144. sAppName._pwz, -1, L"Microsoft.Avalon.AvPad", -1);
  1145. IF_WIN32_FALSE_EXIT(iCompare);
  1146. if (iCompare == CSTR_EQUAL)
  1147. {
  1148. IF_FAILED_EXIT(pAppIdentity->GetDisplayName(0, &pwz, &cc));
  1149. IF_FAILED_EXIT(sDisplayName.TakeOwnership(pwz));
  1150. IF_FAILED_EXIT(CAssemblyCache::GetCacheRootDir(sAppDir, CAssemblyCache::Base));
  1151. IF_FAILED_EXIT(sAppDir.Append(sDisplayName));
  1152. IF_FAILED_EXIT(sBatchFilePath.Assign(sAppDir));
  1153. IF_FAILED_EXIT(sBatchFilePath.Append(L"\\doi.bat"));
  1154. hInst = ShellExecute(NULL, L"open", sBatchFilePath._pwz, NULL, sAppDir._pwz, SW_HIDE);
  1155. if ((DWORD_PTR) hInst <= 32)
  1156. _hr = HRESULT_FROM_WIN32((DWORD_PTR) hInst);
  1157. else
  1158. _hr = S_OK;
  1159. }
  1160. exit:
  1161. SAFERELEASE(pManifestImport);
  1162. SAFERELEASE(pAppIdentity);
  1163. return _hr;
  1164. }
  1165. // ---------------------------------------------------------------------------
  1166. // IsAvalonAssembly
  1167. // ---------------------------------------------------------------------------
  1168. HRESULT CAssemblyDownload::IsAvalonAssembly(IAssemblyIdentity *pId, BOOL *pbIsAvalon)
  1169. {
  1170. INT iCompare = 0;
  1171. LPWSTR pwz = NULL;
  1172. DWORD cc = 0;
  1173. CString sPublicKeyToken;
  1174. // System Public key tokens;
  1175. // One of these is the ECMA key, I can't remember which.
  1176. const LPWSTR wzNDPToken1 = L"b03f5f7f11d50a3a";
  1177. const LPWSTR wzNDPToken2 = L"b77a5c561934e089";
  1178. // Trusted avalon public key token.
  1179. const LPWSTR wzAvalonToken = L"a29c01bbd4e39ac5";
  1180. LPWSTR wzTokens[] = {wzNDPToken1, wzNDPToken2, wzAvalonToken};
  1181. *pbIsAvalon = FALSE;
  1182. // Get the public key token in string form.
  1183. // bugbuG: COULD USE IF_TRUE_EXIT MACRO.
  1184. _hr = pId->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_PUBLIC_KEY_TOKEN, &pwz, &cc);
  1185. if (_hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
  1186. {
  1187. _hr = S_FALSE;
  1188. goto exit;
  1189. }
  1190. IF_FAILED_EXIT(_hr);
  1191. IF_FAILED_EXIT(sPublicKeyToken.TakeOwnership(pwz));
  1192. // Check for trusted assembly
  1193. _hr = S_FALSE;
  1194. for (int i = 0; i < ( sizeof(wzTokens) / sizeof(wzTokens[0]) ); i++)
  1195. {
  1196. iCompare = CompareString(LOCALE_USER_DEFAULT, 0,
  1197. (LPCWSTR) wzTokens[i], -1, sPublicKeyToken._pwz, -1);
  1198. IF_WIN32_FALSE_EXIT(iCompare);
  1199. if (iCompare == CSTR_EQUAL)
  1200. {
  1201. _hr = S_OK;
  1202. *pbIsAvalon = TRUE;
  1203. break;
  1204. }
  1205. }
  1206. exit:
  1207. return _hr;
  1208. }
  1209. // ---------------------------------------------------------------------------
  1210. // InitBits
  1211. // BUGBUG: not thread safe.
  1212. // ---------------------------------------------------------------------------
  1213. HRESULT CAssemblyDownload::InitBITS()
  1214. {
  1215. HRESULT hr = S_OK;
  1216. MAKE_ERROR_MACROS_STATIC(hr);
  1217. // Connect to BITS if not already connected.
  1218. // BUGBUG - possibly leaking ptr if race condition.
  1219. if (!g_pBITSManager)
  1220. {
  1221. IF_FAILED_EXIT(CoCreateInstance(CLSID_BackgroundCopyManager, NULL, CLSCTX_LOCAL_SERVER,
  1222. IID_IBackgroundCopyManager, (void**) &g_pBITSManager));
  1223. }
  1224. exit:
  1225. return hr;
  1226. }
  1227. HRESULT CAssemblyDownload::GetBITSErrorMsg(IBackgroundCopyError *pError, CString &sMessage)
  1228. {
  1229. HRESULT hrBITSError = S_OK;
  1230. HRESULT hr = S_OK;
  1231. MAKE_ERROR_MACROS_STATIC(hr);
  1232. LPWSTR pwz = NULL;
  1233. CString sDescription(CString::COM_Allocator);
  1234. CString sContext(CString::COM_Allocator);
  1235. CString sRemoteName(CString::COM_Allocator);
  1236. CString sLocalName(CString::COM_Allocator);
  1237. IBackgroundCopyFile *pFile = NULL;
  1238. BG_ERROR_CONTEXT eCtx;
  1239. // Get the BITS error.
  1240. IF_FAILED_EXIT(pError->GetError(&eCtx, &hrBITSError));
  1241. // Get the error description
  1242. IF_FAILED_EXIT(pError->GetErrorDescription(
  1243. LANGIDFROMLCID( GetThreadLocale() ),
  1244. &pwz));
  1245. IF_FAILED_EXIT(sDescription.TakeOwnership(pwz));
  1246. // Get the error context
  1247. IF_FAILED_EXIT(pError->GetErrorContextDescription(
  1248. LANGIDFROMLCID( GetThreadLocale() ),
  1249. &pwz));
  1250. IF_FAILED_EXIT(sContext.TakeOwnership(pwz));
  1251. // Form UI message.
  1252. IF_FAILED_EXIT(sMessage.Assign(sDescription));
  1253. IF_FAILED_EXIT(sMessage.Append(sContext));
  1254. // If error due to remote or local file, indicate this in message.
  1255. if ((BG_ERROR_CONTEXT_LOCAL_FILE == eCtx) || (BG_ERROR_CONTEXT_REMOTE_FILE == eCtx))
  1256. {
  1257. IF_FAILED_EXIT(pError->GetFile(&pFile));
  1258. IF_FAILED_EXIT(pFile->GetRemoteName(&pwz));
  1259. IF_FAILED_EXIT(sRemoteName.TakeOwnership(pwz));
  1260. IF_FAILED_EXIT(pFile->GetLocalName(&pwz));
  1261. IF_FAILED_EXIT(sLocalName.TakeOwnership(pwz));
  1262. IF_FAILED_EXIT(sMessage.Append(L"\r\nURL: "));
  1263. IF_FAILED_EXIT(sMessage.Append(sRemoteName));
  1264. IF_FAILED_EXIT(sMessage.Append(L"\r\n\r\nFile: "));
  1265. IF_FAILED_EXIT(sMessage.Append(sLocalName));
  1266. }
  1267. exit :
  1268. SAFERELEASE(pFile);
  1269. return hr;
  1270. }
  1271. // ---------------------------------------------------------------------------
  1272. // CleanUpTempFilesOnError
  1273. // ---------------------------------------------------------------------------
  1274. HRESULT CAssemblyDownload::CleanUpTempFilesOnError(IBackgroundCopyJob *pJob)
  1275. {
  1276. // Return codes in this function don't affect
  1277. // last error (this->_hr).
  1278. HRESULT hr = S_OK;
  1279. MAKE_ERROR_MACROS_STATIC(hr);
  1280. DWORD nCount = 0;
  1281. LPWSTR pwz=NULL;
  1282. IEnumBackgroundCopyFiles *pEnumFiles = NULL;
  1283. IBackgroundCopyFile *pFile = NULL;
  1284. CString sLocalName(CString::COM_Allocator);
  1285. // Get the file enumerator.
  1286. IF_FAILED_EXIT(pJob->EnumFiles(&pEnumFiles));
  1287. IF_FAILED_EXIT(pEnumFiles->GetCount(&nCount));
  1288. // Enumerate the files in the job.
  1289. for (DWORD i = 0; i < nCount; i++)
  1290. {
  1291. IF_FAILED_EXIT(pEnumFiles->Next(1, &pFile, NULL));
  1292. // Get local file name.
  1293. IF_FAILED_EXIT(pFile->GetLocalName(&pwz));
  1294. IF_FAILED_EXIT(sLocalName.TakeOwnership(pwz)); pwz = NULL;
  1295. IF_FAILED_EXIT(sLocalName.RemoveLastElement());
  1296. IF_FAILED_EXIT(RemoveDirectoryAndChildren(sLocalName._pwz));
  1297. SAFERELEASE(pFile);
  1298. }
  1299. exit:
  1300. SAFERELEASE(pEnumFiles);
  1301. SAFERELEASE(pFile);
  1302. if(pwz)
  1303. CoTaskMemFree(pwz);
  1304. return hr;
  1305. }
  1306. // ---------------------------------------------------------------------------
  1307. // HandleError
  1308. // ---------------------------------------------------------------------------
  1309. HRESULT CAssemblyDownload::HandleError(IBackgroundCopyError *pError, IBackgroundCopyJob *pJob)
  1310. {
  1311. // Return codes in this function don't affect
  1312. // last error (this->_hr).
  1313. HRESULT hr = S_OK;
  1314. MAKE_ERROR_MACROS_STATIC(hr);
  1315. CString sMessage(CString::COM_Allocator);
  1316. // HandleError can be called multiple times on different threads
  1317. // but error is handled only once per lifetime of the object.
  1318. if (!(InterlockedIncrement((LONG*) &_bErrorHandled) == 1))
  1319. goto exit;
  1320. SetErrorCode(STG_E_TERMINATED);
  1321. DEBUGOUT1(_pDbgLog, 1, L" LOG: hr = %x in HandleError()", this->_hr);
  1322. // If an IBackgroundCopyError ptr is provided.
  1323. if ( pError)
  1324. {
  1325. IF_FAILED_EXIT(GetBITSErrorMsg(pError, sMessage));
  1326. DEBUGOUT(_pDbgLog, 1, L" LOG: BITS error msg follows. ");
  1327. DEBUGOUT1(_pDbgLog, 0, L" ERR: %s \n", sMessage._pwz);
  1328. }
  1329. if(_sAppBase._pwz)
  1330. DEBUGOUT1(_pDbgLog, 1, L" LOG: AppBase = %s ", _sAppBase._pwz);
  1331. if(_sAppDisplayName._pwz)
  1332. DEBUGOUT1(_pDbgLog, 1, L" LOG: DisplayName = %s ", _sAppDisplayName._pwz);
  1333. if (_pJob)
  1334. {
  1335. // Cancel job.
  1336. IF_FAILED_EXIT(_pJob->Cancel());
  1337. // Cleanup registry state associated with job.
  1338. IF_FAILED_EXIT(RemoveJobFromRegistry(_pJob, NULL, SHREGDEL_HKCU, RJFR_DELETE_FILES));
  1339. // Clean-up temp files from the job
  1340. CleanUpTempFilesOnError(_pJob);
  1341. SetJobObject(NULL);
  1342. }
  1343. else if (pJob)
  1344. {
  1345. // Clean-up for specified job, only if _pJob == NULL, only applies for JobTransferred case
  1346. CleanUpTempFilesOnError(pJob);
  1347. }
  1348. // Notify bindsink
  1349. if (_pBindSink)
  1350. {
  1351. if (_bAbort || (_hr == E_ABORT))
  1352. _pBindSink->OnProgress(ASM_NOTIFICATION_ABORT, _hr, NULL, 0, 0, NULL);
  1353. else
  1354. _pBindSink->OnProgress(ASM_NOTIFICATION_ERROR, _hr, NULL, 0, 0, NULL);
  1355. // Ensure this is last notification bindsink receives resulting from
  1356. // subsequent JobModified notifications.
  1357. // DO NOT free the bindsink here.
  1358. _pBindSink = NULL;
  1359. }
  1360. // Terminate UI.
  1361. if (_pDlg)
  1362. PostMessage(_pDlg->_hwndDlg, WM_FINISH_DOWNLOAD, 0, 0);
  1363. exit:
  1364. // Return error which generated handling.
  1365. // DownloadManifestAndDependencies will return this.
  1366. return _hr;
  1367. }
  1368. HRESULT CAssemblyDownload::SetErrorCode(HRESULT dwHr)
  1369. {
  1370. BOOL bSetError = FALSE;
  1371. ::EnterCriticalSection(&_cs);
  1372. if(SUCCEEDED(_hrError))
  1373. {
  1374. _hrError = dwHr;
  1375. bSetError = TRUE;
  1376. }
  1377. ::LeaveCriticalSection(&_cs);
  1378. if(!bSetError)
  1379. {
  1380. // We couldn't set error code atleast write some log.
  1381. DEBUGOUT1(_pDbgLog, 1, L" LOG : Could not set error code hr = %x ", dwHr);
  1382. }
  1383. return S_OK;
  1384. }
  1385. // IBackgroundCopyCallback methods
  1386. // ---------------------------------------------------------------------------
  1387. // JobTransferred
  1388. // ---------------------------------------------------------------------------
  1389. HRESULT CAssemblyDownload::JobTransferred(IBackgroundCopyJob *pJob)
  1390. {
  1391. ASSERT(pJob == _pJob);
  1392. // Serialize all calls to object.
  1393. ::EnterCriticalSection(&_cs);
  1394. // Check the abort flag first.
  1395. IF_TRUE_EXIT(_bAbort, E_ABORT);
  1396. // Job is complete; process results.
  1397. IF_FAILED_EXIT(DoCacheUpdate(pJob));
  1398. exit:
  1399. // Handle any error.
  1400. if (FAILED(_hr))
  1401. HandleError(NULL, pJob); // pJob only applies after _pJob is set to NULL in DoCacheUpdate()
  1402. ::LeaveCriticalSection(&_cs);
  1403. // Always return success to BITS.
  1404. return S_OK;
  1405. }
  1406. // ---------------------------------------------------------------------------
  1407. // JobError
  1408. // ---------------------------------------------------------------------------
  1409. HRESULT CAssemblyDownload::JobError(IBackgroundCopyJob *pJob, IBackgroundCopyError *pError)
  1410. {
  1411. // Serialize all calls to object.
  1412. ::EnterCriticalSection(&_cs);
  1413. // Handle any error. Presumeably, if this is concurrent with an abort,
  1414. // the error handling code can do the right thing.
  1415. HandleError(pError, NULL);
  1416. ::LeaveCriticalSection(&_cs);
  1417. // Always return success to BITS.
  1418. return S_OK;
  1419. }
  1420. // ---------------------------------------------------------------------------
  1421. // JobModification
  1422. // ---------------------------------------------------------------------------
  1423. HRESULT CAssemblyDownload::JobModification(IBackgroundCopyJob *pJob, DWORD dwReserved)
  1424. {
  1425. ::EnterCriticalSection(&_cs);
  1426. IBackgroundCopyError *pError = NULL;
  1427. // Check the abort flag first.
  1428. IF_TRUE_EXIT(_bAbort, E_ABORT);
  1429. // JobModification can still be called a few times after abort.
  1430. IF_TRUE_EXIT(_hr == E_ABORT, _hr);
  1431. if (_pDlg)
  1432. IF_FAILED_EXIT(_pDlg->HandleUpdate());
  1433. BG_JOB_STATE state;
  1434. IF_FAILED_EXIT(pJob->GetState( &state ));
  1435. if(state == BG_JOB_STATE_TRANSIENT_ERROR)
  1436. {
  1437. if(pJob->GetError(&pError) == S_OK)
  1438. {
  1439. if(_pDlg)
  1440. {
  1441. HandleError(pError, NULL);
  1442. }
  1443. else
  1444. {
  1445. CString sMessage(CString::COM_Allocator);
  1446. IF_FAILED_EXIT(GetBITSErrorMsg(pError, sMessage));
  1447. DEBUGOUT1(_pDbgLog, 0, L"LOG: TRANSIENT ERROR from BITS. Error msg is : %s", sMessage._pwz);
  1448. }
  1449. }
  1450. }
  1451. exit:
  1452. // Handle any error.
  1453. if (FAILED(_hr))
  1454. HandleError(NULL, NULL);
  1455. ::LeaveCriticalSection(&_cs);
  1456. SAFERELEASE(pError);
  1457. return S_OK;
  1458. }
  1459. // Privates
  1460. // IUnknown methods
  1461. // ---------------------------------------------------------------------------
  1462. // CAssemblyDownload::QI
  1463. // ---------------------------------------------------------------------------
  1464. STDMETHODIMP
  1465. CAssemblyDownload::QueryInterface(REFIID riid, void** ppvObj)
  1466. {
  1467. if ( IsEqualIID(riid, IID_IUnknown)
  1468. || IsEqualIID(riid, IID_IAssemblyDownload)
  1469. )
  1470. {
  1471. *ppvObj = static_cast<IAssemblyDownload*> (this);
  1472. AddRef();
  1473. return S_OK;
  1474. }
  1475. else if (IsEqualIID(riid, IID_IBackgroundCopyCallback))
  1476. {
  1477. *ppvObj = static_cast<IBackgroundCopyCallback*> (this);
  1478. AddRef();
  1479. return S_OK;
  1480. }
  1481. else
  1482. {
  1483. *ppvObj = NULL;
  1484. return E_NOINTERFACE;
  1485. }
  1486. }
  1487. // ---------------------------------------------------------------------------
  1488. // CAssemblyDownload::AddRef
  1489. // ---------------------------------------------------------------------------
  1490. STDMETHODIMP_(ULONG)
  1491. CAssemblyDownload::AddRef()
  1492. {
  1493. return InterlockedIncrement ((LONG*) &_cRef);
  1494. }
  1495. // ---------------------------------------------------------------------------
  1496. // CAssemblyDownload::Release
  1497. // ---------------------------------------------------------------------------
  1498. STDMETHODIMP_(ULONG)
  1499. CAssemblyDownload::Release()
  1500. {
  1501. ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
  1502. if (!lRet)
  1503. delete this;
  1504. return lRet;
  1505. }
  1506. ///////////////////////////////////////////////////////////////////////////////
  1507. // CBitsCallback
  1508. //
  1509. // ---------------------------------------------------------------------------
  1510. // ctor
  1511. // ---------------------------------------------------------------------------
  1512. CBitsCallback::CBitsCallback(IAssemblyDownload *pDownload)
  1513. : _cRef(1), _dwSig(' BCB'), _hr(S_OK)
  1514. {
  1515. _pDownload = pDownload;
  1516. _pDownload->AddRef();
  1517. }
  1518. // ---------------------------------------------------------------------------
  1519. // dtor
  1520. // ---------------------------------------------------------------------------
  1521. CBitsCallback::~CBitsCallback()
  1522. {
  1523. SAFERELEASE(_pDownload);
  1524. }
  1525. // IBitsCallback methods
  1526. // ---------------------------------------------------------------------------
  1527. // JobTransferred
  1528. // ---------------------------------------------------------------------------
  1529. HRESULT CBitsCallback::JobTransferred(IBackgroundCopyJob *pJob)
  1530. {
  1531. return _pDownload->JobTransferred(pJob);
  1532. }
  1533. // ---------------------------------------------------------------------------
  1534. // JobError
  1535. // ---------------------------------------------------------------------------
  1536. HRESULT CBitsCallback::JobError(IBackgroundCopyJob *pJob, IBackgroundCopyError *pError)
  1537. {
  1538. return _pDownload->JobError(pJob, pError);
  1539. }
  1540. // ---------------------------------------------------------------------------
  1541. // JobModification
  1542. // ---------------------------------------------------------------------------
  1543. HRESULT CBitsCallback::JobModification(IBackgroundCopyJob *pJob, DWORD dwReserved)
  1544. {
  1545. return _pDownload->JobModification(pJob, dwReserved);
  1546. }
  1547. // Privates
  1548. // IUnknown methods
  1549. // ---------------------------------------------------------------------------
  1550. // CBitsCallback::QI
  1551. // ---------------------------------------------------------------------------
  1552. STDMETHODIMP
  1553. CBitsCallback::QueryInterface(REFIID riid, void** ppvObj)
  1554. {
  1555. if ( IsEqualIID(riid, IID_IUnknown)
  1556. || IsEqualIID(riid, IID_IBackgroundCopyCallback)
  1557. )
  1558. {
  1559. *ppvObj = static_cast<IBackgroundCopyCallback*> (this);
  1560. AddRef();
  1561. return S_OK;
  1562. }
  1563. else
  1564. {
  1565. *ppvObj = NULL;
  1566. return E_NOINTERFACE;
  1567. }
  1568. }
  1569. // ---------------------------------------------------------------------------
  1570. // CBitsCallback::AddRef
  1571. // ---------------------------------------------------------------------------
  1572. STDMETHODIMP_(ULONG)
  1573. CBitsCallback::AddRef()
  1574. {
  1575. return InterlockedIncrement ((LONG*) &_cRef);
  1576. }
  1577. // ---------------------------------------------------------------------------
  1578. // CBitsCallback::Release
  1579. // ---------------------------------------------------------------------------
  1580. STDMETHODIMP_(ULONG)
  1581. CBitsCallback::Release()
  1582. {
  1583. ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
  1584. if (!lRet)
  1585. delete this;
  1586. return lRet;
  1587. }
  1588. ///////////////////////////////////////////////////////////////////////////////
  1589. // CGlobalCacheInstallEntry
  1590. //
  1591. // ---------------------------------------------------------------------------
  1592. // ctor
  1593. // ---------------------------------------------------------------------------
  1594. CGlobalCacheInstallEntry::CGlobalCacheInstallEntry()
  1595. : _dwSig('ECAG')
  1596. {
  1597. _pICacheImport = NULL;
  1598. }
  1599. // ---------------------------------------------------------------------------
  1600. // dtor
  1601. // ---------------------------------------------------------------------------
  1602. CGlobalCacheInstallEntry::~CGlobalCacheInstallEntry()
  1603. {
  1604. SAFERELEASE(_pICacheImport);
  1605. }