c 调用c语言dll数组,C#调用C类型dll入参为struct的问题详解
前言
C# 可以通過 DllImport 的方式引用 C 類型的 dll。但很多 dll 的參數不會是簡單的基礎類型,而是結構體 struct 。因此就需要在 C# 端定義同樣的結構體類型,才能實現調用 C 類型 dll。這里例舉幾種不同的結構體情況,以及其對應的解決方案。
基礎調用方式
對于一個結構體類型:
typedef struct DATA
{
int nNumber;
float fDecimal;
};
在 C# 端就需要定義為
[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
public int nNumber;
public float fDecimal;
}
包含字符數組
對于一個包含字符數組的結構體類型:
typedef struct DATA
{
int nNumber;
float fDecimal;
char szString[256];
};
在 C# 端就需要使用 Marshal 設置數據空間大小,同時最好定義一個初始化函數與 get 的定義
[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
void alloc() {
szString = new char[256];
}
string sString {
get {
int nLength = 256;
string sData = "";
for (int i = 0; i < nLength; i++)
{
if (szData[i] == '\0') break;
sData += szData[i];
}
return sData;
}
}
public int nNumber;
public float fDecimal;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
char[] szString;
}
包含字符二維數組
對于一個包含字符二維數組的結構體類型:
typedef struct DATA
{
int nNumber;
float fDecimal;
char szString[6][256];
};
在 C# 端同樣需要使用 Marshal 設置數據空間大小,需要將兩個 Size 相乘,并定義一個初始化函數。同時在做一個 get 的定義。
[StructLayout(LayoutKind.Sequential)]
public struct DATA
{
void alloc() {
szString = new char[256 * 6];
}
public string[] sStrings
{
get {
int nSize = 6, nLength = 256;
string[] sDatas = new string[nSize];
for (int i = 0; i < nSize; i++)
{
for (int j = 0; j < nLength; j++)
{
if (szData[i * nLength + j] == '\0') break;
sData += szData[i * nLength + i];
}
sDatas[i] = sData;
}
return sDatas;
}
}
public int nNumber;
public float fDecimal;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256 * 6)]
char[] szStrings;
}
dll 入參為結構體數組
若有一個這樣的 C dll 函數定義:
void FnCall(DATA* datas);
// 調用方式
DATA datas[10];
fnCall(datas);
那么,在 C# 中要實現等價調用:
// 首先 Import 函數
[DllImport("Module.dll")]
public static extern void FnCall(IntPtr pInfo); // 注意入參要定義為指針
// 再定義定義結構體數組
int nCount = 10;
DATA datas = new DATA[nCount];
// 再分配內存空間
int nSize = Marshal.SizeOf(typeof(DEVICE_INFO));
IntPtr Dataptr = Marshal.AllocHGlobal(nSize * nCount);
// 調用函數
FnCall(Dataptr);
// 復制數據到結構體中
for (int i = 0; i < nCount; i++)
{
IntPtr ptr = (IntPtr)((UInt32)Dataptr + i * size);
datas[i] = (DEVICE_INFO)Marshal.PtrToStructure(ptr, typeof(DEVICE_INFO));
}
// 釋放內存空間
Marshal.FreeHGlobal(Dataptr);
另外,如果你要調用的 dll 是非 C 類型 dll,而是 C++ Class。那么我們就可以將其再包裝一層,轉換為 C 類型 dll。
例如:
class Example {
public:
int MethodCall();
};
那么就可以編寫 C 類型的 dll。
extern "C" {
Example* Example_New() {
return new Example();
}
int Example_MethodCall(Example* p) {
return p->MethodCall();
}
void Example_Delete(Example* p) {
delete p;
}
}
C# 那邊就這樣導入
[DllImport("Module.dll")]
public static extern IntPtr Example_Create();
[DllImport("Module.dll")]
public static extern int Example_MethodCall(IntPtr value);
[DllImport("Module.dll")]
public static extern void Example_Delete(IntPtr value);
// 調用方式
IntPtr p = Example_Create();
Example_MethodCall(p);
Example_Delete(p);
至于 C 類型 dll 中其他類型變量在 C# 的對應,則可以參考 Microsoft 的 文檔 。
總結
到此這篇關于C#調用C類型dll入參為struct問題的文章就介紹到這了,更多相關C#調用C類型dll入參內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!
總結
以上是生活随笔為你收集整理的c 调用c语言dll数组,C#调用C类型dll入参为struct的问题详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何给路由器散热片路由器放在窗外如何散热
- 下一篇: token验证_如何利用 C# 爬取带