C#与C/C++的交互zz
C#與C++交互,總體來(lái)說(shuō)可以有兩種方法:
-
利用C++/CLI作為代理中間層
-
利用PInvoke實(shí)現(xiàn)直接調(diào)用
第一種方法:實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單直觀,并且可以實(shí)現(xiàn)C#調(diào)用C++所寫(xiě)的類(lèi),但是問(wèn)題是MONO構(gòu)架不支持C++/CLI功能,因此無(wú)法實(shí)現(xiàn)脫離Microsoft .NET Framework跨平臺(tái)運(yùn)行。
第二種方法:簡(jiǎn)單的實(shí)現(xiàn)并不麻煩,只要添加DllImportAttribute特性即可以導(dǎo)入C/C++的函數(shù),但是問(wèn)題是PInvoke不能簡(jiǎn)單的實(shí)現(xiàn)對(duì)C++類(lèi)的調(diào)用。在Warensoft3D中為了可以使用MONO實(shí)現(xiàn)跨平臺(tái)(當(dāng)然DirectX是不能跨平臺(tái)的),所以使用了本方法,下面將對(duì)本方法展開(kāi)詳細(xì)的說(shuō)明。
測(cè)試平臺(tái):
Windows7 64位,VS2010,.NET4.0
注意事項(xiàng):
PInvoke從功能上來(lái)說(shuō),只支持函數(shù)調(diào)用,在被導(dǎo)出的函數(shù)前面一定要添加extern "C"來(lái)指明導(dǎo)出函數(shù)的時(shí)候使用C語(yǔ)言方式編譯和連接,這樣保證函數(shù)定義的名字和導(dǎo)出的名字相同,否則如果默認(rèn)按C++方式導(dǎo)出,那個(gè)函數(shù)的名字就會(huì)變得亂七八糟,我們的程序就無(wú)法找到入口點(diǎn)了。
本文將說(shuō)明以下幾點(diǎn):
-
互調(diào)的基本原理
-
基本數(shù)據(jù)類(lèi)型的傳遞
-
指針的傳遞
-
函數(shù)指針的傳遞
-
結(jié)構(gòu)體的傳遞
互調(diào)的基本原理
首先,我們來(lái)看一個(gè)再常規(guī)不過(guò)的概念—"數(shù)據(jù)類(lèi)型"
我們知道在大多數(shù)的靜態(tài)語(yǔ)言中定義變量的時(shí)候都要先指定其數(shù)據(jù)類(lèi)型,所謂數(shù)據(jù)類(lèi)型,都是人們強(qiáng)加的一個(gè)便于記憶的名稱(chēng),究其本質(zhì)就是指明了這個(gè)數(shù)據(jù)在內(nèi)存里到底是占用了幾個(gè)字節(jié),程序在運(yùn)行的時(shí)候,首先找到這個(gè)數(shù)據(jù)的地址,然后再按著該類(lèi)型的長(zhǎng)度,讀取相對(duì)應(yīng)的內(nèi)存,然后再處理。
了解了前面這個(gè)事兒,所有編程語(yǔ)言之間進(jìn)行互調(diào)就有點(diǎn)門(mén)道兒了。對(duì)于不同語(yǔ)言之間的互調(diào),只要將該數(shù)據(jù)的指針(內(nèi)存地址)傳遞給另一個(gè)語(yǔ)言,在另一個(gè)語(yǔ)言中根據(jù)通信協(xié)議將指針?biāo)赶虻臄?shù)據(jù)存儲(chǔ)入長(zhǎng)度對(duì)應(yīng)的數(shù)據(jù)類(lèi)型即可,當(dāng)然要滿(mǎn)足以下幾點(diǎn):
對(duì)于像Java,.NET這樣有運(yùn)行時(shí)虛擬機(jī)編程語(yǔ)言來(lái)講,由于虛擬機(jī)會(huì)讓堆內(nèi)存來(lái)回轉(zhuǎn)移,因此,在進(jìn)行互調(diào)的時(shí)候,要保證正在被互調(diào)的數(shù)據(jù)所在的內(nèi)存一定要固定,不能被轉(zhuǎn)移。
有一些編程語(yǔ)言支持指針,有一些語(yǔ)言不支持指針(如Java),這個(gè)問(wèn)題并不重要,所謂指針,其實(shí)就是一個(gè)內(nèi)存地址,對(duì)于32位OS的指針是一個(gè)32位整數(shù),而對(duì)于64位機(jī)OS的指針是一個(gè)64位整數(shù)。因?yàn)榇蠖鄶?shù)語(yǔ)言中都有整型數(shù),所以可以利用整型來(lái)接收指針。
基本數(shù)據(jù)類(lèi)型的傳遞
互調(diào)過(guò)程中,最基本要傳遞的無(wú)非是數(shù)值和字符,即:int,long,float,char等等,但是此類(lèi)型非彼類(lèi)型,C/C++與C#中有一些數(shù)據(jù)類(lèi)型長(zhǎng)度是不一樣的,下表中列出常見(jiàn)數(shù)據(jù)類(lèi)型的異同:
C/C++
C#
長(zhǎng)度
short
short
2Bytes
int
int
4Bytes
long(該類(lèi)型在傳遞的時(shí)候常常會(huì)弄混)
int
4Bytes
bool
bool
1Byte
char(Ascii碼字符)
byte
1Byte
wchar_t(Unicode字符,該類(lèi)型與C#中的Char兼容)
char
2Bytes
float
float
4Bytes
double
double
8Bytes
最容易弄混的是就是long,char兩個(gè)類(lèi)型,在C/C++中l(wèi)ong和int都是4個(gè)字節(jié),都對(duì)應(yīng)著C#中的int類(lèi)型,而C/C++中的char類(lèi)型占一個(gè)字節(jié),用來(lái)表示一個(gè)ASCII碼字符,在C#中能夠表示一個(gè)字節(jié)的是byte類(lèi)型。與C#中char類(lèi)型對(duì)應(yīng)的應(yīng)該是C/C++中的wchar_t類(lèi)型,對(duì)應(yīng)的是一個(gè)2字節(jié)的Unicode字符。
下面通過(guò)實(shí)例來(lái)說(shuō)明調(diào)用過(guò)程:
第一步:
建立一個(gè)C++的Win32DLL,如下圖所示:
這里要注意選擇"Export symbols"導(dǎo)出符號(hào)。點(diǎn)擊完成。
第二步:
由于項(xiàng)目的名稱(chēng)是"TestCPPDLL",因此,會(huì)自動(dòng)生成TestCPPDLL.h和TestCPPDLL.cpp兩個(gè)文件,.h文件是要導(dǎo)出內(nèi)容的聲明文件,為了能清楚的說(shuō)明問(wèn)題,我們將TestCPPDLL.h和TestCPPDLL.cpp兩個(gè)文件中的所有內(nèi)容都刪除,然后在TestCPPDLL.h中添加如下內(nèi)容:
第一行代碼中定義了一個(gè)名為"TESTCPPDLL_API"的宏,該宏對(duì)應(yīng)的內(nèi)容是"__declspec(dllexport)"意思是將后面修飾的內(nèi)容定義為DLL中要導(dǎo)出的內(nèi)容。當(dāng)然你也可以不使用這個(gè)宏,可以直接將"__declspec(dllexport)"寫(xiě)在要導(dǎo)出的函數(shù)前面。
第二行中的"EXTERN_C",是在"winnt.h"中定義的宏,在函數(shù)前面添加"EXTERN_C"等同于在函數(shù)前面添加extern "C",意思是該函數(shù)在編譯和連接時(shí)使用C語(yǔ)言的方式,以保證函數(shù)名字不變。
第二行的代碼是一個(gè)函數(shù)的聲明,說(shuō)明該函數(shù)可以被模塊外部調(diào)用,其定義實(shí)現(xiàn)在TestCPPDLL.cpp中,TestCPPDLL.cpp的代碼如下所示:
第三步:
在編譯C++DLL之前,需要做以下配置,在項(xiàng)目屬性對(duì)話(huà)框中選擇"C/C++"|"Advanced",將Compile AS 選項(xiàng)的值改為"C++"。然后確定,并編譯。
生成的DLL文件如下圖所示:
第四步:
首先,添加一個(gè)C#的應(yīng)用程序,如果要在C#中調(diào)用C++的DLL文件,先要在C#的類(lèi)中添加一個(gè)靜態(tài)方法,并且使用DllImportAttribute對(duì)該方法進(jìn)行修飾,代碼如下所示:
DllImport中的第一個(gè)參數(shù)是指明DLL文件的位置,第二個(gè)參數(shù)"EntryPoint"用來(lái)指明對(duì)應(yīng)的C/C++中的函數(shù)名稱(chēng)是什么。"extern"關(guān)鍵字表明該處聲明的這個(gè)Add方法是一個(gè)外部調(diào)用。
該方法聲明完畢之后,就可以像調(diào)用一個(gè)普通的靜態(tài)方法一樣去使用了。
下面是示例程序:
class Program
{
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "Add")]
extern static int Add(int a, int b);
static void Main(string[] args)
{
int c = Add(1,2);
Console.WriteLine(c);
Console.Read();
}
}
在運(yùn)行C#程序之前,先要修改C#的項(xiàng)目屬性,如下圖所示:
將platform target設(shè)置為x86,并且允許非安全代碼(后面有用)。
然后運(yùn)行該C#程序,其結(jié)果如下圖所示:
第五步:
前面的Add方法中傳遞的是數(shù)值類(lèi)型(int),其他的數(shù)據(jù)類(lèi)型,如float,double,和bool類(lèi)型的傳遞方式是一樣的,下面演示如何傳遞字符串。
在TestCPPDLL.h中添加一個(gè)新的函數(shù)聲明,代碼如下:
EXTERN_C TESTCPPDLL_API void __stdcall WriteString(wchar_t*content);
這里的參數(shù)是wchar_t類(lèi)型的指針,對(duì)應(yīng)著C#中的char類(lèi)型。TestCPPDLL.cpp中添加如下代碼:
TESTCPPDLL_API void __stdcall WriteString(wchar_t*content)
{
??? cout<<content;
}
該代碼的功能就是將輸入的字符串通過(guò)C++在控制臺(tái)上輸出。下面是在C#中的聲明:
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "WriteString")]
extern unsafe static void WriteString(char*c);
調(diào)用過(guò)程如下所示:
//因?yàn)槭褂弥羔?#xff0c;因?yàn)橐暶鞣前踩?/p>
unsafe
{
//在傳遞字符串時(shí),將字符所在的內(nèi)存固化,
//并取出字符數(shù)組的指針
fixed (char* p = &("hello".ToCharArray()[0]))
{
//調(diào)用方法
WriteString(p);
}
}
其運(yùn)行效果如下圖所示:
3. 指針的傳遞
根據(jù)前面介紹的數(shù)據(jù)類(lèi)型對(duì)照表,我們可以直接在方法中傳遞指針,但是要注意的是我們常常需要將數(shù)組的指針(數(shù)據(jù)入口地址,第一個(gè)元素的地址),數(shù)據(jù)從C/C++到C#時(shí)問(wèn)題不大,但是如果從C#到C/C++時(shí)一定要將數(shù)組先固化,然后再傳遞處理。
下面演示如何傳遞指針,首先在TestCPPDLL.h中添加下列聲明:
//傳入一個(gè)整型指針,將其所指向的內(nèi)容加1
EXTERN_C TESTCPPDLL_API void __stdcall AddInt(int *i);
//傳入一個(gè)整型數(shù)組的指針以及數(shù)組長(zhǎng)度,遍歷每一個(gè)元素并且輸出
EXTERN_C TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arraylength);
//在C++中生成一個(gè)整型數(shù)組,并且數(shù)組指針?lè)祷亟oC#
EXTERN_C TESTCPPDLL_API int* __stdcall GetArrayFromCPP();
其實(shí)現(xiàn)寫(xiě)在TestCPPDLL.cpp中,代碼如下所示:
TESTCPPDLL_API void __stdcall AddInt(int *i)
{
??? (*i)++;
}
TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arrayLength)
{
int*currentPointer=firstElement;
for (int i = 0; i < arrayLength; i++)
??? {
??????? cout<<*currentPointer;
??????? currentPointer++;
??? }
??? cout<<endl;
}
int *arrPtr;
TESTCPPDLL_API int* __stdcall GetArrayFromCPP()
{
??? arrPtr=new int[10];
for (int i = 0; i < 10; i++)
??? {
??????? arrPtr[i]=i;
??? }
return arrPtr;
}
對(duì)應(yīng)調(diào)用的C#代碼如下所示:
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddInt")]
extern unsafe static void AddInt(int* i);
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddIntArray")]
extern unsafe static void AddIntArray(int* firstElement, int arraylength);
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "GetArrayFromCPP")]
extern unsafe static int* GetArrayFromCPP();
調(diào)用過(guò)程如下所示:
unsafe
{
// 調(diào)用C++中的AddInt方法
int i = 10;
AddInt(&i);
Console.WriteLine(i);
//調(diào)用C++中的AddIntArray方法將C#中的數(shù)據(jù)傳遞到C++中,并在C++中輸出
int[] CSArray = new int[10];
for (int iArr = 0; iArr < 10; iArr++)
{
CSArray[iArr] = iArr;
}
fixed (int* pCSArray = &CSArray[0])
{
AddIntArray(pCSArray, 10);
}
//調(diào)用C++中的GetArrayFromCPP方法獲取一個(gè)C++中建立的數(shù)組
int* pArrayPointer = null;
pArrayPointer = GetArrayFromCPP();
for (int iArr = 0; iArr < 10; iArr++)
{
Console.WriteLine(*pArrayPointer);
pArrayPointer++;
}
}
4. 函數(shù)指針的傳遞
前面說(shuō)明的都是簡(jiǎn)單數(shù)據(jù)類(lèi)型的及其指針的傳遞,利用PInvoke我們也可以實(shí)現(xiàn)函數(shù)指針的傳遞,C#中并沒(méi)有函數(shù)指針的概念,但是可以使用委托(delegate)來(lái)代替函數(shù)指針,關(guān)于C#中委托的說(shuō)明,可以參考筆者前面的一個(gè)文章:《C#委托及事件》
大家可能會(huì)問(wèn),為什么要傳遞函數(shù)指針呢?利用PInvoke可以實(shí)現(xiàn)C#對(duì)C/C++函數(shù)的調(diào)用,反過(guò)來(lái),我們能不能在C/C++程序運(yùn)行的某一時(shí)刻,來(lái)調(diào)用一個(gè)C#對(duì)應(yīng)的函數(shù)呢?(例如在C++中存在一個(gè)獨(dú)立線(xiàn)程,該線(xiàn)程可能在任意時(shí)刻觸發(fā)一個(gè)事件,并且需要通知C#)。這個(gè)時(shí)候,我們就有必要將一個(gè)C#中已經(jīng)指向某一個(gè)函數(shù)的函數(shù)指針(委托)傳遞給C++。
想要傳遞函數(shù)指針,首先要在C#中定義一個(gè)委托,并且在C++中定義一個(gè)函數(shù)指針,同時(shí)要保證委托和函數(shù)指針具備相同的函數(shù)原型,我們首先編寫(xiě)C#的代碼,如下所示:
//定義一個(gè)委托,返回值為空,存在一個(gè)整型參數(shù)
public delegate void CSCallback(int tick);
//定義一個(gè)用于回調(diào)的方法,與前面定義的委托的原型一樣
//該方法會(huì)被C++所調(diào)用
static void CSCallbackFunction(int tick)
{
Console.WriteLine(tick.ToString ());
}
//定義一個(gè)委托類(lèi)型的實(shí)例,
//在主程序中該委托實(shí)例將指向前面定義的CSCallbackFunction方法
static CSCallback callback;
在CS的主程序中讓callback指向CSCallbackFunction方法,代碼如下所示:
//調(diào)用委托所指向的方法
callback = CSCallbackFunction;
然后在C/C++中定義一個(gè)函數(shù)指針,并且添加一個(gè)用于設(shè)置函數(shù)指針的函數(shù),TestCPPDLL.h中的代碼如下所示:
//定義一個(gè)函數(shù)指針
typedef void (__stdcall *CPPCallback)(int tick);
//定義一個(gè)用于設(shè)置函數(shù)指針的方法,
//并在該函數(shù)中調(diào)用C#中傳遞過(guò)來(lái)的委托
EXTERN_C TESTCPPDLL_API void SetCallback(CPPCallback callback);
SetCallback函數(shù)的實(shí)現(xiàn)在TestCPPDLL.cpp中,代碼如下所示:
TESTCPPDLL_API void SetCallback(CPPCallback callback)
{
int tick=rand();
//下面的代碼是對(duì)C#中委托進(jìn)行調(diào)用
callback(tick);
}
在C#中添加SetCallback函數(shù)的聲明,代碼如下所示:
//這里使用CSCallback委托類(lèi)型來(lái)兼容C++里的CPPCallback函數(shù)指針
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SetCallback")]
extern static void SetCallback(CSCallback callback);
在C#中的調(diào)用過(guò)程如下所示:
//讓委托指向?qū)⒈换卣{(diào)的方法
callback = CSCallbackFunction;
//將委托傳遞給C++
SetCallback(callback);
SetCallback方法被執(zhí)行后,在C#中定義的CSCallbackFunction就會(huì)被C++所調(diào)用。
5. 結(jié)構(gòu)體的傳遞
傳遞結(jié)構(gòu)體的想法和傳遞一個(gè)int類(lèi)型數(shù)據(jù)類(lèi)似,struct中的數(shù)據(jù)是在內(nèi)存中順序排列的,只要保證保證以下幾點(diǎn),就可以直接傳遞結(jié)構(gòu)體,甚至是結(jié)構(gòu)體的指針:
-
要傳遞的成員為公有的值類(lèi)型字段
-
C#中結(jié)構(gòu)體字段類(lèi)型與C++結(jié)構(gòu)體中的字段類(lèi)型相兼容
-
C#結(jié)構(gòu)中的字段順序與C++結(jié)構(gòu)體中的字段順序相同,要保證該功能,需要將C#結(jié)構(gòu)體標(biāo)記為[StructLayout( LayoutKind.Sequential)]
下面通過(guò)代碼進(jìn)行說(shuō)明,首先在C#中添加一個(gè)結(jié)構(gòu)體,代碼如下所示:
[StructLayout( LayoutKind.Sequential)]
struct Vector3
{
public float X, Y, Z;
}
該結(jié)構(gòu)體表示一個(gè)3D向量,包括X,Y,Z三個(gè)float類(lèi)型的分量。
然后在TestCPPDLL.h中也定義一個(gè)相同結(jié)構(gòu)的結(jié)構(gòu)體,代碼如下所示:
struct Vector3
{
float X,Y,Z;
};
在TestCPPDLL.h中聲明一個(gè)用于傳遞Vector3結(jié)構(gòu)體的一個(gè)函數(shù),代碼如下所示:
EXTERN_C TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector);
在TestCPPDLL.cpp中將其實(shí)現(xiàn),代碼如下所示:
TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector)
{
??? cout<<"got vector3 in cpp,x:";
??? cout<<vector.X;
??? cout<<",Y:";
??? cout<<vector.Y;
??? cout<<",Z:";
??? cout<<vector.Z;
}
在C#中添加對(duì)SendStructFromCSToCPP函數(shù)的聲明,代碼如下所示:
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SendStructFromCSToCPP")]
extern static void SendStructFromCSToCPP(Vector3 vector);
C#中的調(diào)用過(guò)程如下所示:
//建立一個(gè)Vector3的實(shí)例
Vector3 vector = new Vector3() { X =10,Y=20,Z=30 };
//將vector傳遞給C++并在C++中輸出
SendStructFromCSToCPP(vector);
基輸出效果如下所示:
完整的TestCPPDLL.h代碼如下所示:
#define TESTCPPDLL_API __declspec(dllexport)EXTERN_C TESTCPPDLL_API int __stdcall Add(int a,int b);
EXTERN_C TESTCPPDLL_API void __stdcall WriteString(wchar_t*content);
//傳入一個(gè)整型指針,將其所指向的內(nèi)容加1
EXTERN_C TESTCPPDLL_API void __stdcall AddInt(int *i);
//傳入一個(gè)整型數(shù)組的指針以及數(shù)組長(zhǎng)度,遍歷每一個(gè)元素并且輸出
EXTERN_C TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arraylength);
//在C++中生成一個(gè)整型數(shù)組,并且數(shù)組指針?lè)祷亟oC#
EXTERN_C TESTCPPDLL_API int* __stdcall GetArrayFromCPP();
//定義一個(gè)函數(shù)指針
typedef void (__stdcall *CPPCallback)(int tick);
//定義一個(gè)用于設(shè)置函數(shù)指針的方法,
//并在該函數(shù)中調(diào)用C#中傳遞過(guò)來(lái)的委托
EXTERN_C TESTCPPDLL_API void __stdcall SetCallback(CPPCallback callback);
struct Vector3
{
float X,Y,Z;
};
EXTERN_C TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector);
完整的TestCPPDLL.CPP代碼如下所示:
#include "stdafx.h"#include <iostream>
#include "TestCPPDLL.h"
using namespace std;
TESTCPPDLL_API int __stdcall Add(int a,int b)
{
return a+b;
}
TESTCPPDLL_API void __stdcall WriteString(wchar_t*content)
{
wprintf(content);
printf("\n");
}
TESTCPPDLL_API void __stdcall AddInt(int *i)
{
(*i)++;
}
TESTCPPDLL_API void __stdcall AddIntArray(int *firstElement,int arrayLength)
{
int*currentPointer=firstElement;
for (int i = 0; i < arrayLength; i++)
{
cout<<*currentPointer;
currentPointer++;
}
cout<<endl;
}
int *arrPtr;
TESTCPPDLL_API int* __stdcall GetArrayFromCPP()
{
arrPtr=new int[10];
for (int i = 0; i < 10; i++)
{
arrPtr[i]=i;
}
return arrPtr;
}
TESTCPPDLL_API void __stdcall SetCallback(CPPCallback callback)
{
int tick=100;
//下面的代碼是對(duì)C#中委托進(jìn)行調(diào)用
callback(tick);
}
TESTCPPDLL_API void __stdcall SendStructFromCSToCPP(Vector3 vector)
{
cout<<"got vector3 in cpp,x:";
cout<<vector.X;
cout<<",Y:";
cout<<vector.Y;
cout<<",Z:";
cout<<vector.Z;
}
完整的C#代碼如下所示:
using System;using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "Add")]
extern static int Add(int a, int b);
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "WriteString")]
extern unsafe static void WriteString(char* c);
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddInt")]
extern unsafe static void AddInt(int* i);
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "AddIntArray")]
extern unsafe static void AddIntArray(int* firstElement, int arraylength);
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "GetArrayFromCPP")]
extern unsafe static int* GetArrayFromCPP();
//定義一個(gè)委托,返回值為空,存在一個(gè)整型參數(shù)
public delegate void CSCallback(int tick);
//定義一個(gè)用于回調(diào)的方法,與前面定義的委托的原型一樣
//該方法會(huì)被C++所調(diào)用
static void CSCallbackFunction(int tick)
{
Console.WriteLine(tick.ToString());
}
//定義一個(gè)委托類(lèi)型的實(shí)例,
//在主程序中該委托實(shí)例將指向前面定義的CSCallbackFunction方法
static CSCallback callback;
//這里使用CSCallback委托類(lèi)型來(lái)兼容C++里的CPPCallback函數(shù)指針
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SetCallback")]
extern static void SetCallback(CSCallback callback);
[StructLayout(LayoutKind.Sequential)]
struct Vector3
{
public float X, Y, Z;
}
[DllImport(@"E:\ex\TestCPPDLL\Debug\TestCPPDLL.dll", EntryPoint = "SendStructFromCSToCPP")]
extern static void SendStructFromCSToCPP(Vector3 vector);
static void Main(string[] args)
{
int c = Add(1, 2);
Console.WriteLine(c);
//因?yàn)槭褂弥羔?#xff0c;因?yàn)橐暶鞣前踩?br />
unsafe
{
//在傳遞字符串時(shí),將字符所在的內(nèi)存固化,
//并取出字符數(shù)組的指針
fixed (char* p = &("hello".ToCharArray()[0]))
{
//調(diào)用方法
WriteString(p);
}
}
unsafe
{
// 調(diào)用C++中的AddInt方法
int i = 10;
AddInt(&i);
Console.WriteLine(i);
//調(diào)用C++中的AddIntArray方法將C#中的數(shù)據(jù)傳遞到C++中,并在C++中輸出
int[] CSArray = new int[10];
for (int iArr = 0; iArr < 10; iArr++)
{
CSArray[iArr] = iArr;
}
fixed (int* pCSArray = &CSArray[0])
{
AddIntArray(pCSArray, 10);
}
//調(diào)用C++中的GetArrayFromCPP方法獲取一個(gè)C++中建立的數(shù)組
int* pArrayPointer = null;
pArrayPointer = GetArrayFromCPP();
for (int iArr = 0; iArr < 10; iArr++)
{
Console.WriteLine(*pArrayPointer);
pArrayPointer++;
}
}
//讓委托指向?qū)⒈换卣{(diào)的方法
callback = CSCallbackFunction;
//將委托傳遞給C++
SetCallback(callback);
//建立一個(gè)Vector3的實(shí)例
Vector3 vector = new Vector3() { X = 10, Y = 20, Z = 30 };
//將vector傳遞給C++并在C++中輸出
SendStructFromCSToCPP(vector);
Console.Read();
}
}
}
總結(jié)
以上是生活随笔為你收集整理的C#与C/C++的交互zz的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 面试进阶题集锦-持续更新
- 下一篇: C# where用法解析