我有一个使用DLLImport导入的外部c ++ dll。如果我的应用程序在x64中编译,我需要导入这个dll的x64版本,如果是x86版本,我需要x86 dll。
实现这一目标的最佳方法是什么?
理想情况下,我喜欢一些预处理器指令,但我知道这不适用于c#?
更多信息:DLL正由一个设置为AnyCPU的项目导入。父项目是确定应用程序是否编译为x64或x86的项目。我们为不同的客户编译两个版本 - 我想在两个版本中共享子项目。
答案 0 :(得分:23)
这主要是部署问题,只需让安装程序根据目标计算机上的Windows版本复制正确的DLL。
但没有人喜欢这样做。动态调整正确的DLL函数是非常痛苦的,你必须为每个导出的函数编写委托类型,并使用LoadLibrary + GetProcAddress + Marshal.GetDelegateForFunctionPointer来创建委托对象。
但没有人喜欢这样做。较不痛苦的方法是将函数声明两次,赋予它不同的名称,并使用[DllImport]属性中的EntryPoint属性指定实名。然后在运行时测试您要调用的内容。
但没有人喜欢这样做。最有效的技巧是引导Windows为您加载正确的DLL。首先要做的是将DLL复制到Windows不会查找的目录中。最好的方法是在构建目录中创建“x86”和“x64”子目录,并将相应的DLL复制到每个子目录中。通过编写创建目录并复制DLL的构建后事件来完成此操作。
然后通过pinvoking 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位模式运行对您是否真的有用。很少需要从中获得巨大的虚拟内存地址空间,这是唯一真正的好处。您仍需要支持需要在2 GB情况下正常运行的32位版本。
答案 1 :(得分:5)
使用不同的名称添加x86和x86_64 DLL导入,然后您可以通过检查Environment.Is64BitProcess(或IntPtr.size,如果您使用< .Net)的值来根据运行时的体系结构有条件地调用它们4)。无论项目是构建为x86,x86_64还是AnyCPU
,这都可以工作或者,设置2个不同的构建配置 - 一个只执行x86,另一个只执行x86_64,为每个构建配置一个条件编译符号,并在自定义符号上使用#ifdef。