示例#1
0
//=====================================================================================================================
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;
}