簡體   English   中英

從C ++轉換Pinvoke結構

[英]Pinvoke struct translation from C++

以下是一些經過驗證的C ++:

typedef struct
{
  PVOID  buffer;
  UINT32 length;
} DATA_BUFFER;

typedef struct 
{
  DATA_BUFFER TxBuf [1];
  DATA_BUFFER RxBuf [1];
} JVM_COMM_BUFFER;

UINT32 SendAndRecv(
  IN    JHI_HANDLE        handle,
  IN    CHAR*             AppId,
  INOUT JVM_COMM_BUFFER* pComm
);

以下是我嘗試將其移植到C#的嘗試:

    [StructLayout(LayoutKind.Sequential)]
    public struct DATA_BUFFER
    {
        public byte[] buffer;
        public uint length;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct JVM_COMM_BUFFER
    {
        public DATA_BUFFER TxBuf;
        public DATA_BUFFER RxBuf;
    }

    [DllImport("jhi.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
    public static extern UInt32 SendAndRecv(IntPtr handle, string AppId, ref JVM_COMM_BUFFER pComm);

封送處理不會在C#中引發異常,但是對於C ++和C#版本,結果是不同的。 對我缺少的東西有任何想法嗎?

問題可能出在您的第一個結構中。 C ++定義包括一個指向數據緩沖區的指針,但Marshaller無法將其直接轉換為.NET byte[] (或者,如果將其轉換為另一個方向,它可能會將byte[]轉換為無效的指針,因此您的非法參數是錯誤)。 相反,您可以分兩個步驟手動執行此操作:

[StructLayout(LayoutKind.Sequential)]
public struct DATA_BUFFER
{
    public IntPtr buffer;
    public uint length;
}

然后使用Marshal手動讀取緩沖區(這只是我對Marshal API的記憶中的一個快速示例):

var txBufBytes = new byte[pComm.TxBuf.length];
Marshal.Copy(pComm.TxBuff.buffer, 0, pComm.TxBuf.length);

除此之外,正如注釋中提到的CharSet.Ansi如果您的本機代碼采用非Unicode /寬字符,則可能需要將CharSet設置為CharSet.Ansi

最后,第二個結構的C ++定義似乎定義了單元素數組,該數組實際上可能是指針,而不是將結構存儲在內存中。 如果是這種情況,您可能必須替換定義以對Interop使用IntPtr ,然后使用Marshal.PtrToStructure獲取實際結構。

通過比較C ++中的sizeof(...)和C#中的Marshal.SizeOf(...)來獲得結構定義,您至少應該比較結構大小是否相同。

鑒於您在注釋中所說的,您應該能夠使用我上面描述的DATA_BUFFER修改以及用於JVM_COMM_BUFFER的原始結構定義

[StructLayout(LayoutKind.Sequential)]
struct JVM_COMM_BUFFER
{
    public DATA_BUFFER TxBuf;
    public DATA_BUFFER RxBuf;
}

結合對DllImport的輕微修改

[DllImport("jhi.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern UInt32 SendAndRecv(IntPtr handle, string AppId, [In, Out] ref JVM_COMM_BUFFER pComm);

CharSet.Ansi對於確保將.NET字符串正確地編組為ansi字符串非常重要(假設您的本機C函數不希望使用wchar_t字符串類型)。 可能不需要[In, Out]屬性,但可能會提示編組如何正確控制該參數。

如果JVM_COMM_BUFFER確實是INOUT ,並且在調用該函數之前預先填充了數據,則可能需要確保數據全部有效。 您正在調用的函數可能具有有關其參數期望值的文檔。 但是,此處的定義應根據您提供的C ++定義正確地編組。

問題是僅分配內存和分配固定對象之間的區別。 一旦將其切換到固定對象,則除了緩沖區字段之外,沒有任何IntPtrs的簽名就可以正常工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM