//--------------------------------------------------------------------------------------- // // Initialize the static instance and lock. // HRESULT LOADEDMODULES::InitializeStatics() { HRESULT hr = S_OK; if (VolatileLoad(&s_pLoadedModules) == NULL) { // Initialize global read-write lock { NewHolder<UTSemReadWrite> pSemReadWrite = new (nothrow) UTSemReadWrite(); IfNullGo(pSemReadWrite); IfFailGo(pSemReadWrite->Init()); if (InterlockedCompareExchangeT<UTSemReadWrite *>(&m_pSemReadWrite, pSemReadWrite, NULL) == NULL) { // We won the initialization race pSemReadWrite.SuppressRelease(); } } // Initialize the global instance { NewHolder<LOADEDMODULES> pLoadedModules = new (nothrow) LOADEDMODULES(); IfNullGo(pLoadedModules); { LOCKWRITE(); if (VolatileLoad(&s_pLoadedModules) == NULL) { VolatileStore(&s_pLoadedModules, pLoadedModules.Extract()); } } } } ErrExit: return hr; } // LOADEDMODULES::InitializeStatics
//===================================================================================================================== HRESULT CLRPrivBinderAppX::BindAppXAssemblyByNameWorker( IAssemblyName * pIAssemblyName, DWORD dwAppXBindFlags, CLRPrivAssemblyAppX ** ppAssembly) { STANDARD_VM_CONTRACT; HRESULT hr = S_OK; fusion::logging::StatusScope logStatus(0, ID_FUSLOG_BINDING_STATUS_IMMERSIVE, &hr); VALIDATE_ARG_RET(pIAssemblyName != nullptr); VALIDATE_ARG_RET((dwAppXBindFlags & ABF_BindIL) == ABF_BindIL); VALIDATE_ARG_RET(ppAssembly != nullptr); DWORD dwContentType = AssemblyContentType_Default; IfFailRet(hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CONTENT_TYPE, &dwContentType)); if ((hr == S_OK) && (dwContentType != AssemblyContentType_Default)) { IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT); } ReleaseHolder<CLRPrivAssemblyAppX> pAssembly; // Get the simple name. WCHAR wzSimpleName[_MAX_PATH]; DWORD cchSimpleName = _MAX_PATH; IfFailRet(pIAssemblyName->GetName(&cchSimpleName, wzSimpleName)); { // Look for previous successful bind. Host callouts are now forbidden. ForbidSuspendThreadCrstHolder lock(&m_MapReadLock); pAssembly = clr::SafeAddRef(m_NameToAssemblyMap.Lookup(wzSimpleName)); } if (pAssembly == nullptr) { ReleaseHolder<ICLRPrivResource> pResourceIL; ReleaseHolder<ICLRPrivResource> pResourceNI; // Create assembly identity using the simple name. For successful binds this will be updated // with the full assembly identity in the VerifyBind callback. NewHolder<AssemblyIdentity> pIdentity = new AssemblyIdentity(); IfFailRet(pIdentity->Initialize(wzSimpleName)); // // Check the head package first to see if this matches an EXE, then check // all packages to see if this matches a DLL. // WCHAR wzFilePath[_MAX_PATH]; { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); if (FAILED(hr)) { // Create simple name with .EXE extension WCHAR wzSimpleFileName[_MAX_PATH]; wcscpy_s(wzSimpleFileName, NumItems(wzSimpleFileName), wzSimpleName); wcscat_s(wzSimpleFileName, NumItems(wzSimpleFileName), W(".EXE")); // Search for the file using AppX::FileFileInCurrentPackage helper. UINT32 cchFilePath = NumItems(wzFilePath); hr = AppX::FindFileInCurrentPackage( wzSimpleFileName, &cchFilePath, wzFilePath, PACKAGE_FILTER_CLR_DEFAULT, (PCWSTR *)(void *)m_rgAltPaths, m_cAltPaths, m_pParentBinder != NULL ? AppX::FindFindInPackageFlags_SkipCurrentPackageGraph : AppX::FindFindInPackageFlags_None); } if (FAILED(hr)) { // Create simple name with .DLL extension WCHAR wzSimpleFileName[_MAX_PATH]; wcscpy_s(wzSimpleFileName, NumItems(wzSimpleFileName), wzSimpleName); wcscat_s(wzSimpleFileName, NumItems(wzSimpleFileName), W(".DLL")); // Search for the file using AppX::FileFileInCurrentPackage helper UINT32 cchFilePath = NumItems(wzFilePath); hr = AppX::FindFileInCurrentPackage( wzSimpleFileName, &cchFilePath, wzFilePath, PACKAGE_FILTER_CLR_DEFAULT, (PCWSTR *)(void *)m_rgAltPaths, m_cAltPaths, m_pParentBinder != NULL ? AppX::FindFindInPackageFlags_SkipCurrentPackageGraph : AppX::FindFindInPackageFlags_None); } if (SUCCEEDED(hr)) { fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FOUND, wzFilePath); } else { // Cache the bind failure result before returning. Careful not to overwrite the bind result with the cache insertion result. HRESULT hrResult = hr; IfFailRet(CacheBindResult(pIdentity, hr)); if (hr == S_OK) { // Cache now owns identity object lifetime. pIdentity.SuppressRelease(); } hr = hrResult; } IfFailRet(hr); } NewHolder<CLRPrivResourcePathImpl> pResourcePath = new CLRPrivResourcePathImpl(wzFilePath); IfFailRet(pResourcePath->QueryInterface(__uuidof(ICLRPrivResource), (LPVOID*)&pResourceIL)); pResourcePath.SuppressRelease(); // Create an IBindResult and provide it to the new CLRPrivAssemblyAppX object. ReleaseHolder<IBindResult> pIBindResult = ToInterface<IBindResult>( new CLRPrivAssemblyBindResultWrapper(pIAssemblyName, wzFilePath, m_pFingerprintFactory)); // Create the new CLRPrivAssemblyAppX object. NewHolder<CLRPrivAssemblyAppX> pAssemblyObj = new CLRPrivAssemblyAppX(pIdentity, this, pResourceIL, pIBindResult); // // Check cache. If someone beat us then use it instead; otherwise add new ICLRPrivAssembly. // do { // Because the read lock must be taken within a ForbidSuspend region, use AddInPhases. if (m_NameToAssemblyMap.CheckAddInPhases<ForbidSuspendThreadCrstHolder, CrstHolder>( pAssemblyObj, m_MapReadLock, m_MapWriteLock, pAssemblyObj.GetValue())) { { // Careful not to allow the cache insertion result to overwrite the bind result. HRESULT hrResult = hr; IfFailRet(CacheBindResult(pIdentity, hr)); if (hr == S_OK) { // Cache now owns identity object lifetime, but ~CLRPrivBinderAssembly // can also remove the identity from the cache prior to cache deletion. pIdentity.SuppressRelease(); } hr = hrResult; } pAssembly = pAssemblyObj.Extract(); } else { ForbidSuspendThreadCrstHolder lock(&m_MapReadLock); pAssembly = clr::SafeAddRef(m_NameToAssemblyMap.Lookup(wzSimpleName)); } } while (pAssembly == nullptr); // Keep looping until we find the existing one, or add a new one } _ASSERTE(pAssembly != nullptr); if (((dwAppXBindFlags & ABF_BindNI) == ABF_BindNI) && m_fCanUseNativeImages) { // // Look to see if there's a native image available. // // Fire BindingNgenPhaseStart ETW event if enabled. { InlineSString<128> ssAssemblyName; FireEtwBindingNgenPhaseStart( (AppDomain::GetCurrentDomain()->GetId().m_dwId), LOADCTX_TYPE_HOSTED, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, NULL, FusionBind::GetAssemblyNameDisplayName(pIAssemblyName, ssAssemblyName, ASM_DISPLAYF_FULL).GetUnicode(), GetClrInstanceId()); } ReleaseHolder<IBindResult> pIBindResultIL; IfFailRet(pAssembly->GetIBindResult(&pIBindResultIL)); _ASSERTE(pIBindResultIL != nullptr); NewArrayHolder<WCHAR> wzZapSet = DuplicateStringThrowing(g_pConfig->ZapSet()); NativeConfigData cfgData = { wzZapSet, PEFile::GetNativeImageConfigFlags() }; IfFailRet(BindToNativeAssembly( pIBindResultIL, &cfgData, static_cast<IBindContext*>(this), fusion::logging::GetCurrentFusionBindLog())); // Ensure that the native image found above in BindToNativeAssembly is reported as existing in the CLRPrivAssembly object if (hr == S_OK) { ReleaseHolder<ICLRPrivResource> pNIImageResource; // This will make GetAvailableImageTypes return that a native image exists. IfFailRet(pAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, NULL, &pNIImageResource)); #ifdef _DEBUG DWORD dwImageTypes; _ASSERTE(SUCCEEDED(pAssembly->GetAvailableImageTypes(&dwImageTypes))); _ASSERTE((dwImageTypes & ASSEMBLY_IMAGE_TYPE_NATIVE) == ASSEMBLY_IMAGE_TYPE_NATIVE); #endif } // Fire BindingNgenPhaseEnd ETW event if enabled. { InlineSString<128> ssAssemblyName; FireEtwBindingNgenPhaseEnd( (AppDomain::GetCurrentDomain()->GetId().m_dwId), LOADCTX_TYPE_HOSTED, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, NULL, FusionBind::GetAssemblyNameDisplayName(pIAssemblyName, ssAssemblyName, ASM_DISPLAYF_FULL).GetUnicode(), GetClrInstanceId()); } // BindToNativeAssembly can return S_FALSE, but this could be misleading. if (hr == S_FALSE) hr = S_OK; } if (SUCCEEDED(hr)) { *ppAssembly = pAssembly.Extract(); } return hr; }