How to handle optional struct parameters when calling C functions from C# [duplicate]
Frage
How can i skip the optional parameter (pioRecvPci) in C#? I think the main problem is that in C the parameter is a pointer so it is possible to supply NULL while in C# the ref keyword on a struct is used which can't be null by definition.
C Code
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# Code
[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);
Lösung
You can change the struct
to a class
and then pass null
. Remember that a C# struct
is quite different from a C++ struct
, and here your really want to use a C# class
.
Or if you always want to ignore pioRecvRequest
change the signature of SCardTransmit
so that pioRecvRequest
is of type IntPtr
. Then pass IntPtr.Zero
for the value.
Actually, the SCARD_IO_REQUEST
is just a header and if you want to pass it in the call you will have to manage this structure and the additional buffer space yourself anyway so IntPtr
is the right choice. You will then have to use the Marshal
functions to allocate and fill the structure before the call and unmarshal the data and free it after the call.
Andere Tipps
C# supports method overloads. Something you can take advantage of here, redeclare the method but now give it an IntPtr argument type (no ref). And pass IntPtr.Zero.
Second way is to marshal the structure yourself. Declare the argument type IntPtr. And use Marshal.AllocHGlobal() to allocate memory for the structure, Marshal.StructureToPtr() to copy the structure into it. Marshal.FreeHGlobal() after the call. Or pass IntPtr.Zero. Clearly the overload trick is much less painful.