在C# 呼叫 C++ DLL,如何把一個復雜的結構體指標作為引數傳過去:
結構體如下:
struct TagPoint
{
int x;
int y;
};
struct TagRect
{
int x;
int y;
int width;
int Height;
};
struct TagInfos
{
char* name;
TagPoint* pointList;
TagRect rect;
int pointCount;
};
struct FSize
{
int width;
int height;
int depth;
};
struct TagImageInfos
{
char* path;
TagInfos* tagList;
FSize imageSize;
bool isLable;
int tagCount;
};
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TagPoint
{
/// int
public int x;
/// int
public int y;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TagRect
{
/// int
public int x;
/// int
public int y;
/// int
public int width;
/// int
public int Height;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TagInfos
{
/// char*
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string name;
/// TagPoint**
public System.IntPtr pointList;
/// TagRect
public TagRect rect;
/// int
public int pointCount;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct FSize
{
/// int
public int width;
/// int
public int height;
/// int
public int depth;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct TagImageInfos
{
/// char*
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string path;
/// TagInfos**
public System.IntPtr tagList;
/// FSize
public FSize imageSize;
/// boolean
public bool isLable;
/// int
public int tagCount;
}
要從C#傳一個TagImageInfos結構體給C++,目前遇到的問題是結構體里面的指標傳值問題
掙扎了好幾天.還是沒有完全解決,請各位大神幫忙提供個思路或者解決辦法,謝謝!
uj5u.com熱心網友回復:
我覺著你應該需要一個工具來幫你簡化一下作業。百度“interopsignaturetoolkit ”這是一個工具,雖然工具翻譯的多少需要修改一下,不過至少可以簡化你80%的作業
另外如果有h頭用“swig”也可以,不過swig翻譯的東西太笨重,所以一般我也不推薦,除非是有超大量的翻譯作業要做,否則還還是建議用interopsignaturetoolkit一條一條翻譯來的保險點
uj5u.com熱心網友回復:
感謝提醒,上述C#代碼是已經使用了interopsignaturetoolkit 的結果,也是為了保證C++和C#兩端代碼型別及結構一致
uj5u.com熱心網友回復:
我大概明白你的問題了你估計是 /// TagPoint** 找個玩意卡住了
這個東西其實是 陣列的表達。就是TagPoint[],當然因為俺們沒辦法確定陣列到底多大,所以不能直接定義,所以采用inptr接收
接收后再根據pointCount 得到陣列大小。然后再copy對應得位元組到記憶體(pointCount *sizeof(TagPoint))
uj5u.com熱心網友回復:
如果不是他傳給你,是你傳給他其實是
TagPoint[] TagPoints=new TagPoint[20]
pointList =Marshal.UnsafeAddrOfPinnedArrayElement(TagPoints,0)
也就是這個陣列的第一元素的指標。
uj5u.com熱心網友回復:
大神厲害,的確是這里的問題:TagInfos**和TagPoint**這兩個點,未知陣列大小,就按照指標傳遞
之前測驗的情況也說明下:
1. 傳一個TagPoint[](用IntPtr代替)到C++端,C++端用一級指標(TagPoint*)接收,結果不對;C++端用二級指標(TagPoint**)接收,結果就對了;
2. 傳一個TagInfos[](用IntPtr代替,)到C++端,C++端TagInfos結構體里面TagPoint定義為二級指標,然后用二級指標(TagInfos**)接收,結果不對;后來請教了一位大神,說是記憶體不連續的問題(自定義陣列轉成IntPtr的問題),就按照大神提供的方法處理了一下,結果也ok了
3.現在要傳一個TagImageInfos物件給C++端(TagImageInfos結構體里面包含一個TagInfos陣列,TagInfos陣列里面的每一個元素都包含一個TagPoint陣列),無論怎么改目前C++端接收到的結果都是錯的
目前的問題應該和第二次測驗遇到的問題一樣,但是不知道如何處理才能解決,大致情況就是這樣
uj5u.com熱心網友回復:
大神的這個方法只能解決單純傳TagPoint[](C++ ----->C#),我上面測驗的第二個問題的解決方法就是這個,和你的差不多
private IntPtr Cov<T>(T[] ps)
{
int ik = ps.Length;
int len = Marshal.SizeOf(typeof(T));
IntPtr ptr = Marshal.AllocHGlobal(len * ik);
IntPtr[] ts = new IntPtr[ik];
for (int i = 0; i < ik; i++)
{
ts[i] = Marshal.UnsafeAddrOfPinnedArrayElement(ps, i);
}
Marshal.Copy(ts, 0, ptr, ik);
return ptr;
}
但是實際上傳的結構體型別還要復雜一點
uj5u.com熱心網友回復:
我覺得你的問題是不是因為C++和C#對結構體和物件的記憶體分配方式不同~這樣的話兩端代碼可能不應該一致。用一塊結構確定的記憶體保存一個中間量,完了再把中間量指標傳過去,C++這邊再決議下套到對應的結構里,直接轉的話可能會有問題。
C++端么 再包一個dll吧 可能比較繞~~ 不知道還有沒有更好的方法
uj5u.com熱心網友回復:
謝謝!看結果是記憶體相關的問題,但暫時沒有想到直接的解決辦法
目前使用的替代辦法是C#傳一個json字串給出C++,然后對json字串進行決議,也能得到想要的資料,這樣的話C++端的代碼會顯得復雜點,但目前只想到它了...
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/39809.html
標籤:C#
上一篇:有沒有識別聲音轉文字的軟體?
