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.

1307 lines
41 KiB

  1. #include <fusenetincludes.h>
  2. #include <assemblycache.h>
  3. #include <sxsapi.h>
  4. #include "fusion.h"
  5. #include "macros.h"
  6. //BUGBUG - this is not localizeable ? could cause avalon a problem
  7. // use shell apis instead.
  8. #define WZ_CACHE_LOCALROOTDIR L"Local Settings\\My Programs\\"
  9. #define WZ_TEMP_DIR L"__temp__\\"
  10. #define WZ_MANIFEST_STAGING_DIR L"__temp__\\__manifests__\\"
  11. #define WZ_SHARED_DIR L"__shared__\\"
  12. #define WZ_WILDCARDSTRING L"*"
  13. typedef HRESULT(*PFNGETCORSYSTEMDIRECTORY)(LPWSTR, DWORD, LPDWORD);
  14. typedef HRESULT (__stdcall *PFNCREATEASSEMBLYCACHE) (IAssemblyCache **ppAsmCache, DWORD dwReserved);
  15. #define WZ_MSCOREE_DLL_NAME L"mscoree.dll"
  16. #define GETCORSYSTEMDIRECTORY_FN_NAME "GetCORSystemDirectory"
  17. #define CREATEASSEMBLYCACHE_FN_NAME "CreateAssemblyCache"
  18. #define WZ_FUSION_DLL_NAME L"Fusion.dll"
  19. IAssemblyCache* CAssemblyCache::g_pFusionAssemblyCache = NULL;
  20. // ---------------------------------------------------------------------------
  21. // CreateAssemblyCacheImport
  22. // ---------------------------------------------------------------------------
  23. HRESULT CreateAssemblyCacheImport(
  24. LPASSEMBLY_CACHE_IMPORT *ppAssemblyCacheImport,
  25. LPASSEMBLY_IDENTITY pAssemblyIdentity,
  26. DWORD dwFlags)
  27. {
  28. return CAssemblyCache::Retrieve(ppAssemblyCacheImport, pAssemblyIdentity, dwFlags);
  29. }
  30. // ---------------------------------------------------------------------------
  31. // CreateAssemblyCacheEmit
  32. // ---------------------------------------------------------------------------
  33. HRESULT CreateAssemblyCacheEmit(
  34. LPASSEMBLY_CACHE_EMIT *ppAssemblyCacheEmit,
  35. LPASSEMBLY_CACHE_EMIT pAssemblyCacheEmit,
  36. DWORD dwFlags)
  37. {
  38. return CAssemblyCache::Create(ppAssemblyCacheEmit, pAssemblyCacheEmit, dwFlags);
  39. }
  40. // ---------------------------------------------------------------------------
  41. // Retrieve
  42. // ---------------------------------------------------------------------------
  43. HRESULT CAssemblyCache::Retrieve(
  44. LPASSEMBLY_CACHE_IMPORT *ppAssemblyCacheImport,
  45. LPASSEMBLY_IDENTITY pAssemblyIdentity,
  46. DWORD dwFlags)
  47. {
  48. HRESULT hr = S_OK;
  49. MAKE_ERROR_MACROS_STATIC(hr);
  50. LPWSTR pwzSearchDisplayName = NULL;
  51. BOOL bNewAsmId = FALSE;
  52. LPWSTR pwzBuf = NULL;
  53. DWORD dwCC = 0;
  54. CAssemblyCache *pAssemblyCache = NULL;
  55. CString sManifestFilename;
  56. CString sDisplayName;
  57. IF_FALSE_EXIT(dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX
  58. || dwFlags == CACHEIMP_CREATE_RETRIEVE
  59. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF
  60. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX, E_INVALIDARG);
  61. IF_NULL_EXIT(pAssemblyIdentity, E_INVALIDARG);
  62. IF_ALLOC_FAILED_EXIT(pAssemblyCache = new(CAssemblyCache));
  63. IF_FAILED_EXIT(pAssemblyCache->Init(NULL, ASSEMBLY_CACHE_TYPE_APP | ASSEMBLY_CACHE_TYPE_IMPORT));
  64. // get the identity name
  65. IF_FALSE_EXIT(pAssemblyIdentity->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  66. &pwzBuf, &dwCC) == S_OK, E_INVALIDARG);
  67. // filename of the manifest must be the same as the assembly name
  68. // BUGBUG??: this implies manifest filename (and asm name) be remained unchange because
  69. // the assembly name from the new AsmId is used for looking up in the older cached version...
  70. IF_FAILED_EXIT(sManifestFilename.TakeOwnership(pwzBuf, dwCC));
  71. IF_FAILED_EXIT(sManifestFilename.Append(L".manifest"));
  72. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX)
  73. {
  74. LPASSEMBLY_IDENTITY pNewAsmId = NULL;
  75. IF_FAILED_EXIT(CloneAssemblyIdentity(pAssemblyIdentity, &pNewAsmId));
  76. pAssemblyIdentity = pNewAsmId;
  77. bNewAsmId = TRUE;
  78. // force Version to be a wildcard
  79. IF_FAILED_EXIT(pAssemblyIdentity->SetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
  80. WZ_WILDCARDSTRING, lstrlen(WZ_WILDCARDSTRING)+1));
  81. }
  82. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX
  83. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF
  84. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX)
  85. {
  86. // issues: what if other then Version is already wildcarded? does version comparison make sense here?
  87. IF_FAILED_EXIT(pAssemblyIdentity->GetDisplayName(ASMID_DISPLAYNAME_WILDCARDED,
  88. &pwzSearchDisplayName, &dwCC));
  89. if ( (hr = SearchForHighestVersionInCache(&pwzBuf, pwzSearchDisplayName, CAssemblyCache::VISIBLE, pAssemblyCache) == S_OK))
  90. {
  91. IF_FAILED_EXIT(sDisplayName.TakeOwnership(pwzBuf));
  92. // BUGBUG - make GetDisplayName call getassemblyid/getdisplayname instead
  93. IF_FAILED_EXIT((pAssemblyCache->_sDisplayName).Assign(sDisplayName));
  94. }
  95. else
  96. {
  97. IF_FAILED_EXIT(hr);
  98. // can't resolve
  99. hr = S_FALSE;
  100. if (dwFlags != CACHEIMP_CREATE_RESOLVE_REF_EX)
  101. goto exit;
  102. }
  103. }
  104. if (dwFlags == CACHEIMP_CREATE_RETRIEVE
  105. || (hr == S_FALSE && dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX))
  106. {
  107. // make the name anyway if resolving a ref that does not have any completed cache counterpart
  108. // BUGBUG: this may no longer be necessary if shortcut code/UI changes - it's expecting a path
  109. // plus this is inefficient as it searchs the disk at above, even if ref is fully qualified
  110. IF_FAILED_EXIT(pAssemblyIdentity->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &dwCC));
  111. IF_FAILED_EXIT(sDisplayName.TakeOwnership(pwzBuf, dwCC));
  112. // BUGBUG - make GetDisplayName call getassemblyid/getdisplayname instead
  113. IF_FAILED_EXIT((pAssemblyCache->_sDisplayName).Assign(sDisplayName));
  114. }
  115. // Note: this will prepare for delay initializing _pManifestImport
  116. IF_FAILED_EXIT((pAssemblyCache->_sManifestFileDir).Assign(pAssemblyCache->_sRootDir));
  117. // build paths
  118. IF_FAILED_EXIT((pAssemblyCache->_sManifestFileDir).Append(sDisplayName));
  119. if (dwFlags == CACHEIMP_CREATE_RETRIEVE)
  120. {
  121. BOOL bExists = FALSE;
  122. // simple check if dir is in cache or not
  123. IF_FAILED_EXIT(CheckFileExistence((pAssemblyCache->_sManifestFileDir)._pwz, &bExists));
  124. if (!bExists)
  125. {
  126. // cache dir not exists
  127. hr = S_FALSE;
  128. goto exit;
  129. }
  130. }
  131. IF_FAILED_EXIT((pAssemblyCache->_sManifestFileDir).Append(L"\\"));
  132. IF_FAILED_EXIT((pAssemblyCache->_sManifestFilePath).Assign(pAssemblyCache->_sManifestFileDir));
  133. IF_FAILED_EXIT((pAssemblyCache->_sManifestFilePath).Append(sManifestFilename));
  134. *ppAssemblyCacheImport = static_cast<IAssemblyCacheImport*> (pAssemblyCache);
  135. (*ppAssemblyCacheImport)->AddRef();
  136. exit:
  137. SAFEDELETEARRAY(pwzSearchDisplayName);
  138. if (bNewAsmId)
  139. SAFERELEASE(pAssemblyIdentity);
  140. SAFERELEASE(pAssemblyCache);
  141. return hr;
  142. }
  143. // ---------------------------------------------------------------------------
  144. // Create
  145. // ---------------------------------------------------------------------------
  146. HRESULT CAssemblyCache::Create(
  147. LPASSEMBLY_CACHE_EMIT *ppAssemblyCacheEmit,
  148. LPASSEMBLY_CACHE_EMIT pAssemblyCacheEmit,
  149. DWORD dwFlags)
  150. {
  151. HRESULT hr = S_OK;
  152. MAKE_ERROR_MACROS_STATIC(hr);
  153. CAssemblyCache *pAssemblyCache = NULL;
  154. IF_ALLOC_FAILED_EXIT(pAssemblyCache = new(CAssemblyCache) );
  155. IF_FAILED_EXIT(hr = pAssemblyCache->Init(static_cast<CAssemblyCache*> (pAssemblyCacheEmit),
  156. ASSEMBLY_CACHE_TYPE_APP | ASSEMBLY_CACHE_TYPE_EMIT));
  157. *ppAssemblyCacheEmit = static_cast<IAssemblyCacheEmit*> (pAssemblyCache);
  158. (*ppAssemblyCacheEmit)->AddRef();
  159. exit:
  160. SAFERELEASE(pAssemblyCache);
  161. return hr;
  162. }
  163. // ---------------------------------------------------------------------------
  164. // FindVersionInDisplayName
  165. // ---------------------------------------------------------------------------
  166. LPCWSTR CAssemblyCache::FindVersionInDisplayName(LPCWSTR pwzDisplayName)
  167. {
  168. int cNumUnderscoreFromEndToVersionString = 2;
  169. int count = 0;
  170. int ccLen = lstrlen(pwzDisplayName);
  171. LPWSTR pwz = (LPWSTR) (pwzDisplayName+ccLen-1);
  172. LPWSTR pwzRetVal = NULL;
  173. // return a pointer to the start of Version string inside a displayName
  174. while (*pwz != NULL && pwz > pwzDisplayName)
  175. {
  176. if (*pwz == L'_')
  177. count++;
  178. if (count == cNumUnderscoreFromEndToVersionString)
  179. break;
  180. pwz--;
  181. }
  182. if (count == cNumUnderscoreFromEndToVersionString)
  183. pwzRetVal = ++pwz;
  184. return pwzRetVal;
  185. }
  186. // ---------------------------------------------------------------------------
  187. // CompareVersion
  188. // ---------------------------------------------------------------------------
  189. int CAssemblyCache::CompareVersion(LPCWSTR pwzVersion1, LPCWSTR pwzVersion2)
  190. {
  191. // BUGBUG: this should compare version by its major minor build revision!
  192. // possible break if V1=10.0.0.0 and V2=2.0.0.0?
  193. // plus pwzVersion1 is something like "1.0.0.0_en"
  194. return wcscmp(pwzVersion1, pwzVersion2); // This is not used....
  195. }
  196. // ---------------------------------------------------------------------------
  197. // SearchForHighestVersionInCache
  198. // Look for a copy in cache that has the highest version and the specified status
  199. // pwzSearchDisplayName should really be created from a partial ref
  200. //
  201. // return: S_OK - found a version from the ref
  202. // S_FALSE - not found any version from the ref, or
  203. // ref not partial and that version is not there/not in that status
  204. // E_*
  205. // ---------------------------------------------------------------------------
  206. HRESULT CAssemblyCache::SearchForHighestVersionInCache(LPWSTR *ppwzResultDisplayName, LPWSTR pwzSearchDisplayName, CAssemblyCache::CacheStatus eCacheStatus, CAssemblyCache* pCache)
  207. {
  208. HRESULT hr = S_OK;
  209. MAKE_ERROR_MACROS_STATIC(hr);
  210. HANDLE hFind = INVALID_HANDLE_VALUE;
  211. WIN32_FIND_DATA fdAppDir;
  212. DWORD dwLastError = 0;
  213. BOOL fFound = FALSE;
  214. CString sDisplayName;
  215. CString sSearchPath;
  216. *ppwzResultDisplayName = NULL;
  217. sDisplayName.Assign(pwzSearchDisplayName);
  218. IF_FAILED_EXIT(sSearchPath.Assign(pCache->_sRootDir));
  219. IF_FAILED_EXIT(sSearchPath.Append(sDisplayName));
  220. hFind = FindFirstFileEx(sSearchPath._pwz, FindExInfoStandard, &fdAppDir, FindExSearchLimitToDirectories, NULL, 0);
  221. if (hFind == INVALID_HANDLE_VALUE)
  222. {
  223. hr = S_FALSE;
  224. goto exit;
  225. }
  226. do
  227. {
  228. // ???? check file attribute to see if it's a directory? needed only if the file system does not support the filter...
  229. // ???? check version string format?
  230. if (CAssemblyCache::IsStatus(fdAppDir.cFileName, eCacheStatus))
  231. {
  232. ULONGLONG ullMax;
  233. ULONGLONG ullCur;
  234. LPCWSTR pwzVerStr = FindVersionInDisplayName(sDisplayName._pwz);
  235. IF_FAILED_EXIT(ConvertVersionStrToULL(pwzVerStr, &ullMax));
  236. pwzVerStr = FindVersionInDisplayName(fdAppDir.cFileName);
  237. if(!pwzVerStr || FAILED(hr = ConvertVersionStrToULL(pwzVerStr, &ullCur)) )
  238. {
  239. // ignore badly formed dirs; maybe we should delete them
  240. continue;
  241. }
  242. if (ullCur > ullMax)
  243. {
  244. IF_FAILED_EXIT(sDisplayName.Assign(fdAppDir.cFileName));
  245. fFound = TRUE;
  246. } else if (ullCur == ullMax)
  247. fFound = TRUE;
  248. // else keep the newest
  249. }
  250. } while(FindNextFile(hFind, &fdAppDir));
  251. if( (dwLastError = GetLastError()) != ERROR_NO_MORE_FILES)
  252. {
  253. IF_WIN32_FAILED_EXIT(dwLastError);
  254. }
  255. if (fFound)
  256. {
  257. sDisplayName.ReleaseOwnership(ppwzResultDisplayName);
  258. hr = S_OK;
  259. }
  260. else
  261. hr = S_FALSE;
  262. exit:
  263. if (hFind != INVALID_HANDLE_VALUE)
  264. {
  265. if (!FindClose(hFind) && SUCCEEDED(hr)) // don't overwrite if we already have useful hr.
  266. {
  267. ASSERT(0);
  268. hr = FusionpHresultFromLastError();
  269. }
  270. }
  271. return hr;
  272. }
  273. // ---------------------------------------------------------------------------
  274. // CreateFusionAssemblyCacheEx
  275. // ---------------------------------------------------------------------------
  276. HRESULT CreateFusionAssemblyCacheEx (IAssemblyCache **ppFusionAsmCache)
  277. {
  278. HRESULT hr = S_OK;
  279. hr = CAssemblyCache::CreateFusionAssemblyCache(ppFusionAsmCache);
  280. return hr;
  281. }
  282. // ---------------------------------------------------------------------------
  283. // ctor
  284. // ---------------------------------------------------------------------------
  285. CAssemblyCache::CAssemblyCache()
  286. : _dwSig('hcac'), _cRef(1), _hr(S_OK), _dwFlags(0), _pManifestImport(NULL), _pAssemblyId(NULL)
  287. {}
  288. // ---------------------------------------------------------------------------
  289. // dtor
  290. // ---------------------------------------------------------------------------
  291. CAssemblyCache::~CAssemblyCache()
  292. {
  293. SAFERELEASE(_pManifestImport);
  294. SAFERELEASE(_pAssemblyId);
  295. /*
  296. if( _hr != S_OK)
  297. RemoveDirectoryAndChildren(_sManifestFileDir._pwz);
  298. */
  299. }
  300. // ---------------------------------------------------------------------------
  301. // Init
  302. // ---------------------------------------------------------------------------
  303. HRESULT CAssemblyCache::Init(CAssemblyCache *pAssemblyCache, DWORD dwFlags)
  304. {
  305. _dwFlags = dwFlags;
  306. if (!pAssemblyCache)
  307. {
  308. if (_dwFlags & ASSEMBLY_CACHE_TYPE_APP)
  309. {
  310. if (_dwFlags & ASSEMBLY_CACHE_TYPE_IMPORT)
  311. IF_FAILED_EXIT( GetCacheRootDir(_sRootDir, Base));
  312. else if (_dwFlags & ASSEMBLY_CACHE_TYPE_EMIT)
  313. IF_FAILED_EXIT( GetCacheRootDir(_sRootDir, Temp));
  314. }
  315. else if (_dwFlags & ASSEMBLY_CACHE_TYPE_SHARED)
  316. {
  317. IF_FAILED_EXIT( GetCacheRootDir(_sRootDir, Shared));
  318. }
  319. }
  320. else
  321. IF_FAILED_EXIT( _sRootDir.Assign(pAssemblyCache->_sManifestFileDir));
  322. exit :
  323. return _hr;
  324. }
  325. // ---------------------------------------------------------------------------
  326. // GetManifestFilePath
  327. // ---------------------------------------------------------------------------
  328. HRESULT CAssemblyCache::GetManifestFilePath(LPOLESTR *ppwzManifestFilePath,
  329. LPDWORD pccManifestFilePath)
  330. {
  331. CString sPathOut;
  332. IF_FAILED_EXIT(sPathOut.Assign(_sManifestFilePath));
  333. *pccManifestFilePath = sPathOut.CharCount();
  334. IF_FAILED_EXIT(sPathOut.ReleaseOwnership(ppwzManifestFilePath));
  335. exit:
  336. if(FAILED(_hr))
  337. {
  338. *ppwzManifestFilePath = NULL;
  339. *pccManifestFilePath = 0;
  340. }
  341. return _hr;
  342. }
  343. // ---------------------------------------------------------------------------
  344. // GetManifestFileDir
  345. // ---------------------------------------------------------------------------
  346. HRESULT CAssemblyCache::GetManifestFileDir(LPOLESTR *ppwzManifestFileDir,
  347. LPDWORD pccManifestFileDir)
  348. {
  349. CString sDirOut;
  350. IF_FAILED_EXIT(sDirOut.Assign(_sManifestFileDir));
  351. *pccManifestFileDir = sDirOut.CharCount();
  352. IF_FAILED_EXIT(sDirOut.ReleaseOwnership(ppwzManifestFileDir));
  353. exit:
  354. if(FAILED(_hr))
  355. {
  356. *ppwzManifestFileDir = NULL;
  357. *pccManifestFileDir = 0;
  358. }
  359. return _hr;
  360. }
  361. // ---------------------------------------------------------------------------
  362. // GetManifestImport
  363. // ---------------------------------------------------------------------------
  364. HRESULT CAssemblyCache::GetManifestImport(LPASSEMBLY_MANIFEST_IMPORT *ppManifestImport)
  365. {
  366. IF_NULL_EXIT(_pManifestImport, E_INVALIDARG);
  367. *ppManifestImport = _pManifestImport;
  368. (*ppManifestImport)->AddRef();
  369. _hr = S_OK;
  370. exit:
  371. return _hr;
  372. }
  373. // ---------------------------------------------------------------------------
  374. // GetAssemblyIdentity
  375. // ---------------------------------------------------------------------------
  376. HRESULT CAssemblyCache::GetAssemblyIdentity(LPASSEMBLY_IDENTITY *ppAssemblyId)
  377. {
  378. if (_pAssemblyId)
  379. {
  380. *ppAssemblyId = _pAssemblyId;
  381. (*ppAssemblyId)->AddRef();
  382. _hr = S_OK;
  383. }
  384. else
  385. {
  386. IF_NULL_EXIT(_pManifestImport, E_INVALIDARG);
  387. IF_FAILED_EXIT(_pManifestImport->GetAssemblyIdentity(&_pAssemblyId));
  388. *ppAssemblyId = _pAssemblyId;
  389. (*ppAssemblyId)->AddRef();
  390. _hr = S_OK;
  391. }
  392. exit:
  393. return _hr;
  394. }
  395. // ---------------------------------------------------------------------------
  396. // GetDisplayName
  397. // ---------------------------------------------------------------------------
  398. HRESULT CAssemblyCache::GetDisplayName(LPOLESTR *ppwzDisplayName, LPDWORD pccDiaplyName)
  399. {
  400. CString sDisplayNameOut;
  401. IF_FAILED_EXIT(sDisplayNameOut.Assign(_sDisplayName));
  402. *pccDiaplyName= sDisplayNameOut.CharCount();
  403. IF_FAILED_EXIT(sDisplayNameOut.ReleaseOwnership(ppwzDisplayName));
  404. exit:
  405. if(FAILED(_hr))
  406. {
  407. *pccDiaplyName= 0;
  408. *ppwzDisplayName = NULL;
  409. }
  410. return _hr;
  411. }
  412. // ---------------------------------------------------------------------------
  413. // FindExistMatching
  414. // return:
  415. // S_OK
  416. // S_FALSE -not exist or not match
  417. // E_*
  418. // ---------------------------------------------------------------------------
  419. HRESULT CAssemblyCache::FindExistMatching(IManifestInfo *pAssemblyFileInfo, LPOLESTR *ppwzPath)
  420. {
  421. LPWSTR pwzBuf = NULL;
  422. DWORD cbBuf = 0, dwFlag;
  423. CString sFileName;
  424. CString sTargetPath;
  425. IManifestInfo *pFoundFileInfo = NULL;
  426. BOOL bExists=FALSE;
  427. IF_NULL_EXIT(pAssemblyFileInfo, E_INVALIDARG);
  428. IF_NULL_EXIT(ppwzPath, E_INVALIDARG);
  429. *ppwzPath = NULL;
  430. if (_pManifestImport == NULL)
  431. {
  432. if (_sManifestFilePath._cc == 0)
  433. {
  434. // no manifest path
  435. _hr = CO_E_NOTINITIALIZED;
  436. goto exit;
  437. }
  438. // lazy init
  439. IF_FAILED_EXIT(CreateAssemblyManifestImport(&_pManifestImport,
  440. _sManifestFilePath._pwz, NULL, 0));
  441. }
  442. // file name parsed from manifest.
  443. IF_FAILED_EXIT(pAssemblyFileInfo->Get(MAN_INFO_ASM_FILE_NAME,
  444. (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  445. IF_FAILED_EXIT(sFileName.TakeOwnership(pwzBuf));
  446. IF_FAILED_EXIT(sTargetPath.Assign(_sManifestFileDir));
  447. IF_FAILED_EXIT(sTargetPath.Append(sFileName._pwz));
  448. // optimization: check if the target exists
  449. IF_FAILED_EXIT(CheckFileExistence(sTargetPath._pwz, &bExists));
  450. if (!bExists)
  451. {
  452. // file doesn't exist - no point looking into the manifest file
  453. _hr = S_FALSE;
  454. goto exit;
  455. }
  456. // find the specified file entry in the manifest
  457. // BUGBUG: check for missing attribute case
  458. if (FAILED(_hr = _pManifestImport->QueryFile(sFileName._pwz, &pFoundFileInfo))
  459. || _hr == S_FALSE)
  460. goto exit;
  461. // check if the entries match
  462. if (pAssemblyFileInfo->IsEqual(pFoundFileInfo) == S_OK)
  463. {
  464. // BUGBUG:? should now check if the actual file has the matching hash etc.
  465. *ppwzPath = sTargetPath._pwz;
  466. IF_FAILED_EXIT(sTargetPath.ReleaseOwnership(ppwzPath));
  467. }
  468. else
  469. _hr = S_FALSE;
  470. exit:
  471. SAFERELEASE(pFoundFileInfo);
  472. return _hr;
  473. }
  474. // ---------------------------------------------------------------------------
  475. // CopyFile
  476. // ---------------------------------------------------------------------------
  477. HRESULT CAssemblyCache::CopyFile(LPOLESTR pwzSourcePath, LPOLESTR pwzRelativeFileName, DWORD dwFlags)
  478. {
  479. LPWSTR pwzBuf = NULL;
  480. DWORD ccBuf = 0, cbBuf =0, dwFlag = 0, n = 0;
  481. WCHAR wzRandom[8+1] = {0};
  482. CString sDisplayName;
  483. LPASSEMBLY_MANIFEST_IMPORT pManifestImport = NULL;
  484. LPASSEMBLY_IDENTITY pIdentity = NULL;
  485. IManifestInfo *pAssemblyFile= NULL;
  486. if (dwFlags & MANIFEST)
  487. {
  488. // Get display name.
  489. IF_FAILED_EXIT(CreateAssemblyManifestImport(&pManifestImport, pwzSourcePath, NULL, 0));
  490. IF_FAILED_EXIT(pManifestImport->GetAssemblyIdentity(&pIdentity));
  491. IF_FAILED_EXIT(pIdentity->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING,
  492. &pwzBuf, &ccBuf));
  493. IF_FAILED_EXIT(sDisplayName.TakeOwnership(pwzBuf, ccBuf));
  494. IF_FAILED_EXIT(_sDisplayName.Assign(sDisplayName));
  495. SAFERELEASE(pManifestImport);
  496. // Create manifest file path.
  497. IF_FAILED_EXIT(_sManifestFilePath.Assign(_sRootDir));
  498. // Component manifests cached
  499. // relative to application dir.
  500. if (!(dwFlags & COMPONENT))
  501. {
  502. IF_FAILED_EXIT(CreateRandomDir(_sManifestFilePath._pwz, wzRandom, 8));
  503. IF_FAILED_EXIT(_sManifestFilePath.Append(wzRandom));
  504. IF_FAILED_EXIT(_sManifestFilePath.Append(L"\\"));
  505. }
  506. IF_FAILED_EXIT(_sManifestFilePath.Append(pwzRelativeFileName));
  507. _sManifestFilePath.PathNormalize();
  508. // Manifest file dir.
  509. IF_FAILED_EXIT(_sManifestFileDir.Assign(_sManifestFilePath));
  510. IF_FAILED_EXIT(_sManifestFileDir.RemoveLastElement());
  511. IF_FAILED_EXIT(_sManifestFileDir.Append(L"\\"));
  512. // Construct target paths
  513. IF_FAILED_EXIT(CreateDirectoryHierarchy(NULL, _sManifestFilePath._pwz));
  514. // Copy the manifest from staging area into cache.
  515. IF_WIN32_FALSE_EXIT(::CopyFile(pwzSourcePath, _sManifestFilePath._pwz, FALSE));
  516. // Create the manifest import interface on cached manifest.
  517. IF_FAILED_EXIT(CreateAssemblyManifestImport(&_pManifestImport, _sManifestFilePath._pwz, NULL, 0));
  518. // Enumerate files from manifest and pre-generate nested
  519. // directories required for background file copy.
  520. while (_pManifestImport->GetNextFile(n++, &pAssemblyFile) == S_OK)
  521. {
  522. CString sPath;
  523. IF_FAILED_EXIT(pAssemblyFile->Get(MAN_INFO_ASM_FILE_NAME,
  524. (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  525. IF_FAILED_EXIT(sPath.TakeOwnership(pwzBuf));
  526. sPath.PathNormalize();
  527. IF_FAILED_EXIT(CreateDirectoryHierarchy(_sManifestFileDir._pwz, sPath._pwz));
  528. // RELEASE pAssebmlyFile everytime through the while loop
  529. SAFERELEASE(pAssemblyFile);
  530. }
  531. }
  532. else
  533. {
  534. CString sTargetPath;
  535. // Construct target path
  536. IF_FAILED_EXIT(sTargetPath.Assign(_sManifestFileDir));
  537. IF_FAILED_EXIT(sTargetPath.Append(pwzRelativeFileName));
  538. IF_FAILED_EXIT(CreateDirectoryHierarchy(NULL, sTargetPath._pwz));
  539. // Copy non-manifest files into cache. Presumably from previous cached location to the new
  540. IF_WIN32_FALSE_EXIT(::CopyFile(pwzSourcePath, sTargetPath._pwz, FALSE));
  541. }
  542. exit:
  543. SAFERELEASE(pIdentity);
  544. SAFERELEASE(pAssemblyFile);
  545. SAFERELEASE(pManifestImport);
  546. return _hr;
  547. }
  548. // ---------------------------------------------------------------------------
  549. // Commit
  550. // ---------------------------------------------------------------------------
  551. HRESULT CAssemblyCache::Commit(DWORD dwFlags)
  552. {
  553. CString sTargetDir;
  554. IF_NULL_EXIT( _sDisplayName._pwz, E_INVALIDARG);
  555. // No-op for shared assemblies; no directory move.
  556. if (_dwFlags & ASSEMBLY_CACHE_TYPE_SHARED)
  557. {
  558. _hr = S_OK;
  559. goto exit;
  560. }
  561. // Need to rename directory
  562. IF_FAILED_EXIT(GetCacheRootDir(sTargetDir, Base));
  563. IF_FAILED_EXIT(sTargetDir.Append(_sDisplayName));
  564. // Move the file from staging dir. The application is now complete.
  565. if(!MoveFileEx(_sManifestFileDir._pwz, sTargetDir._pwz, MOVEFILE_COPY_ALLOWED))
  566. {
  567. _hr = FusionpHresultFromLastError();
  568. // BUGBUG : move this to destructor.
  569. RemoveDirectoryAndChildren(_sManifestFileDir._pwz);
  570. if(_hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
  571. {
  572. _hr = S_FALSE;
  573. goto exit;
  574. }
  575. IF_FAILED_EXIT(_hr);
  576. }
  577. //BUGBUG - if any files are held open, eg due to leaked/unreleased interfaces
  578. // then movefile will fail. Solution is to ensure that IAssemblyManifestImport does
  579. // not hold file, and to attempt copy if failure occurs. In case a collision occurs,
  580. // delete redundant app copy in staging dir.
  581. exit:
  582. return _hr;
  583. }
  584. #define APP_STATUS_KEY TEXT("1.0.0.0\\Cache\\")
  585. #define WZ_STATUS_CONFIRMED L"Confirmed"
  586. #define WZ_STATUS_VISIBLE L"Visible"
  587. #define WZ_STATUS_CRITICAL L"Critical"
  588. HRESULT CAssemblyCache::GetStatusStrings( CacheStatus eStatus,
  589. LPWSTR *ppValueString,
  590. LPCWSTR pwzDisplayName,
  591. CString& sRelStatusKey)
  592. {
  593. HRESULT hr = S_OK;
  594. MAKE_ERROR_MACROS_STATIC(hr);
  595. switch(eStatus)
  596. {
  597. case VISIBLE:
  598. *ppValueString = WZ_STATUS_VISIBLE;
  599. break;
  600. case CONFIRMED:
  601. *ppValueString = WZ_STATUS_CONFIRMED;
  602. break;
  603. case CRITICAL:
  604. *ppValueString = WZ_STATUS_CRITICAL;
  605. break;
  606. default:
  607. hr = E_INVALIDARG;
  608. goto exit;
  609. }
  610. IF_FAILED_EXIT(sRelStatusKey.Assign(APP_STATUS_KEY));
  611. IF_FAILED_EXIT(sRelStatusKey.Append(pwzDisplayName));
  612. exit:
  613. return hr;
  614. }
  615. // ---------------------------------------------------------------------------
  616. // IsStatus
  617. // return FALSE if value FALSE or absent, TRUE if value TRUE
  618. // ---------------------------------------------------------------------------
  619. BOOL CAssemblyCache::IsStatus(LPWSTR pwzDisplayName, CacheStatus eStatus)
  620. {
  621. HRESULT hr = S_OK;
  622. MAKE_ERROR_MACROS_STATIC(hr);
  623. CString sStatus;
  624. DWORD dwValue = -1;
  625. LPWSTR pwzQueryString = NULL;
  626. // Default values spelled out.
  627. BOOL bStatus = FALSE;
  628. CRegImport *pRegImport = NULL;
  629. if((eStatus == VISIBLE) || (eStatus == CONFIRMED) )
  630. {
  631. bStatus = TRUE;
  632. }
  633. IF_FAILED_EXIT(hr = GetStatusStrings( eStatus, &pwzQueryString, pwzDisplayName, sStatus));
  634. IF_FAILED_EXIT(hr = CRegImport::Create(&pRegImport, sStatus._pwz));
  635. if(hr == S_FALSE)
  636. goto exit;
  637. IF_FAILED_EXIT(pRegImport->ReadDword(pwzQueryString, &dwValue));
  638. // Found a value in registry. Return value.
  639. bStatus = (BOOL) dwValue;
  640. hr = S_OK;
  641. exit:
  642. SAFEDELETE(pRegImport);
  643. return bStatus;
  644. }
  645. // ---------------------------------------------------------------------------
  646. // SetStatus
  647. // ---------------------------------------------------------------------------
  648. HRESULT CAssemblyCache::SetStatus(LPWSTR pwzDisplayName, CacheStatus eStatus, BOOL fStatus)
  649. {
  650. HRESULT hr = S_OK;
  651. MAKE_ERROR_MACROS_STATIC(hr);
  652. CString sStatus;
  653. DWORD dwValue = (DWORD) (fStatus);
  654. LPWSTR pwzValueNameString = NULL;
  655. CRegEmit *pRegEmit = NULL;
  656. // BUGBUG: should this be in-sync with what server does to register update?
  657. IF_FAILED_EXIT(GetStatusStrings( eStatus, &pwzValueNameString, pwzDisplayName, sStatus));
  658. IF_FAILED_EXIT(CRegEmit::Create(&pRegEmit, sStatus._pwz));
  659. // Write
  660. IF_FAILED_EXIT(pRegEmit->WriteDword(pwzValueNameString, dwValue));
  661. hr = S_OK;
  662. exit:
  663. SAFEDELETE(pRegEmit);
  664. return hr;
  665. }
  666. // ---------------------------------------------------------------------------
  667. // GetCacheRootDir
  668. // ---------------------------------------------------------------------------
  669. HRESULT CAssemblyCache::GetCacheRootDir(CString &sCacheDir, CacheFlags eFlags)
  670. {
  671. HRESULT hr = S_OK;
  672. MAKE_ERROR_MACROS_STATIC(hr);
  673. CString sPath;
  674. LPWSTR pwzPath = NULL;
  675. DWORD ccSize=0;
  676. IF_FALSE_EXIT((ccSize = GetEnvironmentVariable(L"UserProfile", NULL, 0)) != 0, E_FAIL);
  677. IF_ALLOC_FAILED_EXIT(pwzPath = new WCHAR[ccSize+1]);
  678. IF_FALSE_EXIT(GetEnvironmentVariable(L"UserProfile", pwzPath, ccSize) != 0, E_FAIL);
  679. IF_FAILED_EXIT(sCacheDir.Assign(pwzPath));
  680. // BUGBUG: don't use PathCombine
  681. IF_FAILED_EXIT((DoPathCombine(sCacheDir, WZ_CACHE_LOCALROOTDIR)));
  682. switch(eFlags)
  683. {
  684. case Base:
  685. break;
  686. case Manifests:
  687. // BUGBUG: don't use PathCombine
  688. IF_FAILED_EXIT(DoPathCombine(sCacheDir, WZ_MANIFEST_STAGING_DIR));
  689. break;
  690. case Temp:
  691. // BUGBUG: don't use PathCombine
  692. IF_FAILED_EXIT(DoPathCombine(sCacheDir, WZ_TEMP_DIR));
  693. break;
  694. case Shared:
  695. // BUGBUG: don't use PathCombine
  696. IF_FAILED_EXIT(DoPathCombine(sCacheDir, WZ_SHARED_DIR));
  697. break;
  698. default:
  699. break;
  700. }
  701. exit:
  702. SAFEDELETEARRAY(pwzPath);
  703. return hr;
  704. }
  705. // ---------------------------------------------------------------------------
  706. // IsCached
  707. // ---------------------------------------------------------------------------
  708. HRESULT CAssemblyCache::IsCached(IAssemblyIdentity *pAppId)
  709. {
  710. HRESULT hr = S_FALSE;
  711. MAKE_ERROR_MACROS_STATIC(hr);
  712. LPWSTR pwz = NULL;
  713. DWORD cc = 0, dwAttrib = 0;
  714. CString sDisplayName;
  715. CString sCacheDir;
  716. BOOL bExists=FALSE;
  717. // Get the assembly display name.
  718. IF_FAILED_EXIT(pAppId->GetDisplayName(0, &pwz, &cc));
  719. IF_FAILED_EXIT(sDisplayName.TakeOwnership(pwz));
  720. // Check if top-level dir is present.
  721. IF_FAILED_EXIT(GetCacheRootDir(sCacheDir, Base));
  722. IF_FAILED_EXIT(sCacheDir.Append(sDisplayName));
  723. IF_FAILED_EXIT(CheckFileExistence(sCacheDir._pwz, &bExists));
  724. (bExists) ? (hr = S_OK) : (hr = S_FALSE);
  725. exit :
  726. return hr;
  727. }
  728. // ---------------------------------------------------------------------------
  729. // IsKnownAssembly
  730. // ---------------------------------------------------------------------------
  731. HRESULT CAssemblyCache::IsKnownAssembly(IAssemblyIdentity *pId, DWORD dwFlags)
  732. {
  733. return ::IsKnownAssembly(pId, dwFlags);
  734. }
  735. // ---------------------------------------------------------------------------
  736. // IsaMissingSystemAssembly
  737. // ---------------------------------------------------------------------------
  738. HRESULT CAssemblyCache::IsaMissingSystemAssembly(IAssemblyIdentity *pId, DWORD dwFlags)
  739. {
  740. HRESULT hr = S_FALSE;
  741. CString sCurrentAssemblyPath;
  742. // check if this is a system assembly.
  743. if ((hr = CAssemblyCache::IsKnownAssembly(pId, KNOWN_SYSTEM_ASSEMBLY)) != S_OK)
  744. goto exit;
  745. // see if it exists in GAC
  746. if ((hr = CAssemblyCache::GlobalCacheLookup(pId, sCurrentAssemblyPath)) == S_OK)
  747. goto exit;
  748. if(hr == S_FALSE)
  749. hr = S_OK; // this is a system assembly which has not yet been installed to GAC.
  750. exit:
  751. return hr;
  752. }
  753. // ---------------------------------------------------------------------------
  754. // CreateFusionAssemblyCache
  755. // ---------------------------------------------------------------------------
  756. HRESULT CAssemblyCache::CreateFusionAssemblyCache(IAssemblyCache **ppFusionAsmCache)
  757. {
  758. HRESULT hr = S_OK;
  759. MAKE_ERROR_MACROS_STATIC(hr);
  760. HMODULE hEEShim = NULL;
  761. HMODULE hFusion = NULL;
  762. DWORD ccPath = MAX_PATH;
  763. CString sFusionPath;
  764. LPWSTR pwzPath=NULL;
  765. if (g_pFusionAssemblyCache)
  766. {
  767. *ppFusionAsmCache = g_pFusionAssemblyCache;
  768. (*ppFusionAsmCache)->AddRef();
  769. goto exit;
  770. }
  771. PFNGETCORSYSTEMDIRECTORY pfnGetCorSystemDirectory = NULL;
  772. PFNCREATEASSEMBLYCACHE pfnCreateAssemblyCache = NULL;
  773. // Find out where the current version of URT is installed
  774. hEEShim = LoadLibrary(WZ_MSCOREE_DLL_NAME);
  775. if(!hEEShim)
  776. {
  777. hr = FusionpHresultFromLastError();
  778. goto exit;
  779. }
  780. pfnGetCorSystemDirectory = (PFNGETCORSYSTEMDIRECTORY)
  781. GetProcAddress(hEEShim, GETCORSYSTEMDIRECTORY_FN_NAME);
  782. if((!pfnGetCorSystemDirectory))
  783. {
  784. hr = FusionpHresultFromLastError();
  785. goto exit;
  786. }
  787. // Get cor path.
  788. hr = pfnGetCorSystemDirectory(NULL, 0, &ccPath);
  789. IF_FALSE_EXIT(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), FAILED(hr) ? hr : E_FAIL);
  790. IF_ALLOC_FAILED_EXIT(pwzPath = new WCHAR[ccPath+1]);
  791. IF_FAILED_EXIT(pfnGetCorSystemDirectory(pwzPath, ccPath, &ccPath));
  792. IF_FAILED_EXIT(sFusionPath.Assign(pwzPath));
  793. // Form path to fusion
  794. IF_FAILED_EXIT(sFusionPath.Append(WZ_FUSION_DLL_NAME));
  795. // Fusion.dll has a static dependency on msvcr70.dll.
  796. // If msvcr70.dll is not in the path (a rare case), a simple LoadLibrary() fails (ERROR_MOD_NOT_FOUND).
  797. // LoadLibraryEx() with LOAD_WITH_ALTERED_SEARCH_PATH fixes this.
  798. hFusion = LoadLibraryEx(sFusionPath._pwz, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  799. if(!hFusion)
  800. {
  801. hr = FusionpHresultFromLastError();
  802. goto exit;
  803. }
  804. // Get method ptr.
  805. pfnCreateAssemblyCache = (PFNCREATEASSEMBLYCACHE)
  806. GetProcAddress(hFusion, CREATEASSEMBLYCACHE_FN_NAME);
  807. if((!pfnCreateAssemblyCache))
  808. {
  809. hr = FusionpHresultFromLastError();
  810. goto exit;
  811. }
  812. // Create the fusion cache interface.
  813. IF_FAILED_EXIT(pfnCreateAssemblyCache(ppFusionAsmCache, 0));
  814. //BUGBUG - we never unload fusion, which is ok for now
  815. // but should when switchover to cache api objects.
  816. g_pFusionAssemblyCache = *ppFusionAsmCache;
  817. g_pFusionAssemblyCache->AddRef();
  818. hr = S_OK;
  819. exit:
  820. SAFEDELETEARRAY(pwzPath);
  821. return hr;
  822. }
  823. // ---------------------------------------------------------------------------
  824. // GlobalCacheLookup
  825. // ---------------------------------------------------------------------------
  826. HRESULT CAssemblyCache::GlobalCacheLookup(IAssemblyIdentity *pId, CString& sCurrentAssemblyPath)
  827. {
  828. HRESULT hr = S_OK;
  829. MAKE_ERROR_MACROS_STATIC(hr);
  830. LPWSTR pwz = NULL;
  831. DWORD cc = 0;
  832. CString sCLRDisplayName;
  833. IAssemblyCache *pFusionCache = NULL;
  834. ASSEMBLY_INFO asminfo = {0};
  835. WCHAR pwzPath[MAX_PATH];
  836. CString sPath;
  837. IF_FAILED_EXIT(sPath.ResizeBuffer(MAX_PATH+1));
  838. // Get the URT display name for lookup.
  839. IF_FAILED_EXIT(pId->GetCLRDisplayName(0, &pwz, &cc));
  840. IF_FAILED_EXIT(sCLRDisplayName.TakeOwnership(pwz));
  841. // Set size on asminfo struct.
  842. asminfo.cbAssemblyInfo = sizeof(ASSEMBLY_INFO);
  843. asminfo.pszCurrentAssemblyPathBuf = sPath._pwz;
  844. asminfo.cchBuf = MAX_PATH;
  845. // Create the fusion cache object for lookup.
  846. IF_FAILED_EXIT(CreateFusionAssemblyCache(&pFusionCache));
  847. // Get cache info for assembly. Needs to free [out] pathbuf
  848. if(FAILED(hr = pFusionCache->QueryAssemblyInfo(0, sCLRDisplayName._pwz, &asminfo)))
  849. {
  850. hr = S_FALSE; // all failures are being interpreted as ERROR_FILE_NOT_FOUND
  851. goto exit;
  852. }
  853. // Return ok if install flag present.
  854. if (asminfo.dwAssemblyFlags == ASSEMBLYINFO_FLAG_INSTALLED)
  855. {
  856. IF_FAILED_EXIT(sCurrentAssemblyPath.Assign(asminfo.pszCurrentAssemblyPathBuf));
  857. hr = S_OK;
  858. }
  859. else
  860. hr = S_FALSE;
  861. exit:
  862. SAFERELEASE(pFusionCache);
  863. return hr;
  864. }
  865. // ---------------------------------------------------------------------------
  866. // GlobalCacheInstall
  867. // ---------------------------------------------------------------------------
  868. HRESULT CAssemblyCache::GlobalCacheInstall(IAssemblyCacheImport *pCacheImport,
  869. CString& sCurrentAssemblyPath, CString& sInstallRefString)
  870. {
  871. HRESULT hr = S_OK;
  872. MAKE_ERROR_MACROS_STATIC(hr);
  873. LPWSTR pwz = NULL;
  874. DWORD cc = 0;
  875. // Fusion.dll's assembly cache, not to be confusing.
  876. IAssemblyCache *pFusionCache = NULL;
  877. // note: InstallAssembly takes in LPCFUSION_INSTALL_REFERENCE
  878. // so fix this to have one fiRef instead (of one per loop)
  879. // - make static also ? - adriaanc
  880. FUSION_INSTALL_REFERENCE fiRef = {0};
  881. // Create Fusion cache object for install.
  882. IF_FAILED_EXIT(CreateFusionAssemblyCache(&pFusionCache));
  883. // Setup the necessary reference struct.
  884. fiRef.cbSize = sizeof(FUSION_INSTALL_REFERENCE);
  885. fiRef.dwFlags = 0;
  886. fiRef.guidScheme = FUSION_REFCOUNT_OPAQUE_STRING_GUID;
  887. fiRef.szIdentifier = sInstallRefString._pwz;
  888. fiRef.szNonCannonicalData = NULL;
  889. if (pCacheImport != NULL)
  890. {
  891. CString sManifestFilePath;
  892. // 1. Install the downloaded assembly
  893. // Get the source manifest path.
  894. IF_FAILED_EXIT(pCacheImport->GetManifestFilePath(&pwz, &cc));
  895. IF_FAILED_EXIT(sManifestFilePath.TakeOwnership(pwz));
  896. // Do the install.
  897. // ISSUE - always refresh - check fusion doc on refresh
  898. IF_FAILED_EXIT(pFusionCache->InstallAssembly(IASSEMBLYCACHE_INSTALL_FLAG_REFRESH, sManifestFilePath._pwz, &fiRef));
  899. }
  900. else if ((sCurrentAssemblyPath)._cc != 0)
  901. {
  902. // bugbug - as the list is set up during pre-download, the assemblies to be add-ref-ed
  903. // could have been removed by this time. Need to recover from this.
  904. // ignore error from Fusion and continue for now
  905. // 2. Up the ref count of the existing assembly by doing install.
  906. IF_FAILED_EXIT(pFusionCache->InstallAssembly(0, sCurrentAssemblyPath._pwz, &fiRef));
  907. }
  908. exit :
  909. SAFERELEASE(pFusionCache);
  910. return hr;
  911. }
  912. // ---------------------------------------------------------------------------
  913. // DeleteAssemblyAndModules
  914. // ---------------------------------------------------------------------------
  915. HRESULT CAssemblyCache::DeleteAssemblyAndModules(LPWSTR pszManifestFilePath)
  916. {
  917. HRESULT hr = S_OK;
  918. MAKE_ERROR_MACROS_STATIC(hr);
  919. IAssemblyManifestImport *pManImport=NULL;
  920. DWORD nIndex=0;
  921. DWORD dwFlag;
  922. DWORD cbBuf;
  923. LPWSTR pwzBuf=NULL;
  924. IManifestInfo *pFileInfo = NULL;
  925. CString sAssemblyPath;
  926. IF_FAILED_EXIT(CreateAssemblyManifestImport(&pManImport, pszManifestFilePath, NULL, 0));
  927. IF_FAILED_EXIT(sAssemblyPath.Assign(pszManifestFilePath));
  928. while ((hr = pManImport->GetNextFile(nIndex++, &pFileInfo)) == S_OK)
  929. {
  930. IF_FAILED_EXIT(pFileInfo->Get(MAN_INFO_ASM_FILE_NAME, (LPVOID *)&pwzBuf, &cbBuf, &dwFlag));
  931. IF_FAILED_EXIT(sAssemblyPath.RemoveLastElement());
  932. IF_FAILED_EXIT(sAssemblyPath.Append(L"\\"));
  933. IF_FAILED_EXIT(sAssemblyPath.Append(pwzBuf));
  934. IF_WIN32_FALSE_EXIT(::DeleteFile(sAssemblyPath._pwz));
  935. SAFEDELETEARRAY(pwzBuf);
  936. SAFERELEASE(pFileInfo);
  937. }
  938. if(hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
  939. hr = S_OK;
  940. IF_FAILED_EXIT(hr);
  941. SAFERELEASE(pManImport); // release manImport before deleting manifestFile
  942. IF_WIN32_FALSE_EXIT(::DeleteFile(pszManifestFilePath));
  943. IF_FAILED_EXIT(sAssemblyPath.RemoveLastElement());
  944. if(!::RemoveDirectory(sAssemblyPath._pwz))
  945. {
  946. hr = FusionpHresultFromLastError();
  947. if(hr == HRESULT_FROM_WIN32(ERROR_DIR_NOT_EMPTY))
  948. hr = S_OK; // looks like there are more files in this dir.
  949. goto exit;
  950. }
  951. hr = S_OK;
  952. exit:
  953. SAFERELEASE(pManImport);
  954. SAFEDELETEARRAY(pwzBuf);
  955. SAFERELEASE(pFileInfo);
  956. return hr;
  957. }
  958. // IUnknown methods
  959. // ---------------------------------------------------------------------------
  960. // CAssemblyCache::QI
  961. // ---------------------------------------------------------------------------
  962. STDMETHODIMP
  963. CAssemblyCache::QueryInterface(REFIID riid, void** ppvObj)
  964. {
  965. if ( IsEqualIID(riid, IID_IUnknown)
  966. || IsEqualIID(riid, IID_IAssemblyCacheImport)
  967. )
  968. {
  969. *ppvObj = static_cast<IAssemblyCacheImport*> (this);
  970. AddRef();
  971. return S_OK;
  972. }
  973. else if (IsEqualIID(riid, IID_IAssemblyCacheEmit))
  974. {
  975. *ppvObj = static_cast<IAssemblyCacheEmit*> (this);
  976. AddRef();
  977. return S_OK;
  978. }
  979. else
  980. {
  981. *ppvObj = NULL;
  982. return E_NOINTERFACE;
  983. }
  984. }
  985. // ---------------------------------------------------------------------------
  986. // CAssemblyCache::AddRef
  987. // ---------------------------------------------------------------------------
  988. STDMETHODIMP_(ULONG)
  989. CAssemblyCache::AddRef()
  990. {
  991. return InterlockedIncrement ((LONG*) &_cRef);
  992. }
  993. // ---------------------------------------------------------------------------
  994. // CAssemblyCache::Release
  995. // ---------------------------------------------------------------------------
  996. STDMETHODIMP_(ULONG)
  997. CAssemblyCache::Release()
  998. {
  999. ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
  1000. if (!lRet)
  1001. delete this;
  1002. return lRet;
  1003. }