P/Invoke 动态 DLL 搜索路径

Posted

技术标签:

【中文标题】P/Invoke 动态 DLL 搜索路径【英文标题】:P/Invoke dynamic DLL search path 【发布时间】:2011-01-25 14:04:21 【问题描述】:

我有一个现有的应用程序,它 P/Invokes 到与应用程序本身位于同一目录中的 DLL。

现在(由于佳能生产了最糟糕的 API 之一)我需要支持这个 API 的两个版本,并在运行时确定我应该使用哪一个(旧的或新的)。由于 DLL 具有相同的名称(第一个加载具有相同名称的其他 DLL,因此仅重命名第一个对我没有帮助)我必须将它们保存在不同的目录中。

因此我的问题是:我必须使用哪些选项来控制 DllImport 声明中给出的 DLL 使用哪个目录?

我想我可以从尝试以下两个想法中的任何一个开始:

1) 在执行第一次 P/Invoke 之前使用“SetDllDirectory”设置我想要的目录,然后再将其重置。

2) 使用“LoadLibraryEx”手动加载所需的 DLL,并希望这样做。

但是还有其他“.NET:ish way”可以先尝试吗?

更新:我意识到我可以在两个单独的 .Net 程序集中填充对 DLL 的所有访问,然后将它们中的每一个与相应的 API 文件放在一个单独的目录中。然后我可以动态加载正确的 .Net 程序集,并且正确的 DLL 的加载会自动发生。有什么不应该起作用的原因吗?

我能想到一个:我将如何调试这些东西?是否可以告诉 Visual Studio 程序集(包含在我的解决方案中)应放置在子目录中并从那里进行调试?

【问题讨论】:

【参考方案1】:

从 .NET Core 3.0 开始,也可以与 .NET 5 & .NET 6 一起使用,您可以使用NativeLibrary.Load(string) 在运行时动态加载 DLL,并通过 P/Invoke 正常使用。

查看此答案了解更多详情:https://***.com/a/69958827/211672

【讨论】:

【参考方案2】:

我的哀悼,我已经看到了其中一个 API,它确实非常糟糕。更大的问题是您需要能够说服 Windows 找到 DLL。它们不会在您的 .exe 目录中,因此默认设置不起作用。使用 SetDllDirectory() 可以,使用 Environment.CurrentDirectory 也可以。 LoadLibrary 无法工作,P/Invoke marshaller 将使用 LoadLibrary 本身。

如果它是一个选项,您可以为两个 P/Invoke 声明使用不同的名称,为 DllImport() 构造函数使用不同的参数并使用 EntryPoint 属性。听起来好像不会飞。

【讨论】:

目前,我给你一个 +1 表示哀悼,我真的需要这样,在过去六年中,我多次接触过他们的 API,每次都遭遇灾难...... 【参考方案3】:

我认为第二个选项可行,但需要编写大量代码来管理 .net 中的 dll 加载。

第一个也可以,但我要么不喜欢。

这是我的建议:您可以在 DllImport [DllImport(@"C:\dll\a32.dll"] 中指定完整路径(并且可能是相对的)

【讨论】:

我认为问题在于 DLL 运行所在的目录,而不是 DLL 本身的加载。【参考方案4】:

您的第一个选项(P/Invoke with SetDllDirectory)是我个人更喜欢的选项。不幸的是,没有一种“.NETish”方式来处理加载本机 DLL……这确实很有意义。

【讨论】:

以上是关于P/Invoke 动态 DLL 搜索路径的主要内容,如果未能解决你的问题,请参考以下文章

P/Invoke之C#调用动态链接库DLL

关于DLL搜索路径的顺序问题

定位Dll加载异常的方法

C#如何加上自己的DLL的搜索路径?

P/Invoke 是不是执行 DLL 然后将其关闭?

使用 P/Invoke 调用 dll 时,为啥 LoadLibrary 在某些机器上会失败?