有没有办法让P / Invoke(DllImport)签名引用的特定DLL依赖于CPU架构?
我正在开发一个应用程序,它从第三方供应商的本机dll加载大量方法签名,在这种情况下是用户空间接口DLL到一块硬件。该供应商现在已经开始提供DLL的x86和x64版本,我认为我的应用程序将受益于64位进程的运行。除了这个DLL之外,一切都是.NET代码,因此构建为“任何CPU”都可以。
本机DLL中的所有方法签名在64位上都是相同的,但DLL的名称不同(Foo.dll与Foo_x64.dll)。有没有办法通过P / Invoke签名或app.config条目我可以让它根据正在运行的CPU架构选择加载哪个DLL?
如果代替不同的DLL名称,它在不同的文件夹中是相同的名称,那么打开任何其他选项吗?
注意:由于此用户空间DLL的版本必须与安装的硬件内核驱动程序匹配,因此DLL不与我们的应用程序捆绑在一起,而是依靠供应商安装程序将其放在目录中在%PATH%。
答案 0 :(得分:11)
“如果代替不同的DLL名称,它在不同的文件夹中是相同的名称,那么打开任何其他选项吗?”
也许这对你有用:
public static class NativeMethods
{
// here we just use "Foo" and at runtime we load "Foo.dll" dynamically
// from any path on disk depending on the logic you want to implement
[DllImport("Foo", EntryPoint = "bar")]
private void bar();
[DllImport("kernel32")]
private unsafe static extern void* LoadLibrary(string dllname);
[DllImport("kernel32")]
private unsafe static extern void FreeLibrary(void* handle);
private sealed unsafe class LibraryUnloader
{
internal LibraryUnloader(void* handle)
{
this.handle = handle;
}
~LibraryUnloader()
{
if (handle != null)
FreeLibrary(handle);
}
private void* handle;
} // LibraryUnloader
private static readonly LibraryUnloader unloader;
static NativeMethods()
{
string path;
if (IntPtr.Size == 4)
path = "path/to/the/32/bit/Foo.dll";
else
path = "path/to/the/64/bit/Foo.dll";
unsafe
{
void* handle = LoadLibrary(path);
if (handle == null)
throw new DllNotFoundException("unable to find the native Foo library: " + path);
unloader = new LibraryUnloader(handle);
}
}
}
它包括在P / Invoke本身尝试加载之前显式加载本机库及其完整路径。
您怎么看?
答案 1 :(得分:4)
无法拥有单个PInvoke签名并获得所需的行为。该属性将刻录到元数据中,并且必须具有常量值。你可以做的一件事就是有多种方法。
public static class NativeMethods32 {
[DllImport("Foo.dll")]
public static extern int SomeMethod();
}
public static class NativeMethods64 {
[DllImport("Foo_x864.dll")]
public static extern int SomeMethod();
}
public static class NativeMethods {
public static bool Is32Bit { return 4 == IntPtr.Size; }
public static SomeMethod() {
return Is32Bit ?
NativeMethods32.SomeMethod();
NativeMethods64.SomeMethod();
}
}
然而,这不是首选方法。一种更简单的方法是使DLL在多个平台上具有相同的名称,并创建与平台无关的PInvoke签名。这是大多数/所有Windows库采用的方法。
答案 2 :(得分:1)
我为目标开发了一个特殊的库:InteropDotNet。它引入了新的RuntimeDllImport
属性,动态库路径解析(动态)。在默认方式中,您可以编写
[RuntimeDllImport("NativeLib",
CallingConvention = CallingConvention.Cdecl, EntryPoint = "sum")]
int Sum(int a, int b);
图书馆将根据环境得到解决。例如,Win / Linux,x86 / x64的路径:
x86/NativeLib.dll
x86/libNativeLib.so
x64/NativeLib.dll
x64/libNativeLib.so