19

我有以下 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,但我无法提出任何其他可行的解决方案。

4

2 回答 2

22

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

于 2009-08-21T00:19:39.630 回答
18

UIntPtr是要使用的正确类型。

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

[DllImport("mydll", SetLastError=true, CharSet=CharSet.Unicode)]
private static extern bool FooBar(ref UIntPtr arg1);
于 2009-08-21T01:32:44.473 回答