2012-02-06 64 views
3

我有一個應用程序託管.net clr與自定義AppDomain管理器和一個存儲的AssemblyManager。AppDomainManager可以通過來自CLR主機的ProvideAssembly加載嗎?

當AppDomainManager中的程序集與可執行文件位於同一目錄中時,這一切都可以正常工作。

我想要做的是在可執行文件中嵌入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); 
} 
+1

是的,這是受支持的。 – 2012-02-06 16:12:47

+0

嗨,感謝您的評論,你有任何文件/頁面,你可以指向我,所以我可以計算出爲什麼我的主機失敗?我指的是MS CLR Hosting在線文檔和MS Book「定製CLR」我一定在做一些愚蠢的事! – BafflingTangent 2012-02-06 21:47:57

+0

沒有你沒有的東西。直到你更好地描述你的問題,沒有人能夠幫助你。代碼片段是最低要求。 – 2012-02-06 21:52:07

回答

1

像漢斯說,你已經擁有你所需要的一切。您提到的這本書有一個現成的示例,其中包含AppDomainManager類的程序集由主機從OLE組合文件中提取出來。

我正在做類似的事情,所以我可以確認它的工作原理。您必須小心三點:

  • 當您生成非主機程序集的列表。如果您不知道如何正確構建它,最好讓CLR處理它(傳回NULL)。 這樣,分辨率變爲GAC -> Host -> other Fusion search paths
  • 當您返回pAssemblyId時,永遠不會傳遞0。說不出來,但它會導致一個非常奇怪的行爲。
  • 將文件讀入IStream。就我個人而言,我編寫了使用Win32 API實現IStream的FileStream unamanged類。比依賴不爲此目的編寫的代碼更好(或鏈接到「奇怪」的東西,如shell API)
相關問題