正确的方法来组织SIZE_T *?

时间:2009-08-21 00:13:17

标签: c# c++ pinvoke marshalling intptr

我有以下C ++函数定义,我试图通过托管代码通过PInvoke调用:

bool FooBar(SIZE_T* arg1);

我的管理声明如下:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref uint arg1);

你们中的一些人可能会注意到我最终做的同样的错误。这不是64位便携式。 SIZE_T的大小可变(32-64位),指针也是如此。在托管大小上,指针正确转换为64位,但uint没有,并且您最终可以在arg1的高位中使用垃圾。这是一个特别持久的错误,因为垃圾通常只是零:(

我唯一能够解决的问题是以下管理声明:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref IntPtr arg1);

这当然有效,因为IntPtr可以正确改变其大小。在我的代码中,我只是将IntPtr视为一个整数,它可以工作,虽然它看起来像一个丑陋的黑客。在我看来应该有一些方法来正确指定,也许使用UnmanagedType.SysUInt,但我无法提出任何其他工作解决方案。

2 个答案:

答案 0 :(得分:20)

使用IntPtr和/或UIntPtr 正确地执行此操作 - 这些类型专门用于此目的!我不明白为什么你认为这是一个“丑陋的黑客”。我也不确定你提议的替代方案是什么 - 允许将值映射到uint的任何类型的属性本质上都是错误的,因为C#uint保证是32位而不管64位平台的体系结构,要正确地编组它,它必须修剪一半,丢失数据,并可能使结果无用。

答案 1 :(得分:14)

UIntPtr 是要使用的正确类型。

size_t是一个无符号的,指针大小的整数,这正是UIntPtr的意思。我同意,名字中的“ptr”可能有点令人困惑。它实际上并不意味着“这是一个指针”,它意味着“这是一个指针大小的整数”。所以你的声明是:

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref UIntPtr arg1);