最近使用C++写了一个图形库,想要再给这个图形库做一个编辑器,这就需要选择一个做窗口界面的框架,在Windows上可以选择的有MFC,QT,WinForm和WPF等等,MFC不想了,比较难搞定,QT不错,还能跨平台,但是想做的快以及漂亮一点不容易,WinForm和WPF做出来的东西好看而且能很快做出来,但是都是用C#开发,想要跟C++交互,使用P/Invoke是一种办法,但是这只能调用C++ Dll的导出函数,C++中的类型都不能用,这样肯定也不行的。
这几条路都不好走啊,其实最主要的是我MFC和QT都不行,只想用WPF,那只能绞尽脑汁的想办法了,最开始想到的办法是,可以通过函数调用解决的问题就都通过P/Invoke的方式来解决,其他的交互问题通过Socket发消息的方式来解决,实际写了一些代码发现太麻烦了,要写很多消息,效率不高,最主要的是代码都跑在同一个进程中居然要通过这种方式通信,太Low了吧,后面想过既然Socket可以通信,那么通过一个函数也一样可以,我在C++端定义一个函数来接收C#发过来的数据,然后定义一个C#的委托函数当做函数指针传到C++里面,C++对C#的输出都通过这个函数来完成,这样就不用通过网络这种方式来通讯了,但是这两种办法都还有一个问题,就是C++和C#两端同时都要保持一份数据在,这两份数据需要保持一致,这样很容易出错,而且很浪费,并且这也不是一个很好的设计,想想就觉得很乱!后来看到了托管C++,他不仅可以和C++直接交互,而且编译后是托管的代码,里面的类型C#可以直接使用,抓狂的我终于找到了一点希望。
所以现在需要把C#中需要的类型和数据什么的使用托管的C++做一遍封装就行了,托管的C++代码需要写在 #pragma managed 的后面,托管的代码写完之后最好使用#pragma unmanaged结束,以防止后面其他引用这个文件的文件在编译非托管C++时出问题,托管C++的语法和非托管的C++语法类似,如果想让自己定义的类在C#中可以用的话,需要把类定义为 ref class,不要使用 “*” 来定义托管类型的指针,需要使用 “^” 这个符号,另外记录一下托管C++与非托管C++几种类型之间的转换。
托管C++ String 转std::string :std::string stdStr = marshal_as<std::string>(clrStr);,需要 #include <msclr\marshal_cppstd.h>,using namespace msclr::interop;
std::string 转托管C++ String :System::String ^clrStr = gcnew System::String(stdStr.c_str());
托管C++ IntPtr 转 HWND :HWND hWnd = (HWND)intPtr.ToInt32();
函数指针在C#侧使用委托,并转换成IntPtr传到托管C++中,到托管C++中再转换成对应的函数指针类型。
这样就可以快乐的使用WPF开发界面了。
https://github.com/panqingyun/E3D-Engine 这就是我说的那个图形库和使用WPF编写的编辑器的git地址,有问题欢迎批评指正!