我有一个C库。它有许多函数调用,如下所示:
void init_foo( unsigned long x, unsigned long y );
库本身在运行时动态加载(而非插件)。标头在所有平台上都是一致的。
我的问题是在Windows和32位linux上,unsigned long是32位,而在64位linux上这是64位。
这个库的各种实现都接受这个,你需要为正确的目标平台构建你的C程序(如预期的那样)。
我的互操作方法需要是其中之一,具体取决于架构。
#if lin64
[DllImport("libfoo")]
public static void init_foo( Uint64 x, Uint64 y );
#else
[DllImport("libfoo")]
public static void init_foo( Uint32 x, Uint32 y );
#endif
我可以使用的C#类型在所有平台上都是固定大小的(因为它们应该是这样)。因此,从.Net / Mono传递的托管长将始终是非托管 uint64_t 。
如何处理这个可变整数大小但是有一个程序集可以在32位或64位模式下运行.Net或单声道?
答案 0 :(得分:4)
问题在于64位Windows C长仍然是32位,不像Linux那样是64位,这会引起一些痛苦。
如果您不打算支持64位Windows,则很容易 - 您可以在DllImport定义中将long映射到IntPtr。 32位窗口和linux上的IntPtr都是32位,与长期相同。长64位Linux也是64位,IntPtr也是如此,不过在Windows 64bit上,IntPtr长64位是32位。
如果你想支持64位Windows,你可以同时定义两个签名 - 一个用于64位,一个用于32位:
[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_64bit( Uint64 x, Uint64 y );
[DllImport("libfoo", EntryPoint="init_foo")]
public static void init_foo_32bit( Uint32 x, Uint32 y );
然后在您的代码中,您可以在运行时动态决定调用哪一个:
public void InvokeFoo(long x, long y)
{
if (Environment.Is64BitProcess)
return init_foo_64bit(x, y);
return init_foo_32bit((int)x, (int)y);
}
P.S:如果您不在.NET 4上,另一种检查您是否为64位进程的方法是bool is64Bit = IntPtr.Size == 8
答案 1 :(得分:0)
另一种可能性是使用单个API编写另一个C库,该API不会在.Net平台之间变化,而是为每个API提供正确的包装库。