|
|
#include <fusenetincludes.h>
#include <assemblycache.h>
#include "..\id\sxsid.h"
#define WZ_CACHE_LOCALROOTDIR L"Application Store\\"
#define WZ_MANIFEST_STAGING_DIR L"ManifestStagingDir\\"
#define WZ_WILDCARDSTRING L"*"
extern BOOL IsEqualAssemblyFileInfo(LPASSEMBLY_FILE_INFO pAsmFileInfo1, LPASSEMBLY_FILE_INFO pAsmFileInfo2);
// ---------------------------------------------------------------------------
// CreateAssemblyCacheImport
// ---------------------------------------------------------------------------
STDAPI CreateAssemblyCacheImport( LPASSEMBLY_CACHE_IMPORT *ppAssemblyCacheImport, LPASSEMBLY_IDENTITY pAssemblyIdentity, DWORD dwFlags) { HRESULT hr = S_OK; LPWSTR pwzSearchDisplayName = NULL; BOOL bNewAsmId = FALSE; CAssemblyCache *pAssemblyCache = NULL;
pAssemblyCache = new(CAssemblyCache); if (!pAssemblyCache) { hr = E_OUTOFMEMORY; goto exit; }
if (FAILED(hr = pAssemblyCache->Init(NULL))) goto exit;
if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX_COMPLETED || dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST || dwFlags == CACHEIMP_CREATE_RESOLVE_REF || dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX || dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED) { LPWSTR pwzBuf = NULL; DWORD dwCC = 0; CString sManifestFilename; CString sDisplayName;
if (pAssemblyIdentity == NULL) { hr = E_INVALIDARG; goto exit; }
// get the identity name
if ((hr = pAssemblyIdentity->GetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_NAME, &pwzBuf, &dwCC)) != S_OK) { // BUGBUG?: should this work regardless the existence of asm name?
hr = E_INVALIDARG; goto exit; }
// filename of the manifest must be the same as the assembly name
// BUGBUG??: this implies manifest filename (and asm name) be remained unchange because
// the assembly name from the new AsmId is used for looking up in the older cached version...
sManifestFilename.TakeOwnership(pwzBuf, dwCC); if (FAILED(hr = sManifestFilename.Append(L".manifest"))) goto exit;
if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX_COMPLETED) { LPASSEMBLY_IDENTITY pNewAsmId = NULL; if (FAILED(hr = CloneAssemblyIdentity(pAssemblyIdentity, &pNewAsmId))) goto exit;
pAssemblyIdentity = pNewAsmId; bNewAsmId = TRUE; // force Version to be a wildcard
if (FAILED(hr = pAssemblyIdentity->SetAttribute(SXS_ASSEMBLY_IDENTITY_STD_ATTRIBUTE_NAME_VERSION, WZ_WILDCARDSTRING, lstrlen(WZ_WILDCARDSTRING)+1))) goto exit; }
if (dwFlags == CACHEIMP_CREATE_RETRIEVE_MAX_COMPLETED || dwFlags == CACHEIMP_CREATE_RESOLVE_REF || dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX) { // issues: what if other then Version is already wildcarded? does version comparison make sense here?
if (FAILED(hr = pAssemblyIdentity->GetDisplayName(ASMID_DISPLAYNAME_WILDCARDED, &pwzSearchDisplayName, &dwCC))) goto exit;
if (SearchForHighestVersionInCache(&pwzBuf, pwzSearchDisplayName, CAssemblyCache::COMPLETED, pAssemblyCache) == S_OK) { sDisplayName.TakeOwnership(pwzBuf); // BUGBUG - make GetDisplayName call getassemblyid/getdisplayname instead
if (FAILED(hr = (pAssemblyCache->_sDisplayName).Assign(sDisplayName))) goto exit; } else { // can't resolve
hr = S_FALSE;
if (dwFlags != CACHEIMP_CREATE_RESOLVE_REF_EX) goto exit; } }
if (dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST || dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED || (hr == S_FALSE && dwFlags == CACHEIMP_CREATE_RESOLVE_REF_EX)) { // make the name anyway if resolving a ref that does not have any completed cache counterpart
// BUGBUG: this may no longer be necessary if shortcut code/UI changes - it's expecting a path
// plus this is inefficient as it searchs the disk at above, even if ref is fully qualified
if (FAILED(hr = pAssemblyIdentity->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &dwCC))) goto exit; hr = sDisplayName.TakeOwnership(pwzBuf, dwCC);
// BUGBUG - make GetDisplayName call getassemblyid/getdisplayname instead
if (FAILED(hr = (pAssemblyCache->_sDisplayName).Assign(sDisplayName))) goto exit; } // Note: this will prepare for delay initializing _pManifestImport
if (FAILED(hr = (pAssemblyCache->_sManifestFileDir).Assign(pAssemblyCache->_sRootDir))) goto exit;
// build paths
if (FAILED(hr = (pAssemblyCache->_sManifestFileDir).Append(sDisplayName))) goto exit;
if (dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST ||dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED) { // simple check if dir is in cache or not
if (GetFileAttributes((pAssemblyCache->_sManifestFileDir)._pwz) == (DWORD)-1) { // cache dir not exists
hr = S_FALSE; goto exit; } }
if (dwFlags == CACHEIMP_CREATE_RETRIEVE_EXIST_COMPLETED) { if (!(pAssemblyCache ->IsStatus (sDisplayName._pwz, CAssemblyCache::COMPLETED))) { // cache dir not completed
hr = S_FALSE; goto exit; } }
if (FAILED(hr = (pAssemblyCache->_sManifestFileDir).Append(L"\\"))) goto exit;
if (FAILED(hr = (pAssemblyCache->_sManifestFilePath).Assign(pAssemblyCache->_sManifestFileDir))) goto exit;
if (FAILED(hr = (pAssemblyCache->_sManifestFilePath).Append(sManifestFilename))) goto exit; } exit: SAFEDELETE(pwzSearchDisplayName);
if (bNewAsmId) SAFERELEASE(pAssemblyIdentity); if (FAILED(hr) || hr == S_FALSE) { // hr == S_FALSE for not found
SAFERELEASE(pAssemblyCache); }
*ppAssemblyCacheImport = static_cast<IAssemblyCacheImport*> (pAssemblyCache);
return hr; }
// ---------------------------------------------------------------------------
// CreateAssemblyCacheEmit
// ---------------------------------------------------------------------------
STDAPI CreateAssemblyCacheEmit( LPASSEMBLY_CACHE_EMIT *ppAssemblyCacheEmit, LPASSEMBLY_CACHE_EMIT pAssemblyCacheEmit, DWORD dwFlags) { HRESULT hr = S_OK;
CAssemblyCache *pAssemblyCache = NULL;
pAssemblyCache = new(CAssemblyCache); if (!pAssemblyCache) { hr = E_OUTOFMEMORY; goto exit; }
hr = pAssemblyCache->Init(static_cast<CAssemblyCache*> (pAssemblyCacheEmit)); if (FAILED(hr)) { SAFERELEASE(pAssemblyCache); goto exit; } exit:
*ppAssemblyCacheEmit = static_cast<IAssemblyCacheEmit*> (pAssemblyCache);
return hr; }
// ---------------------------------------------------------------------------
// FindVersionInDisplayName
// ---------------------------------------------------------------------------
LPCWSTR FindVersionInDisplayName(LPCWSTR pwzDisplayName) { int cNumUnderscoreFromEndToVersionString = 2; int count = 0; int ccLen = lstrlen(pwzDisplayName); LPWSTR pwz = (LPWSTR) (pwzDisplayName+ccLen-1); LPWSTR pwzRetVal = NULL;
// return a pointer to the start of Version string inside a displayName
while (*pwz != NULL && pwz > pwzDisplayName) { if (*pwz == L'_') count++;
if (count == cNumUnderscoreFromEndToVersionString) break;
pwz--; }
if (count == cNumUnderscoreFromEndToVersionString) pwzRetVal = ++pwz;
return pwzRetVal; }
// ---------------------------------------------------------------------------
// CompareVersion
// ---------------------------------------------------------------------------
int CompareVersion(LPCWSTR pwzVersion1, LPCWSTR pwzVersion2) { // BUGBUG: this should compare version by its major minor build revision!
// possible break if V1=10.0.0.0 and V2=2.0.0.0?
// plus pwzVersion1 is something like "1.0.0.0_en"
return wcscmp(pwzVersion1, pwzVersion2); }
// ---------------------------------------------------------------------------
// SearchForHighestVersionInCache
// Look for a copy in cache that has the highest version and the specified status
// pwzSearchDisplayName should really be created from a partial ref
//
// return: S_OK - found a version from the ref
// S_FALSE - not found any version from the ref, or
// ref not partial and that version is not there/not in that status
// E_*
// ---------------------------------------------------------------------------
HRESULT SearchForHighestVersionInCache(LPWSTR *ppwzResultDisplayName, LPWSTR pwzSearchDisplayName, CAssemblyCache::CacheStatus eCacheStatus, CAssemblyCache* pCache) { HRESULT hr = S_OK; HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATA fdAppDir; DWORD dwLastError = 0; BOOL fFound = FALSE;
CString sDisplayName; CString sSearchPath;
*ppwzResultDisplayName = NULL;
sDisplayName.Assign(pwzSearchDisplayName); if (FAILED(hr=sSearchPath.Assign(pCache->_sRootDir))) goto exit;
if (FAILED(hr=sSearchPath.Append(sDisplayName))) goto exit;
hFind = FindFirstFileEx(sSearchPath._pwz, FindExInfoStandard, &fdAppDir, FindExSearchLimitToDirectories, NULL, 0); if (hFind == INVALID_HANDLE_VALUE) { hr = S_FALSE; goto exit; }
while (dwLastError != ERROR_NO_MORE_FILES) { // ???? check file attribute to see if it's a directory? needed only if the file system does not support the filter...
// ???? check version string format?
if (pCache->IsStatus(fdAppDir.cFileName, eCacheStatus)) { int iRetVal = CompareVersion(FindVersionInDisplayName(fdAppDir.cFileName), FindVersionInDisplayName(sDisplayName._pwz)); if (iRetVal > 0) { sDisplayName.Assign(fdAppDir.cFileName); fFound = TRUE; } else if (iRetVal == 0) fFound = TRUE; // else keep the newest
}
if (!FindNextFile(hFind, &fdAppDir)) { dwLastError = GetLastError(); continue; } }
if (fFound) { *ppwzResultDisplayName = sDisplayName._pwz; sDisplayName.ReleaseOwnership(); hr = S_OK; } else hr = S_FALSE;
exit: if (hFind != INVALID_HANDLE_VALUE) { if (!FindClose(hFind)) { // can return 0, even when there's an error.
DWORD dw = GetLastError(); hr = dw ? HRESULT_FROM_WIN32(dw) : E_FAIL; } }
return hr; }
// ---------------------------------------------------------------------------
// ctor
// ---------------------------------------------------------------------------
CAssemblyCache::CAssemblyCache() : _dwSig('hcac'), _cRef(1), _hr(S_OK), _pManifestImport(NULL) {}
// ---------------------------------------------------------------------------
// dtor
// ---------------------------------------------------------------------------
CAssemblyCache::~CAssemblyCache() { SAFERELEASE(_pManifestImport); }
// ---------------------------------------------------------------------------
// Init
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::Init(CAssemblyCache *pAssemblyCache) { if (!pAssemblyCache) GetCacheRootDir(_sRootDir, Base); else _sRootDir.Assign(pAssemblyCache->_sManifestFileDir);
return S_OK; }
// ---------------------------------------------------------------------------
// GetManifestFilePath
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::GetManifestFilePath(LPOLESTR *ppwzManifestFilePath, LPDWORD pccManifestFilePath) { CString sPathOut; sPathOut.Assign(_sManifestFilePath); *ppwzManifestFilePath = sPathOut._pwz; *pccManifestFilePath = sPathOut._cc; sPathOut.ReleaseOwnership(); return S_OK; }
// ---------------------------------------------------------------------------
// GetManifestFileDir
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::GetManifestFileDir(LPOLESTR *ppwzManifestFileDir, LPDWORD pccManifestFileDir) { CString sDirOut; sDirOut.Assign(_sManifestFileDir); *ppwzManifestFileDir = sDirOut._pwz; *pccManifestFileDir = sDirOut._cc; sDirOut.ReleaseOwnership(); return S_OK; }
// ---------------------------------------------------------------------------
// GetManifestImport
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::GetManifestImport(LPASSEMBLY_MANIFEST_IMPORT *ppManifestImport) { *ppManifestImport = _pManifestImport; (*ppManifestImport)->AddRef(); return S_OK; }
// ---------------------------------------------------------------------------
// GetDisplayName
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::GetDisplayName(LPOLESTR *ppwzDisplayName, LPDWORD pccDiaplyName) { CString sDisplayNameOut; sDisplayNameOut.Assign(_sDisplayName); *ppwzDisplayName = sDisplayNameOut._pwz; *pccDiaplyName= sDisplayNameOut._cc; sDisplayNameOut.ReleaseOwnership(); return S_OK; }
// ---------------------------------------------------------------------------
// FindExistMatching
// return:
// S_OK
// S_FALSE -not exist or not match
// E_*
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::FindExistMatching(LPASSEMBLY_FILE_INFO pAssemblyFileInfo, LPOLESTR *ppwzPath) { LPWSTR pwzBuf = NULL; DWORD ccBuf = 0; CString sFileName; CString sTargetPath; LPASSEMBLY_FILE_INFO pFoundFileInfo = NULL;
if (pAssemblyFileInfo == NULL || ppwzPath == NULL) { _hr = E_INVALIDARG; goto exit; } *ppwzPath = NULL;
if (_pManifestImport == NULL) { if (_sManifestFilePath._cc == 0) { // no manifest path
_hr = CO_E_NOTINITIALIZED; goto exit; }
// lazy init
if (FAILED(_hr = CreateAssemblyManifestImport(&_pManifestImport, _sManifestFilePath._pwz))) goto exit; }
// file name parsed from manifest.
if (FAILED(_hr = pAssemblyFileInfo->Get(ASM_FILE_NAME, &pwzBuf, &ccBuf))) goto exit; sFileName.TakeOwnership(pwzBuf, ccBuf);
if (FAILED(_hr = sTargetPath.Assign(_sManifestFileDir))) goto exit; if (FAILED(_hr = sTargetPath.Append(sFileName._pwz))) goto exit;
// optimization: check if the target exists
if (GetFileAttributes(sTargetPath._pwz) == (DWORD)-1) { // file doesn't exist - no point looking into the manifest file
_hr = S_FALSE; goto exit; }
// find the specified file entry in the manifest
// BUGBUG: check for missing attribute case
if (FAILED(_hr = _pManifestImport->QueryFile(sFileName._pwz, &pFoundFileInfo)) || _hr == S_FALSE) goto exit;
// check if the entries match
if (IsEqualAssemblyFileInfo(pAssemblyFileInfo, pFoundFileInfo)) { // BUGBUG:? should now check if the actual file has the matching hash etc.
*ppwzPath = sTargetPath._pwz; sTargetPath.ReleaseOwnership(); } else _hr = S_FALSE;
exit: SAFERELEASE(pFoundFileInfo); return _hr; }
// ---------------------------------------------------------------------------
// CopyFile
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::CopyFile(LPOLESTR pwzSourcePath, LPOLESTR pwzFileName, DWORD dwFlags) { LPWSTR pwzBuf = NULL; DWORD ccBuf = 0;
CString sDisplayName;
LPASSEMBLY_MANIFEST_IMPORT pManifestImport = NULL; LPASSEMBLY_IDENTITY pIdentity = NULL; LPASSEMBLY_FILE_INFO pAssemblyFile= NULL; if (dwFlags == MANIFEST) { DWORD n = 0; CreateAssemblyManifestImport(&pManifestImport, pwzSourcePath); pManifestImport->GetAssemblyIdentity(&pIdentity); pIdentity->GetDisplayName(ASMID_DISPLAYNAME_NOMANGLING, &pwzBuf, &ccBuf); sDisplayName.TakeOwnership(pwzBuf, ccBuf);
_sDisplayName.Assign(sDisplayName); // Construct target path
_sManifestFileDir.Assign(_sRootDir); _sManifestFileDir.Append(sDisplayName); _sManifestFileDir.Append(L"\\");
_sManifestFilePath.Assign(_sManifestFileDir); _sManifestFilePath.Append(pwzFileName); CreateDirectoryHierarchy(NULL, _sManifestFilePath._pwz);
// Copy the manifest from staging area into cache.
::CopyFile(pwzSourcePath, _sManifestFilePath._pwz, FALSE);
SAFERELEASE(pManifestImport); ::DeleteFile(pwzSourcePath); // Create the manifest import interface
CreateAssemblyManifestImport(&_pManifestImport, _sManifestFilePath._pwz);
// Enumerate files from manifest and pre-generate nested
// directories required for background file copy.
while (_pManifestImport->GetNextFile(n++, &pAssemblyFile) == S_OK) { CString sPath; pAssemblyFile->Get(ASM_FILE_NAME, &pwzBuf, &ccBuf); sPath.TakeOwnership(pwzBuf, ccBuf); sPath.PathNormalize(); CreateDirectoryHierarchy(_sManifestFileDir._pwz, sPath._pwz);
// RELEASE pAssebmlyFile everytime through the while loop
SAFERELEASE(pAssemblyFile); } } else { CString sTargetPath;
// Construct target path
sTargetPath.Assign(_sManifestFileDir); sTargetPath.Append(pwzFileName);
CreateDirectoryHierarchy(NULL, sTargetPath._pwz);
// Copy non-manifest files into cache. Presumably from previous cached location to the new
::CopyFile(pwzSourcePath, sTargetPath._pwz, FALSE); }
if (pIdentity) pIdentity->Release();
return _hr;
}
// ---------------------------------------------------------------------------
// Commit
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::Commit(DWORD dwFlags) { if (!(_sDisplayName._pwz)) { _hr = E_FAIL; goto exit; } // mark cache completed
_hr = SetStatus(_sDisplayName._pwz, COMPLETED);
exit:
return _hr; }
#define REG_KEY_FUSION_SETTINGS TEXT("Software\\Microsoft\\Fusion\\Installer\\1.0.0.0\\Cache\\")
#define WZ_STATUS_CONFIRMED L"Confirmed"
#define WZ_STATUS_COMPLETED L"Complete"
#define WZ_STATUS_CRITICAL L"Critical"
#define SET_VALUE 1
// ---------------------------------------------------------------------------
// IsStatus
// return FALSE if absent
// ---------------------------------------------------------------------------
BOOL CAssemblyCache::IsStatus(LPWSTR pwzDisplayName, CacheStatus eStatus) { CString sStatus; HUSKEY hRegKey; DWORD dwType = 0; DWORD dwValue = -1; DWORD dwSize = sizeof(dwValue); DWORD dwDefault = -1; LPCWSTR pwzQueryString = NULL; BOOL bRelVal = FALSE;
if (eStatus == COMPLETED) pwzQueryString = WZ_STATUS_COMPLETED; else if (eStatus == CONFIRMED) pwzQueryString = WZ_STATUS_CONFIRMED; else if (eStatus == CRITICAL) pwzQueryString = WZ_STATUS_CRITICAL; else { _hr = E_INVALIDARG; goto exit; }
if (FAILED(_hr=sStatus.Assign(REG_KEY_FUSION_SETTINGS))) goto exit;
if (FAILED(_hr=sStatus.Append(pwzDisplayName))) goto exit; // Open registry entry
if (SHRegOpenUSKey(sStatus._pwz, KEY_ALL_ACCESS, NULL, &hRegKey, FALSE) != ERROR_SUCCESS) { _hr = E_FAIL; goto exit; }
// Query
if(SHRegQueryUSValue(hRegKey, pwzQueryString, &dwType, (LPVOID) &dwValue, &dwSize, FALSE, (LPVOID) &dwDefault, sizeof(dwDefault)) != ERROR_SUCCESS) _hr = E_FAIL; if (dwValue == SET_VALUE) bRelVal = TRUE;
if(SHRegCloseUSKey(hRegKey) != ERROR_SUCCESS) _hr = E_FAIL; exit: return bRelVal; }
// ---------------------------------------------------------------------------
// SetStatus
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::SetStatus(LPWSTR pwzDisplayName, CacheStatus eStatus) { CString sStatus; HUSKEY hRegKey; DWORD dwValue = SET_VALUE; LPCWSTR pwzValueNameString = NULL; // BUGBUG: should this be in-sync with what server does to register update?
if (eStatus == COMPLETED) pwzValueNameString = WZ_STATUS_COMPLETED; else if (eStatus == CONFIRMED) pwzValueNameString = WZ_STATUS_CONFIRMED; else if (eStatus == CRITICAL) pwzValueNameString = WZ_STATUS_CRITICAL; else { _hr = E_INVALIDARG; goto exit; }
if (FAILED(_hr=sStatus.Assign(REG_KEY_FUSION_SETTINGS))) goto exit;
if (FAILED(_hr=sStatus.Append(pwzDisplayName))) goto exit; // Create registry entry
if (SHRegCreateUSKey(sStatus._pwz, KEY_ALL_ACCESS, NULL, &hRegKey, SHREGSET_FORCE_HKCU) != ERROR_SUCCESS) //SHREGSET_DEFAULT for strongly named apps?
{ _hr = E_FAIL; goto exit; }
// Write
if (SHRegWriteUSValue(hRegKey, pwzValueNameString, REG_DWORD, (LPVOID) &dwValue, sizeof(dwValue), SHREGSET_FORCE_HKCU) != ERROR_SUCCESS) _hr = E_FAIL;
if (SHRegCloseUSKey(hRegKey) != ERROR_SUCCESS) _hr = E_FAIL;
exit: return _hr; }
// ---------------------------------------------------------------------------
// CreateDirectoryHierarchy
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::CreateDirectoryHierarchy(LPWSTR pwzRootDir, LPWSTR pwzFilePath) { LPWSTR pwzPath, pwzEnd; CString sCombinedPath;
if (pwzRootDir) sCombinedPath.Assign(pwzRootDir); sCombinedPath.Append(pwzFilePath); pwzPath = sCombinedPath._pwz; pwzEnd = pwzPath + sizeof("C:\\"); while (pwzEnd = StrChr(pwzEnd, L'\\')) { *pwzEnd = L'\0'; if (GetFileAttributes(pwzPath) == -1) CreateDirectory(pwzPath, NULL); *(pwzEnd++) = L'\\'; } return S_OK;
}
// ---------------------------------------------------------------------------
// GetCacheRootDir
// ---------------------------------------------------------------------------
HRESULT CAssemblyCache::GetCacheRootDir(CString &sCacheDir, CacheFlags eFlags) { HRESULT hr = S_OK; WCHAR wzPath[MAX_PATH];
// BUGBUG?: MAX_PATH restriction. Seems reasonable in this case?
if(GetEnvironmentVariable(L"ProgramFiles", wzPath, MAX_PATH/*-lstrlen(WZ_CACHE_LOCALROOTDIR)*/-1) == 0) { hr = CO_E_PATHTOOLONG; goto exit; }
if (FAILED(hr = sCacheDir.Assign(wzPath))) goto exit; if (FAILED(hr = sCacheDir.PathCombine(WZ_CACHE_LOCALROOTDIR))) goto exit;
if (eFlags == Staging) hr = sCacheDir.PathCombine(WZ_MANIFEST_STAGING_DIR); exit: return hr; }
// IUnknown methods
// ---------------------------------------------------------------------------
// CAssemblyCache::QI
// ---------------------------------------------------------------------------
STDMETHODIMP CAssemblyCache::QueryInterface(REFIID riid, void** ppvObj) { if ( IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IAssemblyCacheImport) ) { *ppvObj = static_cast<IAssemblyCacheImport*> (this); AddRef(); return S_OK; } else if (IsEqualIID(riid, IID_IAssemblyCacheEmit)) { *ppvObj = static_cast<IAssemblyCacheEmit*> (this); AddRef(); return S_OK; } else { *ppvObj = NULL; return E_NOINTERFACE; } }
// ---------------------------------------------------------------------------
// CAssemblyCache::AddRef
// ---------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAssemblyCache::AddRef() { return InterlockedIncrement ((LONG*) &_cRef); }
// ---------------------------------------------------------------------------
// CAssemblyCache::Release
// ---------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CAssemblyCache::Release() { ULONG lRet = InterlockedDecrement ((LONG*) &_cRef); if (!lRet) delete this; return lRet; }
|