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 搜索路径的主要内容,如果未能解决你的问题,请参考以下文章