我有一个32位和64位版本的dll。我的.NET WinForm配置为“任何CPU”,我的老板不会让我们为不同的操作系统版本单独安装。所以我想知道:如果我在安装中打包两个dll,那么有没有办法让WinForm确定它的64位/ 32位并加载正确的dll。
我找到this article来确定版本。但我不知道如何注射适当的 在我想要使用的方法上定义DLLImport属性的方法。有什么想法吗?
答案 0 :(得分:14)
您可以利用SetDllDirectory API函数,它会改变非托管程序集的搜索路径。将32位DLL存储在app安装目录的x86子目录中,即x64子目录中的64位DLL。
在进行任何P / Invoke之前,在app启动时运行此代码:
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
...
public static void SetUnmanagedDllDirectory() {
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
path = Path.Combine(path, IntPtr.Size == 8 ? "x64 " : "x86");
if (!SetDllDirectory(path)) throw new System.ComponentModel.Win32Exception();
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
答案 1 :(得分:6)
你能同时导入它们并决定通过.NET调用哪一个吗?
例如:
[DllImport("32bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe32 (IntPtr hWnd, String text, String caption, uint type);
[DllImport("64bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe64 (IntPtr hWnd, String text, String caption, uint type);
答案 2 :(得分:3)
您应该创建两个不同的私有extern
方法,并创建一个内部方法来检查IntPtr.Size
并调用正确的版本。
答案 3 :(得分:3)
我的解决方案是创建一个抽象类,具有加载和包装我的32位DLL的具体版本,以及一个加载和包装64位DLL的单独实现。基类中的单个工厂方法可用于基于IntPtr.Size
实例化适当的实现。
这种方法的好处是你的代码的其余部分完全与平台隔离 - 它只是使用你的基类工厂方法构造一个对象,并使用它。也可以很容易地以统一的方式调用DLL中的多个方法,并且可以轻松地将所有“本机”代码推送到私有实现中。
答案 4 :(得分:2)
...或者您可以使用Marshal.GetDelegateForFunctionPointer()
执行dynamic P/Invoke
...或者在CLR尝试为您加载之前调用LoadLibrary()
with a fully qualified path。