Маршалировать структуру C в C#

Я пытаюсь вызвать функцию в 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;

и мой код C# выглядит так:

[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);
}

Моя проблема заключается в том, что всякий раз, когда я вызываю функцию WFSGetInfo, она будет успешной (hResult == 0), но только RequestID в wfsRESULT будет заполнена, а все остальные значения будут равны 0 (значение по умолчанию), и когда я пытаюсь преобразовать lpBuffer в WFSPINSTATUS, произошло следующее исключение. System.NullReferenceException: 'Object reference not set to an instance of an object.'

Не думаю что проблема в вызываемой dll msxfs т.к. это стандартная dll windows.

Я пробую много решений и методов (например, я пытаюсь установить макет SYSTEMTIME на Explicit), но с тем же результатом; Я не буду добавлять свои испытания, чтобы сократить код.

Я провел много поисков относительно структуры маршалинга и объединения в C, и следующий сайт оказался очень полезным Маршалинг с C#

Я не уверен, что эта информация полезна, но я создаю CEN/XFS интеграцию с устройством EPP.


person Ebraheem    schedule 29.03.2020    source источник
comment
Этот вопрос может быть полезен (если вы пропустили его в своем исследовании).   -  person TripleAccretion    schedule 29.03.2020
comment
Является ли lpBuffer нулевым? Если он равен нулю, ваши входные параметры не возвращают никаких данных. Если вы возвращаете ноль, это означает, что ваш ввод действителен, но не обязательно есть какие-либо результаты. Если lpBuffer не равен нулю, то он указывает на неуправляемую память, и вам нужно использовать Marshal.PtrToStructure, чтобы получить структуру WFSPINSTATUS.   -  person jdweng    schedule 29.03.2020
comment
@jdweng значение lpBuffer равно 0x00000000. и, как указано в документации, возвращаемый функцией результат должен быть возвращен в hResult. Я пытаюсь установить его значение равным 100, чтобы убедиться, что оно не является значением по умолчанию, прежде чем отправлять его, и когда оно вернулось, его значение все еще было 100.   -  person Ebraheem    schedule 29.03.2020
comment
Что в документации говорится о 100 для hResult?   -  person jdweng    schedule 29.03.2020
comment
@jdweng в документации указано, что значение hResult будет похоже на возвращаемое значение функции. Когда я вызываю функцию, она возвращает 0, что означает успех, и значение hResult тоже будет равно 0. Я не был уверен, был ли заполнен hResult успешно или он возвращает 0, поскольку это значение по умолчанию для in, поэтому я установил его значение в 100 перед отправкой запроса, и он возвращается как есть, что означает, что он не был заполнен маршалом.   -  person Ebraheem    schedule 29.03.2020
comment
Я не знаю, как это использовать в C#, но если это поможет вам, в C, когда вы хотите вызвать WFSGetInfo, вам нужно определить lppResult следующим образом: LPWFSRESULT lpResult = NULL;, и передать адрес указателя функции: WFSGetInfo(...., &lpResult). XFS выделит вам память. После того, как вы используете эту информацию, вам нужно освободить этот lpResult.   -  person SuperG280    schedule 30.03.2020