P / Invoke指针指针?

时间:2011-05-17 15:37:00

标签: .net pinvoke

在更新第三方库以便在x64上正常工作时(它使用int作为指针),我正在查看P / Invoke签名。

其中一个需要

__out  LPSCARDCONTEXT phContext

这是在WinSCard.h中定义的

typedef ULONG_PTR SCARDCONTEXT;
typedef SCARDCONTEXT *PSCARDCONTEXT, *LPSCARDCONTEXT;

我对C ++并不熟悉,所以如果我错了,请纠正我。这意味着LPSCARDCONTEXT是指向ULONG_PTR的指针,它也是一个指针。这也解释了为什么IntPtr phContext无效,ref IntPtr phContext在P / Invoke签名中有效。

我对设计感到困惑。为什么需要/使用指针指针?

3 个答案:

答案 0 :(得分:2)

你的理解不太对。 ULONG_PTR是无符号整数类型,至少与指针一样宽。这意味着您可以从任何指针转换到ULONG_PTR并再次返回而不会丢失信息。

ULONG_PTR的命名显然诱使你相信它代表指针,而实际上意图是表明它是 wide 指针。

您可以将ULONG_PTR视为与UIntPtr等效的C ++。

我的猜测是你的函数从本机返回到托管SCARDCONTEXT值。你会像这样P / Invoke:

[DLLImport(...)]
void MyFunc(out IntPtr Context);

我选择使用IntPtr而不是UIntPtr因为我猜你永远不需要对值做任何事情,因为这可能是一个不透明的句柄。 IntPtr通常优先于UIntPtr,因为它符合CLS。

答案 1 :(得分:2)

关于理解API的一些想法。

SCARDCONTEXT定义为ULONG_PTR是一种常用技术,可以精确隐藏指针指向的内容。它实际上并不是指向LONG的指针,它是一个'unsigned long',包含指向某个结构的指针,因为你不需要它(opaque type)。当您将SCARDCONTEXT传递给其中一个智能卡函数时,它会内部转换为指向不透明结构的指针。当它返回给你的其中一个指针时,它首先被转换为SCARDCONTEXT

这是基于C的API中常见的封装技术,因为您可以在SCARDCONTEXT上执行的操作与SCARDCONTEXT的定义分开存在,而不是像在ULONG_PTR中那样作为绑定成员函数。基于对象的语言。作为@DavidHeffernan explained,这可行,因为unsigned long实际上是SCARDCONTEXT,可以包含指针。

所有这一切的要点是你可以忽略PSCARDCONTEXT包含指针的事实。只需将其视为不透明的值。然后LPSCARDCONTEXT和{{1}}变得更容易理解,因为它们只是指向不透明值的指针。不需要打扰指针指针。

答案 2 :(得分:1)

虽然我认为@David Hefferman是绝对正确的,但是他没有解决这个问题的第二部分。

他没有谈到的部分是指针的指针确实存在,因为它们有时用于返回函数作为参数的指针。这是一个更详细的discussion about the benefits of pointers-to-pointers

此外,您需要使用ref关键字以正确封送来自C#代码的数据的原因是,除非您使用ref,否则数据仅被封送到 >本机代码。如果需要在参数中接收修改后的值(由变量声明为指针的事实表示),则需要使用refout来指示P / Invoke在函数执行完毕后,您需要将本机代码的数据封送 out 的API。