简体   繁体   English

正确的方法来组织SIZE_T *?

[英]Correct way to marshal SIZE_T*?

I have the following C++ function definition, which I am trying to call through PInvoke from managed code: 我有以下C ++函数定义,我试图通过托管代码通过PInvoke调用:

bool FooBar(SIZE_T* arg1);

My managed declaration looked as follows: 我的管理声明如下:

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

Some of you may notice the same bug I eventually did. 有些人可能会注意到我最终做的同样的错误。 This is not 64bit portable. 这不是64位便携式。 SIZE_T is of variable size (32-64 bit) as is the pointer to it. SIZE_T的大小可变(32-64位),指针也是如此。 On the managed size the pointer correctly translates to 64bit, but the uint does not, and you can end up with trash in the upper bits of arg1. 在托管大小上,指针正确转换为64位,但uint没有,并且您最终可以在arg1的高位中使用垃圾。 This was an especially persistent error since the trash was often just zeros :( 这是一个特别持久的错误,因为垃圾通常只是零:(

The only solution I have gotten to work is the following managed declaration: 我已经开始工作的唯一解决方案是以下管理声明:

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

This works of course because IntPtr can vary its size correctly. 这当然有效,因为IntPtr可以正确地改变它的大小。 In my code I just treat the IntPtr as an integer, and it works, though it looks like an ugly hack. 在我的代码中,我只是将IntPtr视为一个整数,它可以工作,虽然它看起来像一个丑陋的黑客。 It seems to me there should be some way to specify this properly, perhaps using UnmanagedType.SysUInt, but I have been unable to come up with any other working solution. 在我看来应该有一些方法来正确指定,也许使用UnmanagedType.SysUInt,但我无法提出任何其他工作解决方案。

Using IntPtr and/or UIntPtr is doing it properly - the types are there specifically for this purpose! 使用IntPtr和/或UIntPtr 适当做-的类型有专门用于此目的! I do not understand why you consider it an "ugly hack". 我不明白为什么你认为这是一个“丑陋的黑客”。 I'm also not sure what your proposed alternative would be - any kind of attribute to allow values to be mapped to uint would be inherently wrong, because C# uint is guaranteed to be 32-bit regardless of the architecture, and so on 64-bit platform, to marshal it correctly, it would have to trim half of it, losing data, and likely rendering the result useless. 我也不确定你提议的替代方案是什么 - 允许将值映射到uint任何类型的属性本质上都是错误的,因为无论架构如何,C# uint都保证是32位的,所以64-位平台,要正确编组它,它必须修剪一半,丢失数据,并可能使结果无用。

UIntPtr is the correct type to use. UIntPtr是要使用的正确类型。

size_t is an unsigned, pointer-sized integer and that's exactly what UIntPtr means. size_t是一个无符号的,指针大小的整数,这正是UIntPtr的含义。 The "ptr" in the name can be a bit confusing, I agree. 我同意,名字中的“ptr”可能有点令人困惑。 It doesn't actually mean "this is a pointer", it means "this is a pointer-sized integer". 它实际上并不意味着“这是一个指针”,它意味着“这是一个指针大小的整数”。 So your declaration would be: 所以你的声明是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM