[英]Pass array of struct to C from C# via struct pointer
我想將一個結構數組從 C# 傳遞給 C dll。
C中的結構定義:
typedef struct{
BYTE name[32];
DWORD age;
}DATA;
我將結構編組如下:
[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] name;
public int age;
}
我要傳遞的 C 函數定義:
void test_data(DATA * pStruct, DWORD length){
_tprintf("test start\n");
if (!pData)
{
_tprintf("pData is NULL\n");
}
unsigned int i,j;
for(i = 0; i < length; i++){
_tprintf("name: ");
for(j = 0; j < 32; j++){
_tprintf("%x ",pData[i].name[j]);
}
_tprintf("\n");
_tprintf("age: %d",pData[i].age);
_tprintf("\n");
}
_tprintf("test finish\n");
}
C#中的函數簽名:
[DllImport("a.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void test_data(ref DATA pData, int length);
C#中的設置:
int length = 10;
DATA[] arr = new DATA[length];
for(int i = 0; i < length; i++){
arr[i].name = new byte[32];
arr[i].age = 10;
}
test_data(ref arr[0], length);
但我得到了這些輸出:
test start
name: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
age: 10
name: 7c 67 9a 2 a 0 0 0 1 0 0 0 2 0 0 0 eb 9 77 67 a4 eb 8f 0 0 0 0 0 2 0 0 0
age: 43673448
test finish
第一個是正確的,但第二個似乎很奇怪,我認為我通過引用或進行設置的方式有問題。
我的靈感來自 SCardTransmit 函數中的pinvoke 網絡,它使用ref rapdu[0]
將 C# 中的字節數組傳遞給 C 中的byte *
如何正確地做到這一點?
這不是您將結構數組從托管代碼編組為本機代碼的方式。
在您的 P/Invoke 聲明中:
[DllImport("a.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void test_data(ref DATA pData, int length);
ref DATA pData
編組到指向單個DATA
對象的指針。 無法保證陣列的其余部分將與它一起發送。 如果您的結構是blittable ,它可能會起作用,因為然后編組它只涉及固定數組,然后將其地址按原樣傳遞給 C 函數。 但是,唉,該結構包含一個數組,它是一個引用類型。 當您將它傳遞給 C 函數時,封送拆收器必須進行復制以獲取具有正確布局的結構。 因此,當您通過ref arr[0]
時,您只會發送一份副本,然后您的 C 代碼會直接離開緩沖區的末尾,並且您會遇到未定義的行為。 而且,在更哲學的層面上, pData
應該是一個數組也不太清楚。
因此,要發送整個批次,只需將您的參數聲明為數組, 如文檔中所述,其余的將由編組器完成:
[DllImport("a.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void test_data(DATA[] pData, int length);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.