在更新第三方库以便在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签名中有效。
我对设计感到困惑。为什么需要/使用指针指针?
答案 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,否则数据仅被封送到 >本机代码。如果需要在参数中接收修改后的值(由变量声明为指针的事实表示),则需要使用ref
或out
来指示P / Invoke在函数执行完毕后,您需要将本机代码的数据封送 out 的API。