我有一个外部的C++ dll 文件需要使用 DLLImport 导入。如果我的应用程序是在 x64 编译下,我需要导入 x64 版本的 dll,如果是 x86 构建,则需要 x86 dll。
最好的方法是什么?
理想情况下,我希望使用一些预处理指令,但我知道这在 C# 中不起作用?
更多信息:该 DLL 是由设置为 AnyCPU 的项目导入的。父项目决定应用程序是以 x64 还是 x86 编译。我们为不同的客户编译两个版本-我希望在这两个版本中共享子项目。
我有一个外部的C++ dll 文件需要使用 DLLImport 导入。如果我的应用程序是在 x64 编译下,我需要导入 x64 版本的 dll,如果是 x86 构建,则需要 x86 dll。
最好的方法是什么?
理想情况下,我希望使用一些预处理指令,但我知道这在 C# 中不起作用?
更多信息:该 DLL 是由设置为 AnyCPU 的项目导入的。父项目决定应用程序是以 x64 还是 x86 编译。我们为不同的客户编译两个版本-我希望在这两个版本中共享子项目。
这主要是一个部署问题,只需让您的安装程序根据目标机器上的Windows版本复制正确的DLL即可。
但是没有人喜欢这样做。动态地调用正确的DLL的函数非常痛苦,您必须为每个导出函数编写委托类型,并使用LoadLibrary + GetProcAddress + Marshal.GetDelegateForFunctionPointer来创建委托对象。
但是没有人喜欢这样做。更简单的方法是声明该函数两次,分别赋予不同的名称,并在[DllImport]属性中使用EntryPoint属性指定实际名称。然后在运行时测试您想要调用的内容。
但是没有人喜欢这样做。最有效的技巧是引导Windows为您加载正确的DLL。首先,您需要将DLL复制到Windows不会查找的目录中。最好的方法是在构建目录中创建“x86”和“x64”子目录,并将适当的DLL复制到每个目录中。通过编写一个后置生成事件来完成此操作,以创建目录并复制DLL。
然后通过pinvoke SetDllDirectory()告诉Windows。您指定的路径将被添加到Windows搜索DLL的目录中。就像这样:
using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
class Program {
static void Main(string[] args) {
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
path = Path.Combine(path, IntPtr.Size == 8 ? "x64" : "x86");
bool ok = SetDllDirectory(path);
if (!ok) throw new System.ComponentModel.Win32Exception();
//etc..
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
}
请考虑在64位模式下运行代码是否真正有用。得益于其庞大的虚拟内存地址空间,这种情况非常罕见,且是唯一的实际收益。您仍然需要支持32位版本,在2GB情况下能够正常运行。
LoadLibrary
并传递完整路径,而不是修改 DLL 搜索路径,因为后者总让我感觉很笨拙。当然,基本思想是相同的。 - David Heffernan#ifdef
,你能为他提供一个快速的代码示例,以及加载库的代码示例吗?尽管没有示例,但我仍然给了一个+1。 - Scott Chamberlain
Environment.Is64BitProcess
,或sizeof(void*)
,或IntPtr.Size
。 - Michael Graczyk