混合程序集无法发现本机 DLL 文件

3
我有一个混合模式的dll,它依赖于本地dll。
我正在使用Assembly.Load从C# exe加载混合模式的dll。然而,由于混合模式的dll的位置不在应用程序的bin目录中,因此它会失败,因为它只在bin和PATH环境变量中的文件夹中查找本地C++ dll。
我认为使用选项/assemblylinkresource应该可以解决这个问题,并强制在部署的混合模式dll旁边的备用目录中找到本地dll。但实际上并不能。
是否有一种方法可以使用现有的C++/CLI混合模式dll创建带有本地dll的多文件程序集?我看到的唯一示例都是使用.netmodules和本地dll。(http://msdn.microsoft.com/en-us/library/xawyf94k(v=vs.100).aspx) 因此,解决方案要么是: a)以某种方式强制应用程序在您选择的目录中搜索本地依赖项;或者 b)将本地dll打包到一个托管的混合模式程序集中(这可能吗?)-考虑到静态链接依赖项不是一个选项。
2个回答

5

普通的Windows DLL搜索规则适用。因此,它永远不会找到那些DLL。"多文件程序集"也行不通,你无法合并本机代码。您拥有的选项,大致按首选顺序:

  • 调用SetDllDirectory()将包含DLL的路径添加到Windows将查找的目录集。如果外部代码也使用它,则可能失败。
  • 使用Environment.SetEnvironmentVariable()将路径附加到PATH环境变量。这只会更改进程的PATH副本,因此是一个合理的方法。在PATH达到上限的机器上可能失败。
  • 将Enviroment.CurrentDirectory设置为DLL所在的路径。如果外部代码也进行了修补,则可能失败。
  • 在安装时记录每个DLL的路径HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs注册表键中。
  • 将DLL安装在Windows边-by-side缓存中,并使用清单告诉Windows此事。这很难做到正确。

非常感谢!你在第一个解决方案中所说的“如果外部代码也使用它,则可能会失败”是什么意思?SetDllDirectory文档(http://msdn.microsoft.com/en-us/library/ms686203%28v=vs.85%29.aspx)指出:“将目录添加到用于查找应用程序DLL的搜索路径。”因此,即使外部代码使用它,它不会增加额外的搜索路径吗? - Seth
感谢第四个解决方案。但在我们的特定情况下,这不是一个选项,因为它是一个boostrap应用程序,并且当安装bootstr应用程序时,实现是未知的(dll依赖项)。 - Seth
不,正如文档所述:“每次调用SetDllDirectory函数时,它都会替换上一次SetDllDirectory调用中指定的目录。” AddDllDirectory()更好,但它是Windows的一个非常晚期的补充。 - Hans Passant
我认为我将使用选项2,并在PATH环境变量过多时退而使用选项1。 - Seth

2
潜在的解决方案候选人,未经 MMA 测试:这可能不是您期望的最佳解决方案,但我认为我应该添加它,因为它可以帮助您实现解决方案a)。在C++中,您可以通过手动设置要搜索的目录path search order或通过手动加载dll使用LoadLibraryEx来控制加载路径。我想人们可以使用P/invokes在C#中访问这些调用。请注意,SetDllDirectory仅适用于XP SP1。
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern void SetDllDirectory(string lpPathName);

这个方法可能可行。所以我使用Ninject进行延迟绑定 - 所以我只需要在调用 _kernel.Get<IMixedModeExample> 之前调用 SetDllDirectory 就可以了? - Seth
我认为您在编辑中提供的链接无法与本地dll依赖项配合使用。 - Seth
@Seth:抱歉,我觉得我的解决方案有点不太正规和不确定,开始寻找更好的解决方案(错过了链接不是本地DLL的事情;现在已经删除了它)。 - kamjagin
@Seth:啊,对于混合模式程序集,没有 p/invoke 调用。您需要预配置搜索路径或在加载依赖它们的混合模式程序集之前预加载本地 DLL。不同的时间,相同的方法。 - Ben Voigt
@BenVoigt:感谢您的评论。我在问题陈述上并不是很清楚。但是托管的exe是用C#编写的,所以p/invoke应该可以工作。我有一个C#接口,由一个C#类实现。这个C#类包装了C++/CLI ref类。这使我能够使用ninject和延迟绑定接口。因此,在调用_kernel.Get之前,我应该能够使用SetDllDirectory。 - Seth
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接