【问题标题】:How to handle optional struct parameters when calling C functions from C# [duplicate]从C#调用C函数时如何处理可选的结构参数[重复]
【发布时间】:2012-08-10 12:17:59
【问题描述】:

如何跳过 C# 中的可选参数 (pioRecvPci)? 我认为主要问题是在 C 中参数是一个指针,因此可以提供 NULL 而在 C# 中使用结构上的 ref 关键字,根据定义不能为空。

C 代码

typedef struct {
  DWORD dwProtocol;
  DWORD cbPciLength;
} SCARD_IO_REQUEST;

LONG WINAPI SCardTransmit(
      __in         SCARDHANDLE hCard,
      __in         LPCSCARD_IO_REQUEST pioSendPci,
      __in         LPCBYTE pbSendBuffer,
      __in         DWORD cbSendLength,
      __inout_opt  LPSCARD_IO_REQUEST pioRecvPci,
      __out        LPBYTE pbRecvBuffer,
      __inout      LPDWORD pcbRecvLength
    );

C# 代码

[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
    public int dwProtocol;
    public int cbPciLength;
}

[DllImport("winscard.dll")]
public static extern int SCardTransmit(
     int hCard, 
     ref SCARD_IO_REQUEST pioSendRequest, 
     ref byte SendBuff, 
     int SendBuffLen, 
     ref SCARD_IO_REQUEST pioRecvRequest, 
     ref byte RecvBuff, 
     ref int RecvBuffLen);

【问题讨论】:

  • 您可以使用class 代替(我隐约记得很久很久以前就成功使用过这种方法)。或者,将参数声明为 SCARD_IO_REQUEST? 可能会起作用,但这只是一个疯狂的猜测。

标签: c# c winscard


【解决方案1】:

您可以将struct 更改为class,然后传递null。请记住,C# struct 与 C++ struct 完全不同,在这里你真的想使用 C# class

或者,如果您总是想忽略pioRecvRequest,请更改SCardTransmit 的签名,使pioRecvRequest 的类型为IntPtr。然后传递IntPtr.Zero 的值。

实际上,SCARD_IO_REQUEST 只是一个标头,如果你想在调用中传递它,你将不得不自己管理这个结构和额外的缓冲区空间,所以IntPtr 是正确的选择。然后,您必须使用 Marshal 函数在调用之前分配和填充结构,并在调用之后解组数据并释放它。

【讨论】:

    【解决方案2】:

    C# 支持方法重载。您可以在这里利用一些东西,重新声明该方法,但现在给它一个 IntPtr 参数类型(无 ref)。并通过 IntPtr.Zero。

    第二种方法是自己编组结构。声明参数类型 IntPtr。并使用 Marshal.AllocHGlobal() 为结构分配内存, Marshal.StructureToPtr() 将结构复制到其中。 Marshal.FreeHGlobal() 通话后。或者通过 IntPtr.Zero。显然,重载技巧的痛苦要小得多。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-26
      • 2018-05-14
      • 2011-06-04
      • 1970-01-01
      • 1970-01-01
      • 2021-11-23
      • 2018-06-08
      • 1970-01-01
      相关资源
      最近更新 更多