上面两篇文章分别介绍了.Net平台互操作技术面临的问题,并重点介绍了通过P/Invoke调用Native C++类库的技术实现。光说不做是假把式,本文笔者将设计实验来证明P/Invoke调用技术的可行性。
1 实验方案
通过上述分析,调用Native C++类库的方式将采用平台调用技术(PInvoke),整体方案可以用下图表示:
2 实验设计
2.1实验步骤
本次实验的目的是为了最大程度的模拟用C#调用C++ Library的过程。整个实验的步骤如下:
2.2实验源码
根据上面的实验步骤,在Native C++代码中写了两个函数:QAFun和GetVarProtocol。在C#代码中,按照C++类库制定的内存协议,写了一个数据块解析器MemoryParser和测试函数TestQAFun。对于数据库生成器,在该实验中没有写,而是通过从Native C++生成好之后返回给C#。因为,我们只是要证明,C#中的内存块可以传递到Native C++中。此外,在C#中也是可以生成数据块的。实验的源代码如下:
C# Code public static class NativeMethod { [DllImport(dllPath, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public extern static void QAFun(string STR_PARAM, int LONG_PARAM, double DB_PARAM, IntPtr VAR_PARAM, ref IntPtr OUT_VAR_PARAM); [DllImport(dllPath, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public extern static void GetVarProtocol(ref IntPtr OUT_VAR_PARAM); } private static void TestQAFun() { string Str_Param = "Hello"; int Long_Param = 100; double DB_Param = 99.8; IntPtr Var_Param = IntPtr.Zero; IntPtr Out_Var_Param = IntPtr.Zero; unsafe { Console.WriteLine("1. Test: transfer data from managed environment to native environment"); Console.WriteLine("Initialize matrix in manamged environment"); NativeMethod.GetVarProtocol(ref Var_Param); NativeMethod.QAFun(Str_Param, Long_Param, DB_Param, Var_Param, ref Out_Var_Param); MemoryParser memoryParser = new MemoryParser(Out_Var_Param.ToPointer()); Console.WriteLine("Ouput martix that is from native environment in managed environment"); for (int i = 0; i < memoryParser.Rows; i++) { string str = memoryParser.GetElementString(i, 0); double db = memoryParser.GetElementDouble(i, 1); int integer = memoryParser.GetElementInt(i, 2); Console.WriteLine("{0} {1} {2}", str, db, integer); } } } C++ Code extern "C" __declspec(dllexport) void __stdcall QAFun(char* STR_PARAM, long LONG_PARAM,double DB_PARAM, void* VAR_PARAM, void** OUT_VAR_PARAM) { cout<< "Ouput martix that is from managed environment in native environment" <<endl; iVarProtocol iVar(VAR_PARAM); for(int i = 0; i < 3; i++) { string str = iVar.getElemString(i, 0); double db = iVar.getElemDouble(i, 1); int integer = iVar.getElemInt(i, 2); cout <<str<<" " << db << " " << integer<<endl; } cout<<endl; cout<<"2. Test: transfer data from native environment to managed environment"<<endl; cout<< "Initialize matrix in native environment" << endl; oVarProtocol oVar(3, 3); for(int i = 0; i < 3; i++) { oVar.setElem(STR_PARAM, i , 0); oVar.setElem(DB_PARAM, i , 1); oVar.setElem(LONG_PARAM, i, 2); cout <<STR_PARAM<<" " << DB_PARAM << " " << LONG_PARAM<<endl; } *OUT_VAR_PARAM = oVar.dump(); cout<<endl; } extern "C" __declspec(dllexport) void __stdcall GetVarProtocol(void** OUT_VAR_PARAM) { oVarProtocol oVar(3, 3); for(int i = 0; i < 3; i++) { oVar.setElem("Hello", i , 0); oVar.setElem(99.8, i , 1); oVar.setElem(100, i, 2); cout <<"Hello 99.8 100"<<endl; } *OUT_VAR_PARAM = oVar.dump(); cout<<endl; }
3 实验结果与分析
3.1 实验结果
通过实验,可以得出结论:C#调用C++ Library是可行的,并且在Native C++环境和C#环境之间完全可以传递内存数据块,并能正确的解析。实验结果的截图如下:
3.2 潜在风险
C#调用Native C++类库只需验证C#语言可以操纵内存,就可以通过C#语言调用Native C++ Library的函数。实验已经证明:通过unsafe和fixed关键字可以实现C#操纵内存,且通过Import C++ Dll,C#可以调用C++的函数。然而,在实际调用Native C++库时,因为实际数据结构的复杂性,将会有一些新的问题出现。
4 参考资料
1. 黄际洲 崔晓源 精通.Net互操作PInvoke, C++ Interop和COM Interop
2. http://msdn.microsoft.com/zh-cn/library/aa686045.aspx
3. http://www.cnblogs.com/xumingming/archive/2008/10/10/1308248.html
4. http://www.cnblogs.com/Jianchidaodi/archive/2009/03/09/1407270.html
5. http://www.jb51.net/article/23074.htm
6. http://blogs.microsoft.co.il/blogs/sasha/archive/2008/02/16/net-to-c-bridge.aspx
7. http://msdn.microsoft.com/zh-cn/library/ms228628
8. http://blog.csdn.net/zhangzxy161723/archive/2009/04/28/4132853.aspx
9. http://hi.baidu.com/linzi1128/blog/item/dda5371fa7fa40cea6866946.html
10. http://blog.csdn.net/jadeflute/archive/2010/06/23/5689502.aspx
11. http://blog.csdn.net/null1/archive/2009/03/03/3953155.aspx
12. http://msdn.microsoft.com/en-us/library/eyzhw3s8(VS.80).aspx
13. http://www.cnblogs.com/suyang/archive/2008/03/06/1093827.html
14. http://ondotnet.com/pub/a/dotnet/2003/03/03/mcppp2.html
15. http://ondotnet.com/pub/a/dotnet/2003/01/13/intromcpp.html
16. http://ondotnet.com/pub/a/dotnet/2004/03/29/mcpp_part3.html
17. http://www.codeproject.com/KB/mcpp/cpptomancpp.aspx
18. http://blog.csdn.net/yingzai621/archive/2010/02/01/5278316.aspx