Assembly Resolver

本文介绍了一种特殊情况下的DLL加载问题及其解决方案。在一个混合模式的C++/CLI模块(pluginA.dll)和纯资源DLL(pluginARes.dll)中,由于CLR定位机制限制,无法直接从应用程序目录之外加载。通过使用MS的assemblyResolver机制,可以在首次调用资源前注册委托到AppDomain的AssemblyResolve事件,从而自定义DLL查找路径。
项目中碰到这样一个需求:本来,一个app的plugin (pluginA.dll + pluginARes.dll)是自然的deploy到app dir里面的;但是呢,现在要把这个plugin在这个app以及基于这个app开发的一些衍生产品上共享,就必须要把它放在一个common的目录里。但是呢,这个plugin有点特殊:pluginA.dll是mixedmode C++/CLI的module,然后呢,pluginARes.dll是用C#写的纯资源的dll;由于 CLR locate assembly的机制,它一般只会在app目录树和GAC里寻找,那么如果,像这里的情况一样,把pluginA +pluginARes.dll放到随便一个app dir之外的目录里,CLR是根本找不到的:当CLR去load pluginA.dll的时候,会去load PluginARes.dll,但是它只会在app dir和GAC里找,没找到,最后导致load PluginA.dll失败。(注:加载pluginA的方式呢,这里假设是manual load的方式,即app知道pluginA所在的目录所以肯定可以找得到pluginA.dll;但是呢,pluginA以reference的方式依赖pluginARes.dll)

解决方案:MS的assembly Resolver机制。

 

关于他,我想说几点:
       a. 理解他的基础知识:AppDomain 实例用于加载和执行程序集 (Assembly)。当不再使用 AppDomain 时,可以将它卸载。AppDomain 类实现一组事件,这些事件使应用程序可以在加载程序集、卸载应用程序域或引发未处理的异常时进行响应。CLR不支持unload某个assembly,只支持unload一个appdomain及包含其中的所有assemblies。
       b. 他的基本原理就是(以这里的例子为例):就是在pluginA里第一次调用pluginARes.dll的资源之前,注册一个delegate到pluginA所在的appdomain currentDomain->AssemblyResolve event中去。这样,当第一次调用PluginARes里的资源时,CLR首先尝试自己locate:失败;然后,会fire当前appdomain的load assembly related event,最终会调用到之前注册进去的我们的assemblyresolver,从而,在我们这边,告诉他怎么找到PluginARes,实现load成功!

具体实现可以参考stackoverflow的这篇帖子 (下面是摘录)

AssemblyResolver.h:

/// <summary>
/// Summary for AssemblyResolver
/// </summary>
public ref class AssemblyResolver
{
public:

static Assembly^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args )
{
    Console::WriteLine( "Resolving..." );

    Assembly^ thisAssembly = Assembly::GetExecutingAssembly();
    String^ thisPath = thisAssembly->Location;
    String^ directory = Path::GetDirectoryName(thisPath);
    String^ pathToManagedAssembly = Path::Combine(directory, "managed.dll");

    Assembly^ newAssembly = Assembly::LoadFile(pathToManagedAssembly);
    return newAssembly;
}

};

Wrapper.cpp:

#include "AssemblyResolver.h"

extern "C" __declspec(dllexport) IMyObject* CreateMyObject(void)
{
    try
    {
        AppDomain^ currentDomain = AppDomain::CurrentDomain;
        currentDomain->AssemblyResolve += gcnew ResolveEventHandler( AssemblyResolver::MyResolveEventHandler );

        return new CMyWrapper( ); // this is where the first calling to another dotnet assembly happens and leads to the need for assemblyResolver.
    }
    catch(System::Exception^ e)
    {
        System::Console::WriteLine(e->Message);

        return NULL;
    }
}

转载于:https://www.cnblogs.com/taoxu0903/archive/2010/12/19/1910801.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值