HRESULT FusionBind::LoadAssembly(IApplicationContext* pFusionContext, IAssembly** ppFusionAssembly) { HRESULT hr; TIMELINE_START(FUSIONBIND, ("LoadAssembly %s", m_pAssemblyName)); IAssemblyName* pFusionAssemblyName = NULL; IfFailGo(CreateFusionName(&pFusionAssemblyName)); hr = GetAssemblyFromFusion(pFusionContext, NULL, pFusionAssemblyName, &m_CodeInfo, ppFusionAssembly); ErrExit: if(pFusionAssemblyName) pFusionAssemblyName->Release(); TIMELINE_END(FUSIONBIND, ("LoadAssembly %s", m_pAssemblyName)); return hr; }
HRESULT FusionBind::CreateFusionContext(LPCWSTR pzName, IApplicationContext** ppFusionContext) { TIMELINE_START(FUSIONBIND, ("CreateFusionContext %S", pzName)); _ASSERTE(ppFusionContext); // This is a file name not a namespace LPCWSTR contextName = NULL; if(pzName) { contextName = wcsrchr( pzName, L'\\' ); if(contextName) contextName++; else contextName = pzName; } // We go off and create a fusion context for this application domain. // Note, once it is made it can not be modified. IAssemblyName *pFusionAssemblyName = NULL; HRESULT hr = CreateAssemblyNameObject(&pFusionAssemblyName, contextName, 0, NULL); if(SUCCEEDED(hr)) { hr = CreateApplicationContext(pFusionAssemblyName, ppFusionContext); pFusionAssemblyName->Release(); } if(pzName) TIMELINE_END(FUSIONBIND, ("CreateFusionContext %S", pzName)); else TIMELINE_END(FUSIONBIND, ("CreateFusionContext <unknown>")); return hr; }
HRESULT FusionBind::ParseName() { HRESULT hr = S_OK; if (m_fParsed || !m_pAssemblyName) return S_OK; TIMELINE_START(FUSIONBIND, ("ParseName %s", m_pAssemblyName)); IAssemblyName *pName; CQuickBytes qb; long pwNameLen = WszMultiByteToWideChar(CP_UTF8, 0, m_pAssemblyName, -1, 0, 0); LPWSTR pwName = (LPWSTR) qb.Alloc(pwNameLen*sizeof(WCHAR)); WszMultiByteToWideChar(CP_UTF8, 0, m_pAssemblyName, -1, pwName, pwNameLen); IfFailRet(CreateAssemblyNameObject(&pName, pwName, CANOF_PARSE_DISPLAY_NAME, NULL)); if (m_ownedFlags & NAME_OWNED) delete [] m_pAssemblyName; m_pAssemblyName = NULL; hr = Init(pName); pName->Release(); TIMELINE_END(FUSIONBIND, ("ParseName %s", m_pAssemblyName)); return hr; }
HRESULT AssemblySpec::InitializeSpec(mdToken kAssemblyRef, IMDInternalImport *pImport, Assembly* pAssembly) { HRESULT hr = S_OK; m_fParsed = TRUE; DWORD rid = RidFromToken(kAssemblyRef); if((rid == 0)||(rid > pImport->GetCountWithTokenKind(mdtAssemblyRef))) { BAD_FORMAT_ASSERT(!"AssemblyRef Token Out of Range"); return COR_E_BADIMAGEFORMAT; } // Hash algorithm used to find this hash is saved in Assembly def pImport->GetAssemblyRefProps(kAssemblyRef, // [IN] The AssemblyRef for which to get the properties. (const void**) &m_pbPublicKeyOrToken, // [OUT] Pointer to the public key or token. &m_cbPublicKeyOrToken, // [OUT] Count of bytes in the public key or token. &m_pAssemblyName, // [OUT] Buffer to fill with name. &m_context, // [OUT] Assembly MetaData. NULL, // [OUT] Hash blob. NULL, // [OUT] Count of bytes in the hash blob. &m_dwFlags); // [OUT] Flags. if ((!m_pAssemblyName) || (*m_pAssemblyName == 0)) { BAD_FORMAT_ASSERT(!"NULL AssemblyRef Name"); return COR_E_BADIMAGEFORMAT; } MAKE_WIDEPTR_FROMUTF8(pwName,m_pAssemblyName); if (wcschr(pwName,'\\') || wcschr(pwName,'/') || wcschr(pwName,':') || (RunningOnWin95() && ContainsUnmappableANSIChars(pwName))) { BAD_FORMAT_ASSERT(!"Bad AssemblyRef Name"); return COR_E_BADIMAGEFORMAT; } if((!m_pbPublicKeyOrToken) && (m_cbPublicKeyOrToken != 0)) { BAD_FORMAT_ASSERT(!"NULL Public Key or Token of AssemblyRef"); return COR_E_BADIMAGEFORMAT; } // Let's get the CodeBase from the caller and use it as a hint if(pAssembly && (!pAssembly->IsShared())) m_CodeInfo.SetParentAssembly(pAssembly->GetFusionAssembly()); #if defined(_DEBUG) && defined(FUSION_SUPPORTED) { // Test fusion conversion IAssemblyName *pFusionName; _ASSERTE(CreateFusionName(&pFusionName, TRUE) == S_OK); AssemblySpec testFusion; _ASSERTE(testFusion.InitializeSpec(pFusionName) == S_OK); pFusionName->Release(); } #endif // _DEBUG && FUSION_SUPPORTED return hr; }
HRESULT FusionBind::CreateFusionName(IAssemblyName **ppName, BOOL fIncludeHash) { TIMELINE_START(FUSIONBIND, ("CreateFusionName %s", m_pAssemblyName)); HRESULT hr; IAssemblyName *pFusionAssemblyName = NULL; LPWSTR pwAssemblyName = NULL; CQuickBytes qb; if (m_pAssemblyName) { long pwNameLen = WszMultiByteToWideChar(CP_UTF8, 0, m_pAssemblyName, -1, 0, 0); pwAssemblyName = (LPWSTR) qb.Alloc(pwNameLen*sizeof(WCHAR)); WszMultiByteToWideChar(CP_UTF8, 0, m_pAssemblyName, -1, pwAssemblyName, pwNameLen); } IfFailGo(CreateAssemblyNameObject(&pFusionAssemblyName, pwAssemblyName, m_fParsed || (!pwAssemblyName) ? 0 : CANOF_PARSE_DISPLAY_NAME, NULL)); if (m_fParsed) { if (m_context.usMajorVersion != (USHORT) -1) { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_MAJOR_VERSION, &m_context.usMajorVersion, sizeof(USHORT))); if (m_context.usMinorVersion != (USHORT) -1) { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_MINOR_VERSION, &m_context.usMinorVersion, sizeof(USHORT))); if (m_context.usBuildNumber != (USHORT) -1) { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_BUILD_NUMBER, &m_context.usBuildNumber, sizeof(USHORT))); if (m_context.usRevisionNumber != (USHORT) -1) IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_REVISION_NUMBER, &m_context.usRevisionNumber, sizeof(USHORT))); } } } if (m_context.szLocale) { MAKE_WIDEPTR_FROMUTF8(pwLocale,m_context.szLocale); IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_CULTURE, pwLocale, (DWORD)(wcslen(pwLocale) + 1) * sizeof (WCHAR))); } if (m_pbPublicKeyOrToken) { if (m_cbPublicKeyOrToken) { if(m_dwFlags & afPublicKey) { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_PUBLIC_KEY, m_pbPublicKeyOrToken, m_cbPublicKeyOrToken)); } else { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, m_pbPublicKeyOrToken, m_cbPublicKeyOrToken)); } } else { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0)); } } } if (m_CodeInfo.m_dwCodeBase > 0) { IfFailGo(pFusionAssemblyName->SetProperty(ASM_NAME_CODEBASE_URL, (void*)m_CodeInfo.m_pszCodeBase, m_CodeInfo.m_dwCodeBase*sizeof(WCHAR))); } *ppName = pFusionAssemblyName; TIMELINE_END(FUSIONBIND, ("CreateFusionName %s", m_pAssemblyName)); return S_OK; ErrExit: if (pFusionAssemblyName) pFusionAssemblyName->Release(); TIMELINE_END(FUSIONBIND, ("CreateFusionName %s", m_pAssemblyName)); return hr; }
HRESULT AssemblySpec::LoadAssembly(Assembly** ppAssembly, OBJECTREF* pThrowable, /*= NULL*/ OBJECTREF* pExtraEvidence, /*= NULL*/ BOOL fPolicyLoad) /*= FALSE*/ { IAssembly* pIAssembly = NULL; HRESULT hr; Assembly *pAssembly = GetAppDomain()->FindCachedAssembly(this); if(pAssembly) { if ((pExtraEvidence != NULL) && (*pExtraEvidence != NULL)) IfFailGo(SECURITY_E_INCOMPATIBLE_EVIDENCE); *ppAssembly = pAssembly; return S_FALSE; } PEFile *pFile; IfFailGo(GetAppDomain()->BindAssemblySpec(this, &pFile, &pIAssembly, &pAssembly, pExtraEvidence, pThrowable)); // Loaded by AssemblyResolve event handler if (hr == S_FALSE) { //If loaded by the AssemblyResolve event, check that // the public keys are the same as in the AR. // However, if the found assembly is a dynamically // created one, security has decided to allow it. if (m_cbPublicKeyOrToken && pAssembly->m_pManifestFile) { if (!pAssembly->m_cbPublicKey) IfFailGo(FUSION_E_PRIVATE_ASM_DISALLOWED); // Ref has the full key if (m_dwFlags & afPublicKey) { if ((m_cbPublicKeyOrToken != pAssembly->m_cbPublicKey) || memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbPublicKey, m_cbPublicKeyOrToken)) IfFailGo(FUSION_E_REF_DEF_MISMATCH); } // Ref has a token else if (pAssembly->m_cbRefedPublicKeyToken) { if ((m_cbPublicKeyOrToken != pAssembly->m_cbRefedPublicKeyToken) || memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbRefedPublicKeyToken, m_cbPublicKeyOrToken)) IfFailGo(FUSION_E_REF_DEF_MISMATCH); } else { if (!StrongNameTokenFromPublicKey(pAssembly->m_pbPublicKey, pAssembly->m_cbPublicKey, &pAssembly->m_pbRefedPublicKeyToken, &pAssembly->m_cbRefedPublicKeyToken)) IfFailGo(StrongNameErrorInfo()); if ((m_cbPublicKeyOrToken != pAssembly->m_cbRefedPublicKeyToken) || memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbRefedPublicKeyToken, m_cbPublicKeyOrToken)) IfFailGo(FUSION_E_REF_DEF_MISMATCH); } } *ppAssembly = pAssembly; return S_OK; } // Until we can create multiple Assembly objects for a single HMODULE // we can only store one IAssembly* per Assembly. It is very important // to maintain the IAssembly* for an image that is in the load-context. // An Assembly in the load-from-context can bind to an assembly in the // load-context but not visa-versa. Therefore, if we every get an IAssembly // from the load-from-context we must make sure that it will never be // found using a load. If it did then we could end up with Assembly dependencies // that are wrong. For example, if I do a LoadFrom() on an assembly in the GAC // and it requires another Assembly that I have preloaded in the load-from-context // then that dependency gets burnt into the Jitted code. Later on a Load() is // done on the assembly in the GAC and we single instance it back to the one // we have gotten from the load-from-context because the HMODULES are the same. // Now the dependency is wrong because it would not have the preloaded assembly // if the order was reversed. if (pIAssembly) { IFusionLoadContext *pLoadContext; hr = pIAssembly->GetFusionLoadContext(&pLoadContext); _ASSERTE(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { if (pLoadContext->GetContextType() == LOADCTX_TYPE_LOADFROM) { mdAssembly mda; if (FAILED(pFile->GetMDImport()->GetAssemblyFromScope(&mda))) { hr = COR_E_ASSEMBLYEXPECTED; goto exit; } LPCUTF8 psName; PBYTE pbPublicKey; DWORD cbPublicKey; AssemblyMetaDataInternal context; DWORD dwFlags; pFile->GetMDImport()->GetAssemblyProps(mda, (const void**) &pbPublicKey, &cbPublicKey, NULL, // hash alg &psName, &context, &dwFlags); AssemblySpec spec; if (FAILED(hr = spec.Init(psName, &context, pbPublicKey, cbPublicKey, dwFlags))) goto exit; IAssemblyName* pFoundAssemblyName; if (FAILED(hr = spec.CreateFusionName(&pFoundAssemblyName, FALSE))) goto exit; AssemblySink* pFoundSink = GetAppDomain()->GetAssemblySink(); if(!pFoundSink) { pFoundAssemblyName->Release(); hr = E_OUTOFMEMORY; goto exit; } IAssembly *pFoundIAssembly; BEGIN_ENSURE_PREEMPTIVE_GC(); hr = FusionBind::GetAssemblyFromFusion(GetAppDomain()->GetFusionContext(), pFoundSink, pFoundAssemblyName, &spec.m_CodeInfo, &pFoundIAssembly); if(SUCCEEDED(hr)) { DWORD dwFoundSize = MAX_PATH; WCHAR wszFoundPath[MAX_PATH]; // Get the path to the module containing the manifest if (SUCCEEDED(pFoundIAssembly->GetManifestModulePath(wszFoundPath, &dwFoundSize))) { // Keep the default context's IAssembly if the paths are the same if (!_wcsicmp(wszFoundPath, pFile->GetFileName())) { pIAssembly->Release(); pIAssembly = pFoundIAssembly; // Make sure the new IAssembly isn't holding its own refcount on // the file (we've just verified we're holding the same file.) // Otherwise we will leak the handle when we unload the assembly, // assuming fusion decides to cache this IAssembly pointer // somewhere internally. PEFile::ReleaseFusionMetadataImport(pFoundIAssembly); } else pFoundIAssembly->Release(); } } pFoundAssemblyName->Release(); pFoundSink->Release(); END_ENSURE_PREEMPTIVE_GC(); hr = S_OK; } exit: pLoadContext->Release(); } } // Create the assembly and delay loading the main module. Module* pModule; hr = GetAppDomain()->LoadAssembly(pFile, pIAssembly, &pModule, &pAssembly, pExtraEvidence, fPolicyLoad, pThrowable); BEGIN_ENSURE_PREEMPTIVE_GC(); if(SUCCEEDED(hr)) { *ppAssembly = pAssembly; /*HRESULT hrLoose =*/ GetAppDomain()->AddAssemblyToCache(this, pAssembly); } if(pIAssembly) pIAssembly->Release(); END_ENSURE_PREEMPTIVE_GC(); ErrExit: if (FAILED(hr) && (pThrowable!=NULL)) { BEGIN_ENSURE_COOPERATIVE_GC(); if ((pThrowable != RETURN_ON_ERROR) && (*pThrowable == NULL)) { if (m_pAssemblyName) PostFileLoadException(m_pAssemblyName, FALSE,NULL, hr, pThrowable); else { MAKE_UTF8PTR_FROMWIDE(szName, m_CodeInfo.m_pszCodeBase); PostFileLoadException(szName, TRUE,NULL, hr, pThrowable); } } END_ENSURE_COOPERATIVE_GC(); } return hr; }
HRESULT AssemblySpec::GetAssemblyFromFusion(AppDomain* pAppDomain, IAssemblyName* pFusionAssemblyName, CodeBaseInfo* pCodeBase, IAssembly** ppFusionAssembly, PEFile** ppFile, CQuickWSTR* pFusionLog, OBJECTREF* pExtraEvidence, OBJECTREF* pThrowable) { _ASSERTE(ppFile); HRESULT hr = S_OK; IAssembly *pFusionAssembly = NULL; COMPLUS_TRY { DWORD dwSize = MAX_PATH; CQuickWSTR bufferPath; WCHAR *pPath = NULL; AssemblySink* pSink; DWORD eLocation; CQuickWSTR bufferCodebase; LPWSTR pwsCodeBase = NULL; DWORD dwCodeBase = 0; IAssemblyName *pNameDef = NULL; IApplicationContext *pFusionContext = pAppDomain->GetFusionContext(); pSink = pAppDomain->GetAssemblySink(); if(!pSink) { hr = E_OUTOFMEMORY; COMPLUS_LEAVE; } pSink->pFusionLog=pFusionLog; hr = FusionBind::GetAssemblyFromFusion(pFusionContext, pSink, pFusionAssemblyName, pCodeBase, &pFusionAssembly); pSink->pFusionLog=NULL; if(SUCCEEDED(hr)) { _ASSERTE(pFusionAssembly); // Get the path to the module containing the manifest dwSize = bufferPath.MaxSize(); pPath = bufferPath.Ptr(); hr = pFusionAssembly->GetManifestModulePath(pPath, &dwSize); if(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { pPath = bufferPath.Alloc(dwSize); if (pPath == NULL) { hr = E_OUTOFMEMORY; COMPLUS_LEAVE; } hr = pFusionAssembly->GetManifestModulePath(pPath, &dwSize); } if(SUCCEEDED(hr)) { hr = pFusionAssembly->GetAssemblyNameDef(&pNameDef); if (SUCCEEDED(hr)) { dwCodeBase = bufferCodebase.MaxSize(); pwsCodeBase = bufferCodebase.Ptr(); hr = pNameDef->GetProperty(ASM_NAME_CODEBASE_URL, pwsCodeBase, &dwCodeBase); if(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { pwsCodeBase = bufferCodebase.Alloc(dwCodeBase); if (pwsCodeBase == NULL) { hr = E_OUTOFMEMORY; COMPLUS_LEAVE; } hr = pNameDef->GetProperty(ASM_NAME_CODEBASE_URL, pwsCodeBase, &dwCodeBase); } pNameDef->Release(); } } } pSink->Release(); if(hr == S_OK && dwSize) { // See if we need to perform a strong name verification. hr = pFusionAssembly->GetAssemblyLocation(&eLocation); if (SUCCEEDED(hr)) { switch ((eLocation & ASMLOC_LOCATION_MASK)) { case ASMLOC_GAC: case ASMLOC_DOWNLOAD_CACHE: case ASMLOC_UNKNOWN: // Assemblies from the GAC or download cache have // already been verified by Fusion. Location Unknown // indicates a load from the dev path, which we'll // assume isn't a interesting case for verification. hr = S_OK; break; case ASMLOC_RUN_FROM_SOURCE: // For now, just verify these every time, we need to // cache the fact that at least one verification has // been performed (if strong name policy permits if (SUCCEEDED(hr)&&(eLocation&ASMLOC_CODEBASE_HINT)) { hr=CheckFileAccess(pPath,FILE_READ_DATA); if (FAILED(hr)) break; } // caching of verification results). if (StrongNameSignatureVerification(pPath, SN_INFLAG_INSTALL|SN_INFLAG_ALL_ACCESS|SN_INFLAG_RUNTIME, NULL)) hr = S_OK; else { hr = StrongNameErrorInfo(); if (hr == CORSEC_E_MISSING_STRONGNAME) hr = S_OK; else hr = CORSEC_E_INVALID_STRONGNAME; } break; default: _ASSERTE(FALSE); } if (SUCCEEDED(hr)) { hr = SystemDomain::LoadFile(pPath, NULL, mdFileNil, FALSE, pFusionAssembly, pwsCodeBase, pExtraEvidence, ppFile, FALSE); if (SUCCEEDED(hr)) { if(ppFusionAssembly) { pFusionAssembly->AddRef(); *ppFusionAssembly = pFusionAssembly; } if((eLocation & ASMLOC_LOCATION_MASK) == ASMLOC_GAC) // Assemblies in the GAC have also had any internal module // hashes verified at install time. (*ppFile)->SetHashesVerified(); } } } else if (hr == E_NOTIMPL) { // process exe _ASSERTE(pAppDomain == SystemDomain::System()->DefaultDomain()); hr = PEFile::Clone(SystemDomain::System()->DefaultDomain()->m_pRootFile, ppFile); if(SUCCEEDED(hr) && ppFusionAssembly) { pFusionAssembly->AddRef(); *ppFusionAssembly = pFusionAssembly; } } } } COMPLUS_CATCH { BEGIN_ENSURE_COOPERATIVE_GC(); if (pThrowable) { *pThrowable = GETTHROWABLE(); hr = SecurityHelper::MapToHR(*pThrowable); } else hr = SecurityHelper::MapToHR(GETTHROWABLE()); END_ENSURE_COOPERATIVE_GC(); } COMPLUS_END_CATCH if (pFusionAssembly) pFusionAssembly->Release(); return hr; }
HRESULT AssemblySpec::LowLevelLoadManifestFile(PEFile** ppFile, IAssembly** ppIAssembly, Assembly **ppDynamicAssembly, OBJECTREF* pExtraEvidence, OBJECTREF* pThrowable) { CANNOTTHROWCOMPLUSEXCEPTION(); HRESULT hr = S_OK; IAssemblyName* pFusionAssemblyName = NULL; // Assembly object to assembly in fusion cache if(!(m_pAssemblyName || m_CodeInfo.m_pszCodeBase)) { PostFileLoadException("", FALSE, NULL, COR_E_FILENOTFOUND, pThrowable); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } // // Check to see if this fits our rather loose idea of a reference to mscorlib. // If so, don't use fusion to bind it - do it ourselves. // if (IsMscorlib()) { _ASSERTE(wcslen(SystemDomain::System()->BaseLibrary()) > 0); hr = PEFile::Create(SystemDomain::System()->BaseLibrary(), NULL, mdFileNil, TRUE, NULL, NULL, // Code base is the same as the name NULL, // Extra Evidence ppFile); _ASSERTE((*ppFile)->IsSystem()); if (ppDynamicAssembly) *ppDynamicAssembly = NULL; return hr; } CQuickWSTR FusionLog; FusionLog.Ptr()[0]=L'\0'; BEGIN_ENSURE_PREEMPTIVE_GC(); Assembly *pAssembly = NULL; PEFile *pFile = NULL; hr = CreateFusionName(&pFusionAssemblyName); if (FAILED(hr)) goto exit; hr = pFusionAssemblyName->SetProperty(ASM_NAME_NULL_CUSTOM,NULL,0); //do not look in ZAP if (FAILED(hr)) goto exit; hr = GetAssemblyFromFusion(GetAppDomain(), pFusionAssemblyName, &m_CodeInfo, ppIAssembly, &pFile, &FusionLog, pExtraEvidence, pThrowable); if(FAILED(hr)) { DWORD cb = 0; pFusionAssemblyName->GetDisplayName(NULL, &cb, 0); if(cb) { CQuickBytes qb; LPWSTR pwsFullName = (LPWSTR) qb.Alloc(cb*sizeof(WCHAR)); if (SUCCEEDED(pFusionAssemblyName->GetDisplayName(pwsFullName, &cb, 0))) { if ((pAssembly = GetAppDomain()->RaiseAssemblyResolveEvent(pwsFullName, pThrowable)) != NULL) { pFile = pAssembly->GetManifestFile(); hr = S_FALSE; } } } #ifdef _DEBUG if(FAILED(hr)) { if (m_pAssemblyName) LOG((LF_CLASSLOADER, LL_ERROR, "Fusion could not load from full name, %s\n", m_pAssemblyName)); else if (m_CodeInfo.m_pszCodeBase) LOG((LF_CLASSLOADER, LL_ERROR, "Fusion could not load from codebase, %s\n",m_CodeInfo.m_pszCodeBase)); else LOG((LF_CLASSLOADER, LL_ERROR, "Fusion could not load unknown assembly.\n")); } #endif //_DEBUG } exit: if (SUCCEEDED(hr)) { if (ppFile) *ppFile = pFile; if (ppDynamicAssembly) *ppDynamicAssembly = pAssembly; } if(pFusionAssemblyName) pFusionAssemblyName->Release(); END_ENSURE_PREEMPTIVE_GC(); if (FAILED(hr)) { if (m_pAssemblyName) PostFileLoadException(m_pAssemblyName, FALSE,FusionLog.Ptr(), hr, pThrowable); else { MAKE_UTF8PTR_FROMWIDE(szName, m_CodeInfo.m_pszCodeBase); PostFileLoadException(szName, TRUE,FusionLog.Ptr(), hr, pThrowable); } } return hr; }
void AsmMan::EndAssembly() { if(m_pCurAsmRef) { if(m_pCurAsmRef->isRef) { // list the assembly ref if(GetAsmRefByName(m_pCurAsmRef->szAlias)) { //report->warn("Multiple declarations of Assembly Ref '%s', ignored except the 1st one\n",m_pCurAsmRef->szName); delete m_pCurAsmRef; m_pCurAsmRef = NULL; return; } if(m_pCurAsmRef->isAutodetect) { IAssemblyName* pIAsmName; HRESULT hr; // Convert name to Unicode WszMultiByteToWideChar(g_uCodePage,0,m_pCurAsmRef->szName,-1,wzUniBuf,dwUniBuf); hr = CreateAssemblyNameObject(&pIAsmName,wzUniBuf,CANOF_PARSE_DISPLAY_NAME,NULL); if(SUCCEEDED(hr)) { // set enumeration criteria: what is known about AsmRef (besides name) if(m_pCurAsmRef->usVerMajor != (USHORT)0xFFFF) pIAsmName->SetProperty(ASM_NAME_MAJOR_VERSION,&(m_pCurAsmRef->usVerMajor),2); if(m_pCurAsmRef->usVerMinor != (USHORT)0xFFFF) pIAsmName->SetProperty(ASM_NAME_MINOR_VERSION,&(m_pCurAsmRef->usVerMinor),2); if(m_pCurAsmRef->usBuild != (USHORT)0xFFFF) pIAsmName->SetProperty(ASM_NAME_BUILD_NUMBER,&(m_pCurAsmRef->usBuild),2); if(m_pCurAsmRef->usRevision != (USHORT)0xFFFF) pIAsmName->SetProperty(ASM_NAME_REVISION_NUMBER,&(m_pCurAsmRef->usRevision),2); if(m_pCurAsmRef->pPublicKeyToken) pIAsmName->SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, m_pCurAsmRef->pPublicKeyToken->ptr(), m_pCurAsmRef->pPublicKeyToken->length()); if(m_pCurAsmRef->pLocale) pIAsmName->SetProperty(ASM_NAME_CULTURE, m_pCurAsmRef->pLocale->ptr(), m_pCurAsmRef->pLocale->length()); // enumerate assemblies IAssemblyEnum* pIAsmEnum = NULL; hr = CreateAssemblyEnum(&pIAsmEnum, NULL, pIAsmName, ASM_CACHE_GAC, NULL); if(SUCCEEDED(hr)) { IAssemblyName* pIAsmNameFound; IAssemblyName* pIAsmNameLatestVer = NULL; ULONGLONG ullVer=0, ullVerLatest=0; DWORD dwVerHi, dwVerLo; // find the latest and greatest, if any for(;;) { pIAsmNameFound = NULL; hr = pIAsmEnum->GetNextAssembly(NULL,&pIAsmNameFound,0); if(SUCCEEDED(hr) && pIAsmNameFound) { pIAsmNameFound->GetVersion(&dwVerHi,&dwVerLo); ullVer = (ULONGLONG)dwVerHi; ullVer <<= sizeof(DWORD); ullVer |= dwVerLo; if(ullVer > ullVerLatest) { if(pIAsmNameLatestVer) pIAsmNameLatestVer->Release(); ullVerLatest = ullVer; pIAsmNameLatestVer = pIAsmNameFound; } else pIAsmNameFound->Release(); } else break; } // if found, fill the gaps if(pIAsmNameLatestVer) { DWORD cbSize=0; USHORT usDummy=0; if(m_pCurAsmRef->pPublicKeyToken == NULL) { cbSize = 1024; pIAsmNameLatestVer->GetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, wzUniBuf, &cbSize); if(cbSize) { if((m_pCurAsmRef->pPublicKeyToken = new BinStr())) memcpy(m_pCurAsmRef->pPublicKeyToken->getBuff(cbSize), wzUniBuf, cbSize); } } if(m_pCurAsmRef->usVerMajor == (USHORT)0xFFFF) { cbSize = (DWORD)sizeof(WORD); pIAsmNameLatestVer->GetProperty(ASM_NAME_MAJOR_VERSION, &usDummy, &cbSize); m_pCurAsmRef->usVerMajor = usDummy; } if(m_pCurAsmRef->usVerMinor == (USHORT)0xFFFF) { cbSize = (DWORD)sizeof(WORD); pIAsmNameLatestVer->GetProperty(ASM_NAME_MINOR_VERSION, &usDummy, &cbSize); m_pCurAsmRef->usVerMinor = usDummy; } if(m_pCurAsmRef->usBuild == (USHORT)0xFFFF) { cbSize = (DWORD)sizeof(WORD); pIAsmNameLatestVer->GetProperty(ASM_NAME_BUILD_NUMBER, &usDummy, &cbSize); m_pCurAsmRef->usBuild = usDummy; } if(m_pCurAsmRef->usRevision == (USHORT)0xFFFF) { cbSize = (DWORD)sizeof(WORD); pIAsmNameLatestVer->GetProperty(ASM_NAME_REVISION_NUMBER, &usDummy, &cbSize); m_pCurAsmRef->usRevision = usDummy; } if(m_pCurAsmRef->pLocale == NULL) { cbSize = 1024; pIAsmNameLatestVer->GetProperty(ASM_NAME_CULTURE, wzUniBuf, &cbSize); if(cbSize > (DWORD)sizeof(WCHAR)) { if((m_pCurAsmRef->pLocale = new BinStr())) memcpy(m_pCurAsmRef->pLocale->getBuff(cbSize), wzUniBuf, cbSize); } } pIAsmNameLatestVer->Release(); } else report->warn("Failed to autodetect assembly '%s'\n",m_pCurAsmRef->szName); // if no assembly found, leave it as is, it might be not a GAC assembly pIAsmEnum->Release(); } else report->error("Failed to enum assemblies %S, hr=0x%08X\n",wzUniBuf,hr); pIAsmName->Release(); } else report->error("Failed to create assembly name object for %S, hr=0x%08X\n",wzUniBuf,hr); } // end if isAutodetect m_AsmRefLst.PUSH(m_pCurAsmRef); m_pCurAsmRef->tkTok = TokenFromRid(m_AsmRefLst.COUNT(),mdtAssemblyRef); } else { HRESULT hr = S_OK; m_pCurAsmRef->tkTok = TokenFromRid(1,mdtAssembly); // Determine the strong name public key. This may have been set // via a directive in the source or from the command line (which // overrides the directive). From the command line we may have // been provided with a file or the name of a CAPI key // container. Either may contain a public key or a full key // pair. if (((Assembler*)m_pAssembler)->m_wzKeySourceName) { { // Read public key or key pair from file. HANDLE hFile = WszCreateFile(((Assembler*)m_pAssembler)->m_wzKeySourceName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if(hFile == INVALID_HANDLE_VALUE) { hr = GetLastError(); report->error("Failed to open key file '%S': 0x%08X\n",((Assembler*)m_pAssembler)->m_wzKeySourceName,hr); m_pCurAsmRef = NULL; return; } // Determine file size and allocate an appropriate buffer. m_sStrongName.m_cbPublicKey = SafeGetFileSize(hFile, NULL); if (m_sStrongName.m_cbPublicKey == 0xffffffff) { report->error("File size too large\n"); m_pCurAsmRef = NULL; CloseHandle(hFile); return; } m_sStrongName.m_pbPublicKey = new BYTE[m_sStrongName.m_cbPublicKey]; if (m_sStrongName.m_pbPublicKey == NULL) { report->error("Failed to allocate key buffer\n"); m_pCurAsmRef = NULL; CloseHandle(hFile); return; } m_sStrongName.m_dwPublicKeyAllocated = 2; // Read the file into the buffer. DWORD dwBytesRead; if (!ReadFile(hFile, m_sStrongName.m_pbPublicKey, m_sStrongName.m_cbPublicKey, &dwBytesRead, NULL)) { hr = GetLastError(); report->error("Failed to read key file '%S': 0x%08X\n",((Assembler*)m_pAssembler)->m_wzKeySourceName,hr); m_pCurAsmRef = NULL; CloseHandle(hFile); return; } CloseHandle(hFile); // Guess whether we're full or delay signing based on // whether the blob passed to us looks like a public // key. (I.e. we may just have copied a full key pair // into the public key buffer). if (m_sStrongName.m_cbPublicKey >= sizeof(PublicKeyBlob) && (offsetof(PublicKeyBlob, PublicKey) + ((PublicKeyBlob*)m_sStrongName.m_pbPublicKey)->cbPublicKey) == m_sStrongName.m_cbPublicKey) m_sStrongName.m_fFullSign = FALSE; else m_sStrongName.m_fFullSign = TRUE; // If we really have a key pair, we'll move it into a // key container so the signing code gets the key pair // from a consistent place. if (m_sStrongName.m_fFullSign) { m_sStrongName.m_pbPrivateKey = m_sStrongName.m_pbPublicKey; m_sStrongName.m_cbPrivateKey = m_sStrongName.m_cbPublicKey; m_sStrongName.m_pbPublicKey = NULL; m_sStrongName.m_cbPublicKey = NULL; m_sStrongName.m_dwPublicKeyAllocated = 0; // Retrieve the public key portion as a byte blob. if (!StrongNameGetPublicKey(NULL, m_sStrongName.m_pbPrivateKey, m_sStrongName.m_cbPrivateKey, &m_sStrongName.m_pbPublicKey, &m_sStrongName.m_cbPublicKey)) { hr = StrongNameErrorInfo(); report->error("Failed to extract public key: 0x%08X\n",hr); m_pCurAsmRef = NULL; return; } m_sStrongName.m_dwPublicKeyAllocated = 2; } } } else if (m_pAssembly->pPublicKey) { m_sStrongName.m_pbPublicKey = m_pAssembly->pPublicKey->ptr(); m_sStrongName.m_cbPublicKey = m_pAssembly->pPublicKey->length(); m_sStrongName.m_wzKeyContainer = NULL; m_sStrongName.m_fFullSign = FALSE; m_sStrongName.m_dwPublicKeyAllocated = 0; } else { m_sStrongName.m_pbPublicKey = NULL; m_sStrongName.m_cbPublicKey = 0; m_sStrongName.m_wzKeyContainer = NULL; m_sStrongName.m_fFullSign = FALSE; m_sStrongName.m_dwPublicKeyAllocated = 0; } } m_pCurAsmRef = NULL; } ((Assembler*)m_pAssembler)->m_pCustomDescrList = ((Assembler*)m_pAssembler)->m_CustomDescrListStack.POP(); }