.net 调用指针到指针?

.net 调用指针到指针?,.net,pinvoke,.net,Pinvoke,在更新第三方库以在x64上正常工作时,它使用int作为指针,我查看了p/Invoke签名 其中一个需要 __out LPSCARDCONTEXT phContext 这是在WinSCard.h中定义的 typedef ULONG_PTR SCARDCONTEXT; typedef SCARDCONTEXT *PSCARDCONTEXT, *LPSCARDCONTEXT; 我对C++不太熟悉,所以如果我错了请指正。这意味着LPSCARDCONTEXT是指向ULONG_PTR的指针,ULONG

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

其中一个需要

__out  LPSCARDCONTEXT phContext
这是在WinSCard.h中定义的

typedef ULONG_PTR SCARDCONTEXT;
typedef SCARDCONTEXT *PSCARDCONTEXT, *LPSCARDCONTEXT;
我对C++不太熟悉,所以如果我错了请指正。这意味着LPSCARDCONTEXT是指向ULONG_PTR的指针,ULONG_PTR也是指针。这也解释了为什么在P/Invoke签名中IntPtr phContext不起作用,而ref IntPtr phContext起作用


我被这个设计搞糊涂了。为什么需要/使用指向指针的指针?

你的理解不太正确。ULONG_PTR是一种无符号整数类型,其宽度至少与指针相同。这意味着您可以从任何指向ULONG_PTR的指针进行强制转换,然后再返回,而不会丢失信息

ULONG_PTR的命名显然欺骗了你,让你相信它代表一个指针,而事实上,它的意图是表明它与指针一样宽

你可以把ULUNGU-PTR看作C++等价于UTIPTR .< /P> 我猜您的函数正在从本机返回到托管的SCARDCONTEXT值。您可以这样P/调用它:

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

我选择使用IntPtr而不是UIntPtr,因为我想您永远不需要对值做任何事情,因为这可能是一个不透明的句柄。IntPtr通常比UIntPtr更受欢迎,因为它符合CLS。

您的理解不太正确。ULONG_PTR是一种无符号整数类型,其宽度至少与指针相同。这意味着您可以从任何指向ULONG_PTR的指针进行强制转换,然后再返回,而不会丢失信息

ULONG_PTR的命名显然欺骗了你,让你相信它代表一个指针,而事实上,它的意图是表明它与指针一样宽

你可以把ULUNGU-PTR看作C++等价于UTIPTR .< /P> 我猜您的函数正在从本机返回到托管的SCARDCONTEXT值。您可以这样P/调用它:

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

我选择使用IntPtr而不是UIntPtr,因为我想您永远不需要对值做任何事情,因为这可能是一个不透明的句柄。IntPtr通常比UIntPtr更受欢迎,因为它符合CLS。

虽然我认为@David Hefferman是绝对正确的,但问题的第二部分他没有提到

他没有提到的部分是指向指针的指针确实存在,因为它们有时被用作从函数返回指针作为参数。这里有一个更详细的例子


另外,需要使用ref关键字以便正确地将数据封送到C代码中的原因是,除非使用ref,否则数据仅封送到本机代码中。如果您需要在参数中接收修改后的值,该值由变量声明为指针这一事实表示,那么您需要使用ref或out向P/Invoke API指示,在函数执行完毕后,您需要从本机代码中封送数据。

,而我认为@David Hefferman是绝对正确的问题的第二部分他没有提到

他没有提到的部分是指向指针的指针确实存在,因为它们有时被用作从函数返回指针作为参数。这里有一个更详细的例子


另外,需要使用ref关键字以便正确地将数据封送到C代码中的原因是,除非使用ref,否则数据仅封送到本机代码中。如果您需要在参数中接收修改后的值,该值由变量声明为指针这一事实表示,那么您需要使用ref或out向P/Invoke API指示,在函数执行完毕后,您需要从本机代码中封送数据。

了解API的一些想法

将SCARDCONTEXT定义为ULONG_PTR是一种用于精确隐藏指针指向的内容的常用技术。它不是一个指向LONG的指针,它是一个“unsigned LONG”,包含一个指向某个结构的指针,而这个结构你没有定义,因为你不需要它。当您将SCARDCONTEXT传递给某个智能卡函数时,它会在内部强制转换为指向不透明结构的指针。当它返回这些指针中的一个给你时,它就会被转换为SCARDCONTEXTfirst

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

所有这些的要点是,您可以忽略SCARDCONTEXT包含指针这一事实。只需将其视为不透明值即可。然后PSCARDCONTEXT和LPSCARDCONTEXT变得更容易理解,因为它们只是指向不透明值的指针。不需要为指针到指针的指针操心p> 理解API的一些想法

将SCARDCONTEXT定义为ULONG_PTR是一种用于精确隐藏指针指向的内容的常用技术。它不是一个指向LONG的指针,它是一个“unsigned LONG”,包含一个指向某个结构的指针,而这个结构你没有定义,因为你不需要它。当您将SCARDCONTEXT传递给某个智能卡函数时,它会在内部强制转换为指向不透明结构的指针。当它返回这些指针中的一个给你时,它就会被转换为SCARDCONTEXTfirst

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



所有这些的要点是,您可以忽略SCARDCONTEXT包含指针这一事实。只需将其视为不透明值即可。然后PSCARDCONTEXT和LPSCARDCONTEXT变得更容易理解,因为它们只是指向不透明值的指针。无需为指向指针的指针而烦恼。

我已将签名更改为使用ref uintpttr phContext,它似乎仍然有效,我想它比作为指针的负数更有意义+1@Stijn请参阅我的最新答案。我认为实际上应该使用out而不是ref。我已经将签名更改为使用ref UIntPtr phContext,它似乎仍然有效,我想它比负数作为指针更有意义+1@Stijn请参阅我的最新答案。我认为实际上你应该用out而不是ref。我认为你的最后一段是不对的。我觉得SCARDCONTEXT是一种不透明的句柄类型。然后,当使用带有签名uu out LPSCARDCONTEXT phContext的参数时,该参数建议使用指针按引用传递。我怀疑这真的是C风格的代码,不使用pass-by引用,因为C只有pass-by值。我不会对答案/讨论的其他部分发表评论。@Stijn主要问题是答案的主体是最后一段,它错误地使用了术语marshal。使用ref,无论如何,它应该是out而不是ref,但这是一个次要问题,不会导致编组。它所做的一切都确保参数的值IntPtr被传递回调用方。这里没有编组。那么我是否应该撤销接受,当@Miky删除该段落时,我可以再次接受它?@Stijn,我很高兴我的回答帮助了你@大卫-我想我没有用错这个术语。尽管它可能不会修改数据,但在使用P/Invoke API时,会涉及到互操作封送处理程序。因此,为了论证起见,我认为我们可以称之为编组。请参阅此概述以了解原因:我认为您的最后一段不正确。我觉得SCARDCONTEXT是一种不透明的句柄类型。然后,当使用带有签名uu out LPSCARDCONTEXT phContext的参数时,该参数建议使用指针按引用传递。我怀疑这真的是C风格的代码,不使用pass-by引用,因为C只有pass-by值。我不会对答案/讨论的其他部分发表评论。@Stijn主要问题是答案的主体是最后一段,它错误地使用了术语marshal。使用ref,无论如何,它应该是out而不是ref,但这是一个次要问题,不会导致编组。它所做的一切都确保参数的值IntPtr被传递回调用方。这里没有编组。那么我是否应该撤销接受,当@Miky删除该段落时,我可以再次接受它?@Stijn,我很高兴我的回答帮助了你@大卫-我想我没有用错这个术语。尽管它可能不会修改数据,但在使用P/Invoke API时,会涉及到互操作封送处理程序。因此,为了论证起见,我认为我们可以称之为编组。请参阅此概述了解原因:因此,在编写本机代码时,开发人员不会接触到SCARDCONTEXT的含义,但在编写托管代码时,编写P/Invoke部分的开发人员会接触到SCARDCONTEXT的含义。正确吗?@Stijn在托管代码和非托管代码中,SCARDCONTEXT只是一个值。除了识别某些东西,它实际上没有“意义”。但在p/invoking windows api函数中,除非它们是基于com的函数,否则这些函数总是以C风格的函数为导向,而不是以.net面向对象的函数为导向,这样就跨越了两种不同的代码风格。因此,您必须了解windows api中使用的代码“习惯用法”。这就是我想解释的。其他人已经很好地解释了为什么使用指针从函数返回值,以及p/invoke签名应该是什么。@Stijn顺便说一句,如果您不知道,您可以在上找到一组相当完整的p/invoke函数签名。Clic
k左侧导航栏上的“winscard”条目,查看人们为其提供签名的函数。因此,在编写本机代码时,开发人员不会接触到SCARDCONTEXT的含义,但在编写托管代码时,编写P/Invoke部分的开发人员会接触到该含义。正确吗?@Stijn在托管代码和非托管代码中,SCARDCONTEXT只是一个值。除了识别某些东西,它实际上没有“意义”。但在p/invoking windows api函数中,除非它们是基于com的函数,否则这些函数总是以C风格的函数为导向,而不是以.net面向对象的函数为导向,这样就跨越了两种不同的代码风格。因此,您必须了解windows api中使用的代码“习惯用法”。这就是我想解释的。其他人已经很好地解释了为什么使用指针从函数返回值,以及p/invoke签名应该是什么。@Stijn顺便说一句,如果您不知道,您可以在上找到一组相当完整的p/invoke函数签名。单击左侧导航栏上的“winscard”条目,查看人们为其提供签名的功能。