ProviderAssembly能否从CLR主机加载AppDomainManager



我有一个应用程序,该应用程序托管带有自定义AppDomain Manager的.net clr和带有存储的AssemblyManager。

当中具有AppDomainManager的程序集是与可执行文件位于同一目录中的dll时,这一切都可以正常工作。

我想做的是将Managers程序集嵌入到可执行文件中。当我这样做时,使用正确的强名称调用ProviderAssembly时,我会返回一个包含汇编字节的流,但ICLRuntimeHost->Start()返回一个错误,指示无法加载类型。

所有组件绑定细节匹配等

我的问题是,有人知道是否支持这种配置吗?是否可以通过这种方式而不是从文件加载AppDomainManagers程序集?


当前仅向CLR提供IHostAssemblyManager。呼叫:

#define ASSEMBLY L"MscoreeIntegration, Version=1.0.0.0, PublicKeyToken=a0c02a181a22f567, Culture=neutral"
#define MANAGER L"MscoreeIntegration.Manager"
m_clrcontrol->SetAppDomainManagerType(ASSEMBLY, MANAGER);

从映射中查找绑定标识,返回存储数据的IStream(已使用调试器进行调试,没有任何失败)。

HRESULT STDMETHODCALLTYPE AssemblyManager::GetNonHostStoreAssemblies(ICLRAssemblyReferenceList **ppReferenceList){
    *ppReferenceList = NULL;
    return S_OK;
}
HRESULT STDMETHODCALLTYPE AssemblyManager::GetAssemblyStore(IHostAssemblyStore **ppAssemblyStore){
    *ppAssemblyStore = m_impl->m_store;
    return S_OK;
}
HRESULT STDMETHODCALLTYPE AssemblyStore::ProvideAssembly(AssemblyBindInfo *pBindInfo, UINT64 *pAssemblyId, UINT64 *pContext, IStream **ppStmAssemblyImage, IStream **ppStmPDB){
    map<wstring,Data*>::iterator find = m_impl->m_assemblies.find(pBindInfo->lpPostPolicyIdentity);
    if(find!=m_impl->m_assemblies.end()){
        *pAssemblyId = find->second->m_id;
        HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, find->second->m_cbLength);
        LPVOID pData = ::GlobalLock(hMem);
        memcpy(pData, find->second->m_pData, find->second->m_cbLength);
        ::GlobalUnlock(hMem);
        HRESULT hr = ::CreateStreamOnHGlobal(hMem, FALSE, ppStmAssemblyImage);
        *pContext = 0;
        *ppStmPDB = NULL;
        return S_OK;
    }
    return 0x80070002; //COR_E_FILENOTFOUND;
}

我得到的绑定身份是这样的:

void AddAssembly(AssemblyStore *store, ICLRAssemblyIdentityManager *ident, const char* filename){
    int length = 0;
    const char *buffer = LoadData(filename, length);
    IStream *stream = GetStream(buffer, length);
    if(!stream){ return; }
    DWORD cbBuffer = 0;
    HRESULT hr = ident->GetBindingIdentityFromStream(stream, 0, NULL, &cbBuffer);
    wchar_t *bind = (wchar_t*)malloc(cbBuffer*sizeof(wchar_t));
    stream = GetStream(buffer, length);
    hr = ident->GetBindingIdentityFromStream(stream, 0, bind, &cbBuffer);
    BOOL strong;
    hr = ident->IsStronglyNamed(bind, &strong);
    if(!strong){
        printf("NOT STRONG: %Sn", bind);
    }
    store->AddAssembly(bind, (BYTE*)buffer, length);
}

正如Hans所说,您已经拥有了所需的一切。您提到的书中有一个现成的示例,其中包含AppDomainManager类的程序集由主机从OLE复合文件中拉出。

我正在做类似的事情,所以我可以确认它有效。你必须小心三点:

  • 生成非宿主程序集列表时。如果您不知道如何正确构建它,最好让CLR处理它(返回NULL)通过这种方式,分辨率变为GAC -> Host -> other Fusion search paths
  • 当您返回pAssemblyId时,永远不要超过0。医生没有告诉它,但它导致了一个非常。。奇特的行为
  • 将该文件读取到CCD_ 3。就我个人而言,我编写了FileStream未修改类,该类通过使用Win32 API实现IStream。比依赖不是为此目的编写的代码(或链接到"奇怪"的东西,如shell API)要好得多

请注意,在"pBindInfo"中,您传递的程序集的标识与请求的"processorarchitecture"匹配,特别是检查请求的"rocessorarchiteture"的"lpPostPolicyIdentity",如果程序集不匹配,则会使请求失败。clr将尝试首先加载x64或x86,然后加载msil(anycpu),所以请等待,直到您获得正确的请求

相关内容

  • 没有找到相关文章

最新更新