是否有跨平台(x86 和 x64)PInvoke 和 Windows 数据类型的明确指南?
我正在验证一些代码的 x64 兼容性。以前我使用过 PInvoke.net,但我发现了一些 x64 方面的可疑声明。现在,我:
- 查找 API 参考,例如 MapViewOfFile
- 查找windows 数据类型定义
- 查找相应的 .NET 类型。
在第 3 步中,我想要一个明确的参考
作为示例:
LPVOID WINAPI MapViewOfFile(
__in HANDLE hFileMappingObject,
__in DWORD dwDesiredAccess,
__in DWORD dwFileOffsetHigh,
__in DWORD dwFileOffsetLow,
__in SIZE_T dwNumberOfBytesToMap
);
返回值是 LPVOID,其定义为:
LPVOID
指向任何类型的指针。
该类型在 WinDef.h 中声明如下:
typedef void *LPVOID;
好的...所以我猜这是 IntPtr
或 UIntPtr
。这篇文章有一个表格并提出建议LPVOID 应映射到 IntPtr 或 UIntPtr。好的。
接下来,处理。
手柄
对象的句柄。
该类型在 WinNT.h 中声明如下:
typedef PVOID 句柄;
好的,HANDLE 是 PVOID。
PVOID
指向任何类型的指针。
该类型在 WinNT.h 中声明如下:
typedef void *PVOID;
嗯嗯,听起来像 IntPtr
接下来,DWORD
双字
32 位无符号整数。范围是十进制 0 到 4294967295。
该类型在 WinDef.h 中声明如下:
typedef unsigned long DWORD;
好的,unsigned long 0 到 4294967295,所以这是一个 uint
,但 此处 建议 Int32 或UInt32。 Int32 将无法存储任何超过 2,147,483,648 的值。所以这张表非常可疑。
最后,我们有 SIZE_T,它被定义为 ULONG_PTR,它可以是 32 位或 64 位有符号长,具体取决于平台(定义如下)。这篇文章(以及关注up)得出结论,您应该使用 IntPtr,因为它将处理可变大小。
SIZE_T
指针可以指向的最大字节数。用于 计数必须跨越指针的整个范围。
该类型在 BaseTsd.h 中声明如下:
typedef ULONG_PTR SIZE_T;
ULONG_PTR
未签名的 LONG_PTR。
该类型在 BaseTsd.h 中声明如下:
#if 已定义(_WIN64) typedef 无符号 __int64 ULONG_PTR; #别的 typedef 无符号长 ULONG_PTR; #endif
长
32 位有符号整数。范围为 –2147483648 到 2147483647 小数。
该类型在 WinNT.h 中声明如下:
typedef long LONG;
INT64
64 位有符号整数。范围是 –9223372036854775808 到 9223372036854775807 十进制。
该类型在 BaseTsd.h 中声明如下:
typedef 有符号 __int64 INT64;
因此,虽然我可以查找每个 Windows 数据类型的定义,然后在大小、符号以及是否适用于 x86 和 x64 方面找到相应的 .NET 数据类型,这并不理想。
是否有一个明确的参考资料(不是 pinvoke.net),其中包含最新的 x64 映射表?
I am verifying some code for x64 compatability. Previously I've used PInvoke.net, but I've found a few suspect declarations in terms of x64. So now, I:
- Look up the API reference such as MapViewOfFile
- Look up the windows data type definition
- Find the corresponding .NET type.
It's step 3 where I'd like a definitive reference
As an example:
LPVOID WINAPI MapViewOfFile(
__in HANDLE hFileMappingObject,
__in DWORD dwDesiredAccess,
__in DWORD dwFileOffsetHigh,
__in DWORD dwFileOffsetLow,
__in SIZE_T dwNumberOfBytesToMap
);
Return value is LPVOID, which is defined as:
LPVOID
A pointer to any type.
This type is declared in WinDef.h as follows:
typedef void *LPVOID;
OK... so I guess that's IntPtr
or UIntPtr
. This article has a table and suggests LPVOID should map to IntPtr or UIntPtr. OK.
Next, HANDLE.
HANDLE
A handle to an object.
This type is declared in WinNT.h as follows:
typedef PVOID HANDLE;
OK, HANDLE is a PVOID.
PVOID
A pointer to any type.
This type is declared in WinNT.h as follows:
typedef void *PVOID;
Hmmmm, sounds like IntPtr
Next, DWORD
DWORD
A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
This type is declared in WinDef.h as follows:
typedef unsigned long DWORD;
OK, unsigned long 0 to 4294967295, so that's a uint
and yet here it suggests Int32 or UInt32. Int32 won't be able to store any value over 2,147,483,648. So that table is very suspect.
Finally, we have SIZE_T, which is defined as a ULONG_PTR which can be 32 or 64 bit signed long depending on the platform (definitions below). This article (and follow up) conclude you should use IntPtr, since it will handle the variable sizes.
SIZE_T
The maximum number of bytes to which a pointer can point. Use for a
count that must span the full range of a pointer.This type is declared in BaseTsd.h as follows:
typedef ULONG_PTR SIZE_T;
ULONG_PTR
An unsigned LONG_PTR.
This type is declared in BaseTsd.h as follows:
#if defined(_WIN64) typedef unsigned __int64 ULONG_PTR; #else typedef unsigned long ULONG_PTR; #endif
LONG
A 32-bit signed integer. The range is –2147483648 through 2147483647
decimal.This type is declared in WinNT.h as follows:
typedef long LONG;
INT64
A 64-bit signed integer. The range is –9223372036854775808 through
9223372036854775807 decimal.This type is declared in BaseTsd.h as follows:
typedef signed __int64 INT64;
So, while I can look up the definition of every windows data type and then find a corresponding .NET datatype in terms of size, sign, and whether it works on both x86 and x64, it's not ideal.
Is there a definitive reference out there (not pinvoke.net) with a good mapping table that's up to date for x64?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
将本机数据类型映射到托管类型时,重要的是大小和一致性。
有符号与无符号类型的选择仅在解释托管值时才重要。
它们都被整理为原始位。
在大多数情况下,您只需将值从一个 API 方法传递到另一个 API 方法即可;在这些情况下,类型是有符号还是无符号并不重要,只要它的大小正确即可。
因此,一般规则是任何指针大小的值都变为
IntPtr
,DWORD
和QWORD
变为U?Int32
> 和U?Int64
分别。When mapping native datatypes to managed types, all that matters is size and consistency.
The choice of signed vs. unsigned types only matters when interpreting the managed value.
They're both marshaled as raw bits.
In most cases, you will just be passing values from one API method to another; in these cases, it doesn't matter whether the type is signed or unsigned, as long as it's the right size.
Therefore, the general rule is that any pointer-sized value becomes
IntPtr
, andDWORD
andQWORD
becomeU?Int32
andU?Int64
, respectively.