首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# 調用 C++ DLL:結構體指針封送詳解

     編輯:程式設計綜合問答

問題場景

C++ 定義了包含指針的結構體:

typedef struct { BYTE byIndex; BYTE byRW; } PACKET;
typedef struct { PACKET* pPackets; INT32 iNumPackets; } BLOCK;
BOOL Transfer(BLOCK block);

需要在 C# 中正確定義結構體並調用 Transfer 函數。

C# 結構體定義與封送屬性

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PACKET
{
    public byte byIndex;
    public byte byRW;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BLOCK
{
    // 關鍵:使用 IntPtr 表示指針,配合 MarshalAs 指定數組封送方式
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
    public PACKET[] pPackets;  // C# 數組自動封送為連續內存塊
    public int iNumPackets;    // 數組長度,對應 SizeParamIndex=1
}

DllImport 簽名與調用

[DllImport("YourCppDll.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern bool Transfer(ref BLOCK block);  // 注意:C++ 傳值結構體較大時常用引用/指針,這裡用 ref 模擬

// 調用示例
public bool CallTransfer(PACKET[] packets)
{
    BLOCK block = new BLOCK();
    block.pPackets = packets;
    block.iNumPackets = packets.Length;
    return Transfer(ref block);
}

關鍵注意點

  1. 內存佈局一致:Pack = 1 對應 C++ #pragma pack(1),確保字節對齊一致。
  2. 指針轉數組:C++ PACKET* pPackets 配合長度字段,在 C# 直接用數組 PACKET[] 加 MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1),運行時自動分配非托管內存並拷貝數據。
  3. 調用約定:C++ 默認 __cdecl,C# 需顯式指定 CallingConvention.Cdecl。
  4. 結構體傳遞方式:C++ 若為 BOOL Transfer(BLOCK block)(傳值),C# 用 ref BLOCK 或 out BLOCK;若為 BOOL Transfer(BLOCK* block),C# 用 IntPtr 手動 Marshal.StructureToPtr。
  5. 內存釋放:若 C++ 內部分配內存並返回指針,C# 需調用對應的釋放函數;若由 C# 分配傳入,C# 負責釋放(數組自動由 GC 管理,但非托管副本需 Marshal.FreeHGlobal)。

完整示例(含內存手動管理版)

[DllImport("CppDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool Transfer(IntPtr pBlock);  // 對應 BLOCK*

public unsafe bool TransferPackets(PACKET[] packets)
{
    fixed (PACKET* p = packets)
    {
        BLOCK block = new BLOCK { pPackets = (IntPtr)p, iNumPackets = packets.Length };
        IntPtr pBlock = Marshal.AllocHGlobal(Marshal.SizeOf());
        Marshal.StructureToPtr(block, pBlock, false);
        bool ret = Transfer(pBlock);
        Marshal.FreeHGlobal(pBlock);
        return ret;
    }
}

參考資源

微軟官方文檔:默認封送行為、平台調用數據封送。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved