C# DLL搜索DLL

C# DLL搜索DLL,c#,c++,.net,dll,jsctypes,C#,C++,.net,Dll,Jsctypes,我为雷鸟做了一个扩展。它调用(通过JS cType)我编写的C++ DLL,它又引用了其他用C语言编写的程序集(现有代码)。如果所有文件都与Thunderbird可执行文件位于同一目录中,则一切正常 现在,我已经将自己的文件移动到了一个目录中,以使它们与Thunderbird文件不同。目录在路径中,所以当调用时,我的C++ DLL会被加载。但是,当它开始查找引用的程序集时,它会失败 Procmon显示它只在Thunderbird运行的目录中查找引用的程序集。不仅没有路径,甚至没有在系统目录中查找

我为雷鸟做了一个扩展。它调用(通过JS cType)我编写的C++ 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.\u freeStr=this.\u lib.declare(“FreePackage”, ctypes.default_abi, ctypes.void\t, ctypes.char.ptr)

ret=此值。\u 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仍然为true。因此,要么SetDllDirectory实际上没有通过ctypes正确获取字符串,要么它没有对其进行任何健全性检查


我现在的感觉是,每个js ctypes调用都是在自己的上下文中进行的,在某种程度上,这扰乱了.net的程序集搜索机制,而实现这一点的唯一方法是使用一个单独的本机DLL,其中包含一个从javascript调用的函数。然后在同一上下文中调用setdldirectory和LoadLibrary来调用链中的下一个包装器,然后它调用我真正的C#代码。凌乱而且似乎更容易出错,所以我希望有人来证明我错了?

您需要修改


在调用<代码> cType(打开)(<)>代码之前,调用一个C++的DLL。传递到

SetDllDirectory
包含DLL及其相关模块的目录。当对
ctypes.open()
的调用返回时,再次调用
setdldirectory
,传递
NULL
,以撤消对搜索路径的修改。

由于似乎没有其他人有答案,我将记录我最终的操作

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

因为我也不想这样做,所以需要做的是创建一个只直接依赖于框架程序集的.net DLL,而不引用我自己的任何程序集。这样就可以启动CLR并运行我的代码。然后,我可以通过
assembly::LoadFrom()
加载我想要使用的程序集,并调用我想要使用的方法

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


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

TB扩展指南对此有什么要说的吗?通常您会调用
setdldirectory
。或者使用加载时间链接。但后者并不有趣,我没见过。我使用js ctypes从JavaScript调用我的DLL,因为我在使用XPCOM时失败得很惨。js ctypes文档包括搜索初始DLL,但不包括进一步搜索。好的,那么我认为您有一个路径。您已经有了一个加载DLL的JS层。大概需要调用
LoadLibrary
。因此,在调用C++ DLL之前,在调用<代码> LoadLibrary < /代码>之前,添加一个对<代码> SETDLARTHORCT//COD>的调用。返回后,添加第二个对
setdldirectory
的调用以撤消更改。问题是我没有
LoadLibrary
。C++是一个.NET程序集,它输出了我在JS中想要的函数,但是通过在项目中添加它们作为引用来获取其他程序集——实际的搜索和加载在后台的某个地方发生。我隐约意识到,我可能可以使用反射来消除引用,但我以前从未去过,我希望有一种更简单、更简单的方法。比如以某种方式注册我的程序集,但是在mo上注册regasm