Can AppDomainManager be loaded by ProvideAssembly from a CLR Host?

3

I have an application hosting the .net clr with a custom AppDomain Manager and an AssemblyManager with a store.

This all works fine when the Assembly with the AppDomainManager in is a dll in the same directory as the executable.

What I want to do is embed the Managers assembly inside the executable. When I do this ProvideAssembly is called with the correct strong name, I return a stream with the assembly bytes, but ICLRRuntimeHost->Start() returns an error indicating that a type cannot be loaded.

All the assembly binding details match etc.

My questions is, does anyone know if this configuration is supported? Can the AppDomainManagers assembly be loaded in this way rather than from a file?


Currently only provide an IHostAssemblyManager to the CLR. And Call:

#define ASSEMBLY L"MscoreeIntegration, Version=1.0.0.0, PublicKeyToken=a0c02a181a22f567, Culture=neutral"
#define MANAGER L"MscoreeIntegration.Manager"

m_clrcontrol->SetAppDomainManagerType(ASSEMBLY, MANAGER);

Lookup Binding identity from map, return an IStream of the stored data (Have stepped through with a debugger and nothing fails).

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;
}

I get the binding identities like so:

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);
}
.net
clr
clr-hosting
asked on Stack Overflow Feb 6, 2012 by BafflingTangent • edited Feb 6, 2012 by BafflingTangent

2 Answers

1

Like Hans said, you already have everything you need. The book you mentioned has a ready-made example in which the assembly that contains the AppDomainManager class is pulled out of a OLE compound file by the host.

I am doing something similar, so I can confirm it works. You have to be careful on three points:

  • when you generate the list of non-host assemblies. If you do not know how to build it properly, it's way better to let the CLR handle it (passing back NULL) In this way the resolution becomes GAC -> Host -> other Fusion search paths
  • when you return pAssemblyId, never, ever pass 0. The docs don't tell it, but it results in a very .. peculiar behaviour.
  • reading the file into a IStream. Personally, I wrote my FileStream unamanged class that implements IStream by using the Win32 API. Way better than relying on code that was not written for this purpose (or linking to something "strange", like the shell API)
answered on Stack Overflow Dec 15, 2014 by Lorenzo Dematté
0

Be aware that in the "pBindInfo" the identity of the assembly you pass matches the requested "processorarchitecture" in particular check the "lpPostPolicyIdentity" for the requested "processorarchitecture" and fail the request if your assembly doesn't match. The clr will try to load first the x64 or the x86 and then the msil (anycpu) so wait untill you get the correct request

answered on Stack Overflow Dec 30, 2019 by user3409863

User contributions licensed under CC BY-SA 3.0