【问题标题】:Can AppDomainManager be loaded by ProvideAssembly from a CLR Host?AppDomainManager 可以由 ProvideAssembly 从 CLR 主机加载吗?
【发布时间】:2012-02-28 00:11:09
【问题描述】:

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

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

我想要做的是将 Managers 程序集嵌入到可执行文件中。当我这样做时,使用正确的强名称调用 ProvideAssembly,我返回一个带有程序集字节的流,但 ICLRRuntimeHost->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: %S\n", bind);
    }

    store->AddAssembly(bind, (BYTE*)buffer, length);
}

【问题讨论】:

  • 您好,感谢您的评论,您是否有任何文档/页面可以指向我,以便我找出主机失败的原因?我指的是 MS CLR Hosting 在线文档和 MS Book“自定义 CLR”,我一定是在做一些愚蠢的事情!
  • 没有你还没有的东西。在您更好地描述您的问题之前,没有人可以帮助您。代码 sn-p 是最低要求。
  • 您好,已添加sn-ps,您还想看哪些其他区域?谢谢。

标签: .net clr clr-hosting


【解决方案1】:

正如汉斯所说,您已经拥有了所需的一切。你提到的书有一个现成的例子,其中包含 AppDomainManager 类的程序集被宿主从 OLE 复合文件中提取出来。

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

  • 当您生成非主机程序集列表时。如果您不知道如何正确构建它,最好让 CLR 处理它(传回 NULL) 这样分辨率就变成GAC -&gt; Host -&gt; other Fusion search paths
  • 当您返回 pAssemblyId 时,永远不会超过 0。文档没有告诉它,但它会导致非常.. 特殊的行为。
  • 将文件读入IStream。就个人而言,我使用 Win32 API 编写了实现 IStream 的 FileStream 无管理类。比依赖不是为此目的编写的代码(或链接到“奇怪”的东西,比如 shell API)要好得多

【讨论】:

    【解决方案2】:

    请注意,在“pBindInfo”中,您传递的程序集的标识与请求的“处理器架构”匹配,特别是检查请求的“处理器架构”的“lpPostPolicyIdentity”,如果您的程序集不匹配,则请求失败。 clr 将尝试先加载 x64 或 x86,然后再加载 msil (anycpu),所以请等到您收到正确的请求

    【讨论】:

      猜你喜欢
      • 2015-02-21
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多