Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

830 lines
25 KiB

  1. #include <fusenetincludes.h>
  2. #include <assemblycache.h>
  3. #include "..\id\sxsid.h"
  4. #define WZ_CACHE_LOCALROOTDIR L"Application Store\\"
  5. #define WZ_MANIFEST_STAGING_DIR L"ManifestStagingDir\\"
  6. #define WZ_WILDCARDSTRING L"*"
  7. extern BOOL IsEqualAssemblyFileInfo(LPASSEMBLY_FILE_INFO pAsmFileInfo1, LPASSEMBLY_FILE_INFO pAsmFileInfo2);
  8. // ---------------------------------------------------------------------------
  9. // CreateAssemblyCacheImport
  10. // ---------------------------------------------------------------------------
  11. STDAPI
  12. CreateAssemblyCacheImport(
  13. LPASSEMBLY_CACHE_IMPORT *ppAssemblyCacheImport,
  14. LPASSEMBLY_IDENTITY pAssemblyIdentity,
  15. DWORD dwFlags)
  16. {
  17. HRESULT hr = S_OK;
  18. LPWSTR pwzSearchDisplayName = NULL;
  19. BOOL bNewAsmId = FALSE;
  20. CAssemblyCache *pAssemblyCache = NULL;
  21. pAssemblyCache = new(CAssemblyCache);
  22. if (!pAssemblyCache)
  23. {
  24. hr = E_OUTOFMEMORY;
  25. goto exit;
  26. }
  27. if (FAILED(hr = pAssemblyCache->Init(NULL)))
  28. goto exit;
  29. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX_COMPLETED
  30. || dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST
  31. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF
  32. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX
  33. || dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED)
  34. {
  35. LPWSTR pwzBuf = NULL;
  36. DWORD dwCC = 0;
  37. CString sManifestFilename;
  38. CString sDisplayName;
  39. if (pAssemblyIdentity == NULL)
  40. {
  41. hr = E_INVALIDARG;
  42. goto exit;
  43. }
  44. // get the identity name
  45. if ((hr = pAssemblyIdentity->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME,
  46. &pwzBuf, &dwCC)) != S_OK)
  47. {
  48. // BUGBUG?: should this work regardless the existence of asm name?
  49. hr = E_INVALIDARG;
  50. goto exit;
  51. }
  52. // filename of the manifest must be the same as the assembly name
  53. // BUGBUG??: this implies manifest filename (and asm name) be remained unchange because
  54. // the assembly name from the new AsmId is used for looking up in the older cached version...
  55. sManifestFilename.TakeOwnership(pwzBuf, dwCC);
  56. if (FAILED(hr = sManifestFilename.Append(L".manifest")))
  57. goto exit;
  58. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX_COMPLETED)
  59. {
  60. LPASSEMBLY_IDENTITY pNewAsmId = NULL;
  61. if (FAILED(hr = CloneAssemblyIdentity(pAssemblyIdentity, &pNewAsmId)))
  62. goto exit;
  63. pAssemblyIdentity = pNewAsmId;
  64. bNewAsmId = TRUE;
  65. // force Version to be a wildcard
  66. if (FAILED(hr = pAssemblyIdentity->SetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION,
  67. WZ_WILDCARDSTRING, lstrlen(WZ_WILDCARDSTRING)+1)))
  68. goto exit;
  69. }
  70. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX_COMPLETED
  71. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF
  72. || dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX)
  73. {
  74. // issues: what if other then Version is already wildcarded? does version comparison make sense here?
  75. if (FAILED(hr = pAssemblyIdentity->GetDisplayName(ASMID_DISPLAYNAME_WILDCARDED,
  76. &pwzSearchDisplayName, &dwCC)))
  77. goto exit;
  78. if (SearchForHighestVersionInCache(&pwzBuf, pwzSearchDisplayName, CAssemblyCache::COMPLETED, pAssemblyCache) == S_OK)
  79. {
  80. sDisplayName.TakeOwnership(pwzBuf);
  81. // BUGBUG - make GetDisplayName call getassemblyid/getdisplayname instead
  82. if (FAILED(hr = (pAssemblyCache->_sDisplayName).Assign(sDisplayName)))
  83. goto exit;
  84. }
  85. else
  86. {
  87. // can't resolve
  88. hr = S_FALSE;
  89. if (dwFlags != CACHEIMP_CREATE_RESOLVE_REF_EX)
  90. goto exit;
  91. }
  92. }
  93. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST
  94. || dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED
  95. || (hr == S_FALSE && dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX))
  96. {
  97. // make the name anyway if resolving a ref that does not have any completed cache counterpart
  98. // BUGBUG: this may no longer be necessary if shortcut code/UI changes - it's expecting a path
  99. // plus this is inefficient as it searchs the disk at above, even if ref is fully qualified
  100. if (FAILED(hr = pAssemblyIdentity->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &dwCC)))
  101. goto exit;
  102. hr = sDisplayName.TakeOwnership(pwzBuf, dwCC);
  103. // BUGBUG - make GetDisplayName call getassemblyid/getdisplayname instead
  104. if (FAILED(hr = (pAssemblyCache->_sDisplayName).Assign(sDisplayName)))
  105. goto exit;
  106. }
  107. // Note: this will prepare for delay initializing _pManifestImport
  108. if (FAILED(hr = (pAssemblyCache->_sManifestFileDir).Assign(pAssemblyCache->_sRootDir)))
  109. goto exit;
  110. // build paths
  111. if (FAILED(hr = (pAssemblyCache->_sManifestFileDir).Append(sDisplayName)))
  112. goto exit;
  113. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST ||dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED)
  114. {
  115. // simple check if dir is in cache or not
  116. if (GetFileAttributes((pAssemblyCache->_sManifestFileDir)._pwz) == (DWORD)-1)
  117. {
  118. // cache dir not exists
  119. hr = S_FALSE;
  120. goto exit;
  121. }
  122. }
  123. if (dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED)
  124. {
  125. if (!(pAssemblyCache ->IsStatus (sDisplayName._pwz, CAssemblyCache::COMPLETED)))
  126. {
  127. // cache dir not completed
  128. hr = S_FALSE;
  129. goto exit;
  130. }
  131. }
  132. if (FAILED(hr = (pAssemblyCache->_sManifestFileDir).Append(L"\\")))
  133. goto exit;
  134. if (FAILED(hr = (pAssemblyCache->_sManifestFilePath).Assign(pAssemblyCache->_sManifestFileDir)))
  135. goto exit;
  136. if (FAILED(hr = (pAssemblyCache->_sManifestFilePath).Append(sManifestFilename)))
  137. goto exit;
  138. }
  139. exit:
  140. SAFEDELETE(pwzSearchDisplayName);
  141. if (bNewAsmId)
  142. SAFERELEASE(pAssemblyIdentity);
  143. if (FAILED(hr) || hr == S_FALSE)
  144. {
  145. // hr == S_FALSE for not found
  146. SAFERELEASE(pAssemblyCache);
  147. }
  148. *ppAssemblyCacheImport = static_cast<IAssemblyCacheImport*> (pAssemblyCache);
  149. return hr;
  150. }
  151. // ---------------------------------------------------------------------------
  152. // CreateAssemblyCacheEmit
  153. // ---------------------------------------------------------------------------
  154. STDAPI
  155. CreateAssemblyCacheEmit(
  156. LPASSEMBLY_CACHE_EMIT *ppAssemblyCacheEmit,
  157. LPASSEMBLY_CACHE_EMIT pAssemblyCacheEmit,
  158. DWORD dwFlags)
  159. {
  160. HRESULT hr = S_OK;
  161. CAssemblyCache *pAssemblyCache = NULL;
  162. pAssemblyCache = new(CAssemblyCache);
  163. if (!pAssemblyCache)
  164. {
  165. hr = E_OUTOFMEMORY;
  166. goto exit;
  167. }
  168. hr = pAssemblyCache->Init(static_cast<CAssemblyCache*> (pAssemblyCacheEmit));
  169. if (FAILED(hr))
  170. {
  171. SAFERELEASE(pAssemblyCache);
  172. goto exit;
  173. }
  174. exit:
  175. *ppAssemblyCacheEmit = static_cast<IAssemblyCacheEmit*> (pAssemblyCache);
  176. return hr;
  177. }
  178. // ---------------------------------------------------------------------------
  179. // FindVersionInDisplayName
  180. // ---------------------------------------------------------------------------
  181. LPCWSTR
  182. FindVersionInDisplayName(LPCWSTR pwzDisplayName)
  183. {
  184. int cNumUnderscoreFromEndToVersionString = 2;
  185. int count = 0;
  186. int ccLen = lstrlen(pwzDisplayName);
  187. LPWSTR pwz = (LPWSTR) (pwzDisplayName+ccLen-1);
  188. LPWSTR pwzRetVal = NULL;
  189. // return a pointer to the start of Version string inside a displayName
  190. while (*pwz != NULL && pwz > pwzDisplayName)
  191. {
  192. if (*pwz == L'_')
  193. count++;
  194. if (count == cNumUnderscoreFromEndToVersionString)
  195. break;
  196. pwz--;
  197. }
  198. if (count == cNumUnderscoreFromEndToVersionString)
  199. pwzRetVal = ++pwz;
  200. return pwzRetVal;
  201. }
  202. // ---------------------------------------------------------------------------
  203. // CompareVersion
  204. // ---------------------------------------------------------------------------
  205. int
  206. CompareVersion(LPCWSTR pwzVersion1, LPCWSTR pwzVersion2)
  207. {
  208. // BUGBUG: this should compare version by its major minor build revision!
  209. // possible break if V1=10.0.0.0 and V2=2.0.0.0?
  210. // plus pwzVersion1 is something like "1.0.0.0_en"
  211. return wcscmp(pwzVersion1, pwzVersion2);
  212. }
  213. // ---------------------------------------------------------------------------
  214. // SearchForHighestVersionInCache
  215. // Look for a copy in cache that has the highest version and the specified status
  216. // pwzSearchDisplayName should really be created from a partial ref
  217. //
  218. // return: S_OK - found a version from the ref
  219. // S_FALSE - not found any version from the ref, or
  220. // ref not partial and that version is not there/not in that status
  221. // E_*
  222. // ---------------------------------------------------------------------------
  223. HRESULT
  224. SearchForHighestVersionInCache(LPWSTR *ppwzResultDisplayName, LPWSTR pwzSearchDisplayName, CAssemblyCache::CacheStatus eCacheStatus, CAssemblyCache* pCache)
  225. {
  226. HRESULT hr = S_OK;
  227. HANDLE hFind = INVALID_HANDLE_VALUE;
  228. WIN32_FIND_DATA fdAppDir;
  229. DWORD dwLastError = 0;
  230. BOOL fFound = FALSE;
  231. CString sDisplayName;
  232. CString sSearchPath;
  233. *ppwzResultDisplayName = NULL;
  234. sDisplayName.Assign(pwzSearchDisplayName);
  235. if (FAILED(hr=sSearchPath.Assign(pCache->_sRootDir)))
  236. goto exit;
  237. if (FAILED(hr=sSearchPath.Append(sDisplayName)))
  238. goto exit;
  239. hFind = FindFirstFileEx(sSearchPath._pwz, FindExInfoStandard, &fdAppDir, FindExSearchLimitToDirectories, NULL, 0);
  240. if (hFind == INVALID_HANDLE_VALUE)
  241. {
  242. hr = S_FALSE;
  243. goto exit;
  244. }
  245. while (dwLastError != ERROR_NO_MORE_FILES)
  246. {
  247. // ???? check file attribute to see if it's a directory? needed only if the file system does not support the filter...
  248. // ???? check version string format?
  249. if (pCache->IsStatus(fdAppDir.cFileName, eCacheStatus))
  250. {
  251. int iRetVal = CompareVersion(FindVersionInDisplayName(fdAppDir.cFileName), FindVersionInDisplayName(sDisplayName._pwz));
  252. if (iRetVal > 0)
  253. {
  254. sDisplayName.Assign(fdAppDir.cFileName);
  255. fFound = TRUE;
  256. } else if (iRetVal == 0)
  257. fFound = TRUE;
  258. // else keep the newest
  259. }
  260. if (!FindNextFile(hFind, &fdAppDir))
  261. {
  262. dwLastError = GetLastError();
  263. continue;
  264. }
  265. }
  266. if (fFound)
  267. {
  268. *ppwzResultDisplayName = sDisplayName._pwz;
  269. sDisplayName.ReleaseOwnership();
  270. hr = S_OK;
  271. }
  272. else
  273. hr = S_FALSE;
  274. exit:
  275. if (hFind != INVALID_HANDLE_VALUE)
  276. {
  277. if (!FindClose(hFind))
  278. {
  279. // can return 0, even when there's an error.
  280. DWORD dw = GetLastError();
  281. hr = dw ? HRESULT_FROM_WIN32(dw) : E_FAIL;
  282. }
  283. }
  284. return hr;
  285. }
  286. // ---------------------------------------------------------------------------
  287. // ctor
  288. // ---------------------------------------------------------------------------
  289. CAssemblyCache::CAssemblyCache()
  290. : _dwSig('hcac'), _cRef(1), _hr(S_OK), _pManifestImport(NULL)
  291. {}
  292. // ---------------------------------------------------------------------------
  293. // dtor
  294. // ---------------------------------------------------------------------------
  295. CAssemblyCache::~CAssemblyCache()
  296. {
  297. SAFERELEASE(_pManifestImport);
  298. }
  299. // ---------------------------------------------------------------------------
  300. // Init
  301. // ---------------------------------------------------------------------------
  302. HRESULT CAssemblyCache::Init(CAssemblyCache *pAssemblyCache)
  303. {
  304. if (!pAssemblyCache)
  305. GetCacheRootDir(_sRootDir, Base);
  306. else
  307. _sRootDir.Assign(pAssemblyCache->_sManifestFileDir);
  308. return S_OK;
  309. }
  310. // ---------------------------------------------------------------------------
  311. // GetManifestFilePath
  312. // ---------------------------------------------------------------------------
  313. HRESULT CAssemblyCache::GetManifestFilePath(LPOLESTR *ppwzManifestFilePath,
  314. LPDWORD pccManifestFilePath)
  315. {
  316. CString sPathOut;
  317. sPathOut.Assign(_sManifestFilePath);
  318. *ppwzManifestFilePath = sPathOut._pwz;
  319. *pccManifestFilePath = sPathOut._cc;
  320. sPathOut.ReleaseOwnership();
  321. return S_OK;
  322. }
  323. // ---------------------------------------------------------------------------
  324. // GetManifestFileDir
  325. // ---------------------------------------------------------------------------
  326. HRESULT CAssemblyCache::GetManifestFileDir(LPOLESTR *ppwzManifestFileDir,
  327. LPDWORD pccManifestFileDir)
  328. {
  329. CString sDirOut;
  330. sDirOut.Assign(_sManifestFileDir);
  331. *ppwzManifestFileDir = sDirOut._pwz;
  332. *pccManifestFileDir = sDirOut._cc;
  333. sDirOut.ReleaseOwnership();
  334. return S_OK;
  335. }
  336. // ---------------------------------------------------------------------------
  337. // GetManifestImport
  338. // ---------------------------------------------------------------------------
  339. HRESULT CAssemblyCache::GetManifestImport(LPASSEMBLY_MANIFEST_IMPORT *ppManifestImport)
  340. {
  341. *ppManifestImport = _pManifestImport;
  342. (*ppManifestImport)->AddRef();
  343. return S_OK;
  344. }
  345. // ---------------------------------------------------------------------------
  346. // GetDisplayName
  347. // ---------------------------------------------------------------------------
  348. HRESULT CAssemblyCache::GetDisplayName(LPOLESTR *ppwzDisplayName, LPDWORD pccDiaplyName)
  349. {
  350. CString sDisplayNameOut;
  351. sDisplayNameOut.Assign(_sDisplayName);
  352. *ppwzDisplayName = sDisplayNameOut._pwz;
  353. *pccDiaplyName= sDisplayNameOut._cc;
  354. sDisplayNameOut.ReleaseOwnership();
  355. return S_OK;
  356. }
  357. // ---------------------------------------------------------------------------
  358. // FindExistMatching
  359. // return:
  360. // S_OK
  361. // S_FALSE -not exist or not match
  362. // E_*
  363. // ---------------------------------------------------------------------------
  364. HRESULT CAssemblyCache::FindExistMatching(LPASSEMBLY_FILE_INFO pAssemblyFileInfo, LPOLESTR *ppwzPath)
  365. {
  366. LPWSTR pwzBuf = NULL;
  367. DWORD ccBuf = 0;
  368. CString sFileName;
  369. CString sTargetPath;
  370. LPASSEMBLY_FILE_INFO pFoundFileInfo = NULL;
  371. if (pAssemblyFileInfo == NULL || ppwzPath == NULL)
  372. {
  373. _hr = E_INVALIDARG;
  374. goto exit;
  375. }
  376. *ppwzPath = NULL;
  377. if (_pManifestImport == NULL)
  378. {
  379. if (_sManifestFilePath._cc == 0)
  380. {
  381. // no manifest path
  382. _hr = CO_E_NOTINITIALIZED;
  383. goto exit;
  384. }
  385. // lazy init
  386. if (FAILED(_hr = CreateAssemblyManifestImport(&_pManifestImport, _sManifestFilePath._pwz)))
  387. goto exit;
  388. }
  389. // file name parsed from manifest.
  390. if (FAILED(_hr = pAssemblyFileInfo->Get(ASM_FILE_NAME, &pwzBuf, &ccBuf)))
  391. goto exit;
  392. sFileName.TakeOwnership(pwzBuf, ccBuf);
  393. if (FAILED(_hr = sTargetPath.Assign(_sManifestFileDir)))
  394. goto exit;
  395. if (FAILED(_hr = sTargetPath.Append(sFileName._pwz)))
  396. goto exit;
  397. // optimization: check if the target exists
  398. if (GetFileAttributes(sTargetPath._pwz) == (DWORD)-1)
  399. {
  400. // file doesn't exist - no point looking into the manifest file
  401. _hr = S_FALSE;
  402. goto exit;
  403. }
  404. // find the specified file entry in the manifest
  405. // BUGBUG: check for missing attribute case
  406. if (FAILED(_hr = _pManifestImport->QueryFile(sFileName._pwz, &pFoundFileInfo))
  407. || _hr == S_FALSE)
  408. goto exit;
  409. // check if the entries match
  410. if (IsEqualAssemblyFileInfo(pAssemblyFileInfo, pFoundFileInfo))
  411. {
  412. // BUGBUG:? should now check if the actual file has the matching hash etc.
  413. *ppwzPath = sTargetPath._pwz;
  414. sTargetPath.ReleaseOwnership();
  415. }
  416. else
  417. _hr = S_FALSE;
  418. exit:
  419. SAFERELEASE(pFoundFileInfo);
  420. return _hr;
  421. }
  422. // ---------------------------------------------------------------------------
  423. // CopyFile
  424. // ---------------------------------------------------------------------------
  425. HRESULT CAssemblyCache::CopyFile(LPOLESTR pwzSourcePath, LPOLESTR pwzFileName, DWORD dwFlags)
  426. {
  427. LPWSTR pwzBuf = NULL;
  428. DWORD ccBuf = 0;
  429. CString sDisplayName;
  430. LPASSEMBLY_MANIFEST_IMPORT pManifestImport = NULL;
  431. LPASSEMBLY_IDENTITY pIdentity = NULL;
  432. LPASSEMBLY_FILE_INFO pAssemblyFile= NULL;
  433. if (dwFlags == MANIFEST)
  434. {
  435. DWORD n = 0;
  436. CreateAssemblyManifestImport(&pManifestImport, pwzSourcePath);
  437. pManifestImport->GetAssemblyIdentity(&pIdentity);
  438. pIdentity->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &ccBuf);
  439. sDisplayName.TakeOwnership(pwzBuf, ccBuf);
  440. _sDisplayName.Assign(sDisplayName);
  441. // Construct target path
  442. _sManifestFileDir.Assign(_sRootDir);
  443. _sManifestFileDir.Append(sDisplayName);
  444. _sManifestFileDir.Append(L"\\");
  445. _sManifestFilePath.Assign(_sManifestFileDir);
  446. _sManifestFilePath.Append(pwzFileName);
  447. CreateDirectoryHierarchy(NULL, _sManifestFilePath._pwz);
  448. // Copy the manifest from staging area into cache.
  449. ::CopyFile(pwzSourcePath, _sManifestFilePath._pwz, FALSE);
  450. SAFERELEASE(pManifestImport);
  451. ::DeleteFile(pwzSourcePath);
  452. // Create the manifest import interface
  453. CreateAssemblyManifestImport(&_pManifestImport, _sManifestFilePath._pwz);
  454. // Enumerate files from manifest and pre-generate nested
  455. // directories required for background file copy.
  456. while (_pManifestImport->GetNextFile(n++, &pAssemblyFile) == S_OK)
  457. {
  458. CString sPath;
  459. pAssemblyFile->Get(ASM_FILE_NAME, &pwzBuf, &ccBuf);
  460. sPath.TakeOwnership(pwzBuf, ccBuf);
  461. sPath.PathNormalize();
  462. CreateDirectoryHierarchy(_sManifestFileDir._pwz, sPath._pwz);
  463. // RELEASE pAssebmlyFile everytime through the while loop
  464. SAFERELEASE(pAssemblyFile);
  465. }
  466. }
  467. else
  468. {
  469. CString sTargetPath;
  470. // Construct target path
  471. sTargetPath.Assign(_sManifestFileDir);
  472. sTargetPath.Append(pwzFileName);
  473. CreateDirectoryHierarchy(NULL, sTargetPath._pwz);
  474. // Copy non-manifest files into cache. Presumably from previous cached location to the new
  475. ::CopyFile(pwzSourcePath, sTargetPath._pwz, FALSE);
  476. }
  477. if (pIdentity)
  478. pIdentity->Release();
  479. return _hr;
  480. }
  481. // ---------------------------------------------------------------------------
  482. // Commit
  483. // ---------------------------------------------------------------------------
  484. HRESULT CAssemblyCache::Commit(DWORD dwFlags)
  485. {
  486. if (!(_sDisplayName._pwz))
  487. {
  488. _hr = E_FAIL;
  489. goto exit;
  490. }
  491. // mark cache completed
  492. _hr = SetStatus(_sDisplayName._pwz, COMPLETED);
  493. exit:
  494. return _hr;
  495. }
  496. #define REG_KEY_FUSION_SETTINGS TEXT("Software\\Microsoft\\Fusion\\Installer\\1.0.0.0\\Cache\\")
  497. #define WZ_STATUS_CONFIRMED L"Confirmed"
  498. #define WZ_STATUS_COMPLETED L"Complete"
  499. #define WZ_STATUS_CRITICAL L"Critical"
  500. #define SET_VALUE 1
  501. // ---------------------------------------------------------------------------
  502. // IsStatus
  503. // return FALSE if absent
  504. // ---------------------------------------------------------------------------
  505. BOOL CAssemblyCache::IsStatus(LPWSTR pwzDisplayName, CacheStatus eStatus)
  506. {
  507. CString sStatus;
  508. HUSKEY hRegKey;
  509. DWORD dwType = 0;
  510. DWORD dwValue = -1;
  511. DWORD dwSize = sizeof(dwValue);
  512. DWORD dwDefault = -1;
  513. LPCWSTR pwzQueryString = NULL;
  514. BOOL bRelVal = FALSE;
  515. if (eStatus == COMPLETED)
  516. pwzQueryString = WZ_STATUS_COMPLETED;
  517. else if (eStatus == CONFIRMED)
  518. pwzQueryString = WZ_STATUS_CONFIRMED;
  519. else if (eStatus == CRITICAL)
  520. pwzQueryString = WZ_STATUS_CRITICAL;
  521. else
  522. {
  523. _hr = E_INVALIDARG;
  524. goto exit;
  525. }
  526. if (FAILED(_hr=sStatus.Assign(REG_KEY_FUSION_SETTINGS)))
  527. goto exit;
  528. if (FAILED(_hr=sStatus.Append(pwzDisplayName)))
  529. goto exit;
  530. // Open registry entry
  531. if (SHRegOpenUSKey(sStatus._pwz, KEY_ALL_ACCESS, NULL,
  532. &hRegKey, FALSE) != ERROR_SUCCESS)
  533. {
  534. _hr = E_FAIL;
  535. goto exit;
  536. }
  537. // Query
  538. if(SHRegQueryUSValue(hRegKey, pwzQueryString, &dwType, (LPVOID) &dwValue,
  539. &dwSize, FALSE, (LPVOID) &dwDefault, sizeof(dwDefault)) != ERROR_SUCCESS)
  540. _hr = E_FAIL;
  541. if (dwValue == SET_VALUE)
  542. bRelVal = TRUE;
  543. if(SHRegCloseUSKey(hRegKey) != ERROR_SUCCESS)
  544. _hr = E_FAIL;
  545. exit:
  546. return bRelVal;
  547. }
  548. // ---------------------------------------------------------------------------
  549. // SetStatus
  550. // ---------------------------------------------------------------------------
  551. HRESULT CAssemblyCache::SetStatus(LPWSTR pwzDisplayName, CacheStatus eStatus)
  552. {
  553. CString sStatus;
  554. HUSKEY hRegKey;
  555. DWORD dwValue = SET_VALUE;
  556. LPCWSTR pwzValueNameString = NULL;
  557. // BUGBUG: should this be in-sync with what server does to register update?
  558. if (eStatus == COMPLETED)
  559. pwzValueNameString = WZ_STATUS_COMPLETED;
  560. else if (eStatus == CONFIRMED)
  561. pwzValueNameString = WZ_STATUS_CONFIRMED;
  562. else if (eStatus == CRITICAL)
  563. pwzValueNameString = WZ_STATUS_CRITICAL;
  564. else
  565. {
  566. _hr = E_INVALIDARG;
  567. goto exit;
  568. }
  569. if (FAILED(_hr=sStatus.Assign(REG_KEY_FUSION_SETTINGS)))
  570. goto exit;
  571. if (FAILED(_hr=sStatus.Append(pwzDisplayName)))
  572. goto exit;
  573. // Create registry entry
  574. if (SHRegCreateUSKey(sStatus._pwz, KEY_ALL_ACCESS, NULL,
  575. &hRegKey, SHREGSET_FORCE_HKCU) != ERROR_SUCCESS) //SHREGSET_DEFAULT for strongly named apps?
  576. {
  577. _hr = E_FAIL;
  578. goto exit;
  579. }
  580. // Write
  581. if (SHRegWriteUSValue(hRegKey, pwzValueNameString, REG_DWORD, (LPVOID) &dwValue,
  582. sizeof(dwValue), SHREGSET_FORCE_HKCU) != ERROR_SUCCESS)
  583. _hr = E_FAIL;
  584. if (SHRegCloseUSKey(hRegKey) != ERROR_SUCCESS)
  585. _hr = E_FAIL;
  586. exit:
  587. return _hr;
  588. }
  589. // ---------------------------------------------------------------------------
  590. // CreateDirectoryHierarchy
  591. // ---------------------------------------------------------------------------
  592. HRESULT CAssemblyCache::CreateDirectoryHierarchy(LPWSTR pwzRootDir, LPWSTR pwzFilePath)
  593. {
  594. LPWSTR pwzPath, pwzEnd;
  595. CString sCombinedPath;
  596. if (pwzRootDir)
  597. sCombinedPath.Assign(pwzRootDir);
  598. sCombinedPath.Append(pwzFilePath);
  599. pwzPath = sCombinedPath._pwz;
  600. pwzEnd = pwzPath + sizeof("C:\\");
  601. while (pwzEnd = StrChr(pwzEnd, L'\\'))
  602. {
  603. *pwzEnd = L'\0';
  604. if (GetFileAttributes(pwzPath) == -1)
  605. CreateDirectory(pwzPath, NULL);
  606. *(pwzEnd++) = L'\\';
  607. }
  608. return S_OK;
  609. }
  610. // ---------------------------------------------------------------------------
  611. // GetCacheRootDir
  612. // ---------------------------------------------------------------------------
  613. HRESULT CAssemblyCache::GetCacheRootDir(CString &sCacheDir, CacheFlags eFlags)
  614. {
  615. HRESULT hr = S_OK;
  616. WCHAR wzPath[MAX_PATH];
  617. // BUGBUG?: MAX_PATH restriction. Seems reasonable in this case?
  618. if(GetEnvironmentVariable(L"ProgramFiles", wzPath, MAX_PATH/*-lstrlen(WZ_CACHE_LOCALROOTDIR)*/-1) == 0)
  619. {
  620. hr = CO_E_PATHTOOLONG;
  621. goto exit;
  622. }
  623. if (FAILED(hr = sCacheDir.Assign(wzPath)))
  624. goto exit;
  625. if (FAILED(hr = sCacheDir.PathCombine(WZ_CACHE_LOCALROOTDIR)))
  626. goto exit;
  627. if (eFlags == Staging)
  628. hr = sCacheDir.PathCombine(WZ_MANIFEST_STAGING_DIR);
  629. exit:
  630. return hr;
  631. }
  632. // IUnknown methods
  633. // ---------------------------------------------------------------------------
  634. // CAssemblyCache::QI
  635. // ---------------------------------------------------------------------------
  636. STDMETHODIMP
  637. CAssemblyCache::QueryInterface(REFIID riid, void** ppvObj)
  638. {
  639. if ( IsEqualIID(riid, IID_IUnknown)
  640. || IsEqualIID(riid, IID_IAssemblyCacheImport)
  641. )
  642. {
  643. *ppvObj = static_cast<IAssemblyCacheImport*> (this);
  644. AddRef();
  645. return S_OK;
  646. }
  647. else if (IsEqualIID(riid, IID_IAssemblyCacheEmit))
  648. {
  649. *ppvObj = static_cast<IAssemblyCacheEmit*> (this);
  650. AddRef();
  651. return S_OK;
  652. }
  653. else
  654. {
  655. *ppvObj = NULL;
  656. return E_NOINTERFACE;
  657. }
  658. }
  659. // ---------------------------------------------------------------------------
  660. // CAssemblyCache::AddRef
  661. // ---------------------------------------------------------------------------
  662. STDMETHODIMP_(ULONG)
  663. CAssemblyCache::AddRef()
  664. {
  665. return InterlockedIncrement ((LONG*) &_cRef);
  666. }
  667. // ---------------------------------------------------------------------------
  668. // CAssemblyCache::Release
  669. // ---------------------------------------------------------------------------
  670. STDMETHODIMP_(ULONG)
  671. CAssemblyCache::Release()
  672. {
  673. ULONG lRet = InterlockedDecrement ((LONG*) &_cRef);
  674. if (!lRet)
  675. delete this;
  676. return lRet;
  677. }