编组 SIZE_T* 的正确方法?

Posted

技术标签:

【中文标题】编组 SIZE_T* 的正确方法?【英文标题】:Correct way to marshal SIZE_T*? 【发布时间】:2010-11-21 12:35:04 【问题描述】:

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

我认为它是一个丑陋的黑客,因为 IntPtr 应该代表一个指向某物的指针。但是,我只是将其直接视为整数。 SysUInt 特别声明它是 uint 的可变大小表示。正是我想要的,除了我不知道如何将它正确编组为 SysUInt 指针,而不是 SysUInt。 您正在使用指向 SIZE_T 的指针作为参数,Soonil。 IntPtr 看起来很合适 你会注意到我没有使用 IntPtr,但是我使用的是 ref IntPtr。 @Soonil,没有什么可以说IntPtr“应该代表指向某物的指针”。 MSDN 是这样描述它的:“IntPtr 类型被设计为一个整数,其大小是特定于平台的。也就是说,这种类型的实例在 32 位硬件和操作系统上应该是 32 位,而 64 位在 64 位硬件和操作系统上”。因此,它只是一个与平台字长匹配的整数类型。 size_tptrdiff_t 也是如此(通常,无论如何),所以映射是完全正常的。 附带说明,在 MSIL/CLR 级别(这是您可以获得的最低级别)上,int 被称为int32,而IntPtr 被称为native int。如果是 BCL 中类型的“Ptr”前缀让您感到困惑,那么您不应将其视为“指针的整数”。相反,它的意思是“与指针大小相同的整数”。【参考方案2】:

UIntPtr 是要使用的正确类型。

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

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

【讨论】:

嗯,很好 :) 不会是第一个命名错误的 API,呵呵。 实际上,这是这种类型的通用名称。 Win32 API 具有类型定义 INT_PTRUINT_PTR。 ISO C99 在<stddef.h> 中有intptr_tuintptr_t。因此,虽然它可能是一个用词不当,但现在它是一个传统的。

以上是关于编组 SIZE_T* 的正确方法?的主要内容,如果未能解决你的问题,请参考以下文章

用于 C 结构和函数的 C# 编组

将具有枚举成员的非托管结构编组到 c#

Camel 的编组问题,无法正确编组 SOAP 请求?

如何为 Gson 编组和解组创建通用方法?

有啥方法可以安全地进行图像量化且无需编组?

使用 C# P/Invoke 方法在 Struct 内编组数组