搜索DLL的DLL

我为Thunderbird做了一个扩展。 它调用(通过js-ctypes)我编写的C ++ DLL,然后引用其他DLL,它们是用C#(现有代码)编写的程序集。 如果所有文件与Thunderbird可执行文件位于同一目录中,则一切正常。

我现在已将我自己的文件移至我制作的目录,以使它们不同于Thunderbird文件。 该目录在路径中,所以我的C ++ DLL在调用时被加载。 但是,当它开始寻找引用的程序集时,它会失败。

Procmon显示它只在Thunderbird运行的目录中查找引用的程序集。 不仅没有路径,它甚至不在系统目录中查看。

我能做些什么来让我的DLL加载它的依赖关系,而不会将所有东西都转储到Thunderbird自己的文件夹中,而且当我将扩展端口移植到其他邮件程序时,这会变得很愚蠢。

编辑:从JS代码添加提取。

从我的'init'函数,有;

this._kernel32 = ctypes.open("kernel32.dll");

this._setDLLDir = this._kernel32.declare("SetDllDirectoryA",
                               ctypes.default_abi,
                               ctypes.bool,
                               ctypes.char.ptr);

var ret;
ret = this._setDLLDir("C:Program Files (x86)AuthentStreamAttacher");

this._lib = ctypes.open("AttacherC.dll");
this._getStr = this._lib.declare("GetPackage",
                         ctypes.default_abi,
                         ctypes.char.ptr);

this._freeStr = this._lib.declare(“FreePackage”,ctypes.default_abi,ctypes.void_t,ctypes.char.ptr);

ret = this._setDLLDir(null);

而我实际上正在调用_getStr并搜索AttacherC.dll的依赖关系是;

var ret;
ret = this._setDLLDir("C:Program Files (x86)AuthentStreamAttacher");
var str = this._getStr();

在每种情况下,ret都是true(根据逐步调试程序),表明对SetDllDirectory的调用成功。 无论我使用“A”还是“W”版本,行为都是相同的,JS中没有任何内容只是让我调用“SetDllDirectory”。 就好像每个调用都发生在它自己的独立上下文中,但在我的DLL中,“GetPackage”使用malloc分配一些内存,然后需要在“FreePackage”中释放它。 FreePackage不会抛出异常,表明内存分配在两次调用之间持续存在。

更奇怪的行为; 如果我在SetDllDirectory中指定一个随机字符串作为路径(在这种情况下为“helloworld”)ret仍然为真。 所以,SetDllDirectory实际上并不是通过ctypes正确获取字符串,或者没有对它进行任何理智检查。

我现在的感觉是,每个js-ctypes调用都以其某种方式发生在它自己的上下文中,并且它让人不安.net的程序集搜索机制,并且让这个工作起作用的唯一方法是使用一个单独的函数从javascript调用。 然后它调用SetDllDirectory和LoadLibrary在相同的上下文中调用链中的下一个包装器,然后调用我的真正的C#代码。 杂乱,似乎更容易发生错误,所以我希望有人来证明我错了?


由于没有其他人似乎有答案,我将记录我最终做了什么。

当本地代码调用一个dotnet DLL时,CLR会在幕后启动以运行它。 虽然本机代码可以在各种位置(包括由SetDllDirectory指定的位置)搜索DLL,但CLR只会查看初始可执行文件所在的目录以及全局程序集缓存。 要通过在Visual Studio中添加对它们的引用来访问DLL链接到的程序集,它们必须位于这两个位置之一中。

由于我不想这样做,所需要做的就是制作一个.net DLL,它直接仅依赖于框架程序集,而不涉及我自己的任何内容。 然后这将获得CLR并运行我的代码。 然后,我可以通过Assembly::LoadFrom()加载我想要使用的程序集,并调用我想要使用的方法,如此处所述。

当然,以这种方式加载程序集仍然会导致在可执行目录或GAC中搜索任何其他依赖程序集(如果它们尚未加载),并且除了最微不足道的情况外,它都会显式地从最基本向上的顺序加载每个组件。 所以AssemblyResolve事件首先被注册。 当CLR在其两个搜索位置找不到组件时,它会引发此事件并让我确定程序集的完整路径并加载它,再次使用Assembly::LoadFrom()

当然,LoadFrom需要知道基本路径 - 似乎可用的唯一信息涉及可执行文件的目录,但有很多方法可以解决这个问题。


您将需要修改DLL搜索路径。

在调用ctypes.open()加载C ++ DLL之前,先调用SetDllDirectory 。 传递给SetDllDirectory包含您的DLL及其相关模块的目录。 当对ctypes.open()的调用返回时,再次调用SetDllDirectory ,传递NULL以撤销搜索路径修改。

链接地址: http://www.djcxy.com/p/7743.html

上一篇: DLLs searching for DLLs

下一篇: unable to find an entry point named 'interlockedexchange'