2

I'm trying to call a function in C that has the following signature from C#

typedef struct _wfs_result 
{
   ULONG RequestID;
   USHORT hService;
   TIMESTAMP tsTimestamp;
   LONG hResult;
   union {
      DWORD dwCommandCode;
      DWORD dwEventID;
   } u;
   LPVOID lpBuffer;
} WFSRESULT, *LPWFSRESULT;

LONG WFSGetInfo(USHORT hService, DWORD dwCategory, LPVOID lpQueryDetails, DWORD dwTimeOut, LPWFSRESULT *lppResult)

typedef struct _wfs_pin_status
{
   WORD fwDevice;
   WORD fwEncStat;
   LPSTR lpszExtra;
   DWORD dwGuidLights[WFS_PIN_GUIDLIGHTS_SIZE];
   WORD fwAutoBeepMode;
   DWORD dwCertificateState;
   WORD wDevicePosition;
   USHORT usPowerSaveRecoveryTime;
} WFSPINSTATUS, *LPWFSPINSTATUS;

and my C# code look like this:

[DllImport("msxfs")]
public static extern int WFSGetInfo(ushort hService, uint dwCategory, IntPtr lpQueryDetails, uint dwTimeOut, ref WFSRESULT lppResult);

[StructLayout(LayoutKind.Explicit)]
public struct WFSRESULT
{
   [FieldOffset(0)]
   public uint RequestID;
   [FieldOffset(4)]
   public ushort hService;
   [FieldOffset(6)]
   public SYSTEMTIME tsTimestamp;
   [FieldOffset(22)]
   public int hResult;
   [FieldOffset(26)]
   public uint dwCommandCode;
   [FieldOffset(26)]
   public uint dwEventID;
   [FieldOffset(30)]
   public IntPtr lpBuffer; //It should be pointer to a structure that contain more information
}

[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
   public ushort wYear;
   public ushort wMonth;
   public ushort wDayOfWeek;
   public ushort wDay;
   public ushort wHour;
   public ushort wMinute;
   public ushort wSecond;
   public ushort wMilliseconds;
}

[StructLayout(LayoutKind.Sequential)]
public struct WFSPINSTATUS
{
   public ushort fwDevice;
   public ushort fwEncStat;
   public string lpszExtra;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
   public uint[] dwGuidLights;
   public ushort fwAutoBeepMode;
   public uint dwCertificateState;
   public ushort wDevicePosition;
   public ushort usPowerSaveRecoveryTime;
}

private void WfsGetInfo()
{
   WFSRESULT wfsRESULT = new WFSRESULT();

   int hResult = WFSGetInfo(_lphService, InfoCommands.WFS_INF_PIN_CAPABILITIES, IntPtr.Zero, WFS_INDEFINITE_WAIT, ref wfsRESULT);

   WFSPINSTATUS pinStatus = Marshal.PtrToStructure<WFSPINSTATUS>(wfsRESULT.lpBuffer);
}

My problem that whenever I call WFSGetInfo function it will be succeeded (hResult == 0), but only RequestID in wfsRESULT will be filled and all other values will be 0 (default value), and when I try to convert lpBuffer to WFSPINSTATUS following exception occurred. System.NullReferenceException: 'Object reference not set to an instance of an object.'

I do not think the problem is in the called dll msxfs because It is a standard windows dll.

I try a lot of solution and techniques (for example I try to set SYSTEMTIME layout to Explicit) but with same result; I will not add my trials to shorten the code.

I done a lot of search regarding marshaling structure and union in C, and following site was very helpful Marshaling with C#

I'm not sure if this information is helpful but I'm building an CEN/XFS integration with EPP device.

Ebraheem
  • 603
  • 6
  • 24
  • [This question might be of some help](https://stackoverflow.com/q/45035424/10857604) (if you missed it in your research). – TripleAccretion Mar 29 '20 at 10:52
  • Is lpBuffer null? If it is null than your input parameters are not returning any data. If you are returning zero than it indicates you input are valid, but not necessarily there are any results. If lpBuffer is not null than it is pointing to non managed memory and you need to use Marshal.PtrToStructure to get the struct WFSPINSTATUS – jdweng Mar 29 '20 at 12:48
  • @jdweng the value of `lpBuffer` is `0x00000000`. and as documentation said the function returned result should be returned in `hResult`. I try to set it's value to 100 to make sure that it is not the default value before sending it, and when it returned it's value was still 100. – Ebraheem Mar 29 '20 at 12:56
  • What does the documentation say about 100 for hResult? – jdweng Mar 29 '20 at 13:36
  • @jdweng the documentation indicate that hResult value will be similar to function returned value. When I call the function it return 0 which mean success, and hResult value will be 0 too. I was not sure if hResult has been filled successfully or it return 0 as it is the default value of in, so I set it's value to 100 before sending the request and it return as is, which mean it was not filled by the marshal. – Ebraheem Mar 29 '20 at 13:59
  • I don't know about how to use it in C# but in case it helps you, in C, when you whant to call `WFSGetInfo`, you need to define `lppResult` like this: `LPWFSRESULT lpResult = NULL;`, and pass the pointer address to the funtion: `WFSGetInfo(...., &lpResult)`. XFS will allocate the memory for you. After you use this information, you need to free this `lpResult`. – SuperG280 Mar 30 '20 at 09:46

0 Answers0