这里讲C#调用C++的类,也是我真正想要的做的。网上关于这方面的知识挺杂,我折腾了好久终于搞定了。
大致有两种方法。第一种C#直接调,用到System.Runtime.InteropServices中的Marshal类,貌似这样可能通过直接操纵内存来实现调用,但我没有尝试;第二种方法是用managed C++包装native C++,然后供C#调用。这里详细讲一下这种方法,并基本考虑到了所有的情况。
1 //nativecpp.h
2 //nA不是C#调用对象,nB是,但nB中用到了nA类
3 class __declspec( dllexport ) nA //有人提醒我__declspec( dllexport )可以加在方法前面,//但不要加在类前面,否则会出现问题.但我去掉后编译就出错了。
4 {
5 char* Ama;
6 int Afoo();
7 };
8 //nB基本已经涵盖了所有的情况
9 class __declspec( dllexport ) nB
10 {
11 nA Bma;
12 int Bmb;
13 nA BmArr[];
14 bool Bfoo( char* a, nA[] b); //假设主要想调用这个函数,则包装时只要包装这个即可
15 };
用managed C++包装。在vs2008中建工程时选CLR Class Library即可。添加对上面生成的nativecpp.dll的引用。这里我的引用采用了C#的add reference的形式,而不是传统C++在linker中添加.lib的方式。
1 #include "nativecpp.h"
2 using namespace System;
3
4 namespace managecpp{
5 public ref class mA
6 {
7 private:
8 nA* aptr;
9 public:
10 mA(): aptr(new nA()) {}
11 ~mA() { delete aptr; }
12 nA getA()
13 {
14 return *aptr;
15 }
16 };
17 public ref class mB
18 {
19 private:
20 nB* bptr;
21 public:
22 mB(): bptr( new(nB) ) {}
23 ~mB() { delete bptr; }
24 bool mBoo( System::String ^a, array<mA^> ^b, int count) //数组的包装,//这里'^'的含义我不太明白,这里a, b都是指针
25 {
26 //string转成char*
27 cli::array<wchar_t,1> ^ aArr = a->ToCharArray();
28 const int nLength = aArr->Length;
29 char * ap = new char[nLength + 1];
30 for (int x = 0; x < nLength; ++x)
31 {
32 ap[x] = static_cast<char>(apArr[x]);
33 }
34 ap[nLength] = 0;
35 //array<mA>转成mA[]
36 mA *newb = new mA[count];
37 for( int i = 0; i < count; i++)
38 {
39 newb[i] = b->getA();
40 }
41 bool rel = bptr->nBfoo(ap, newb);
42 delete[] aArr;
43 delete[] newb;
44 return rel;
45 }
46 };
47 }
剩下的是c#调用的代码。首先要添加对managecpp.dll的引用,另外要将nativecpp.dll拷贝到bin目录下(无法理解)。
1 namespace cscallcpp
2 {
3 public class csB
4 {
5 bool csBoo(String a, csA[] b)
6 {
7 mB mb = new mB();
8 return mb.mBoo(a, b); //实例化后正常调用即可
9 }
10 }
11 }
我主要纠结的是在native c++中定义的类型的数组如何包装的问题,最后采用的方法比较挫,又创建了一个数组,然后赋值,这在空间、效率上都不咋的。请高人赐教。