从C#调用C函数时如何处理可选的struct参数

时间:2012-08-10 12:18:00

标签: c# c winscard

如何在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);

2 个答案:

答案 0 :(得分:3)

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

或者,如果您始终要忽略pioRecvRequest,请更改SCardTransmit的签名,以便pioRecvRequest的类型为IntPtr。然后通过IntPtr.Zero获取值。

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

答案 1 :(得分:3)

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

第二种方法是自己整理结构。声明参数类型IntPtr。并使用Marshal.AllocHGlobal()为结构分配内存,Marshal.StructureToPtr()将结构复制到其中。 Marshal.FreeHGlobal()通话结束后。或者通过IntPtr.Zero。显然,过载技巧不那么痛苦。