C#与C++交互之——参数传递
来源:互联网 发布:企业oa软件 外贸 编辑:程序博客网 时间:2024/05/19 17:51
出发点:最近在做C#、C++的交互,期间出现不少的问题,边学边做
以下是《精通.NET互操作》读书笔记,该书详细讲述了.Net与C/C++的交互技术
托管代码和非托管代码的交互技术有3种:平台调用(PInvoke)、C++ Interop、COM Interop
平台调用(PInvoke)
其中,PInvoke最简单,但只能调用函数,不能调用类。但有一个折衷的办法,就是在C++里面定义一系列函数,里面调用相应的类,暴露给调用方(托管语言)的只有一系列的函数接口(API)。PInvoke本质就是调用dll,dll里面包含一系列C/C++ 的API。
PInvoke的过程:
1、获取非托管函数的信息(查看dll的内容或者头文件,得到API);
2、在托管代码中声明非托管函数,设置PInovke的属性(如函数入口点);
3、在托管代码中直接调用上一步声明的函数。
代码:
C++中使用 extern "C" _declspec(dllexport) 定义API;C#中DllImport方法。
既然是调用函数,少不了的就是参数传递。但由于托管语言是基于CLR的,而非托管语言则是本机代码(Native code),两者存在很大的差别,如数据类型不一致。这时候,在托管语言这一方,需要进行数据封送处理。封送指的就是托管内存和非托管内存之间传递数据的过程。
封送是双向的,由封送拆收器完成,其主要任务是:
1、数据类型转换。非托管数据类型到托管数据类型的转换(输出),或者,托管数据类型到管数据类型的转换(输入);
2、内存搬运。非托管内存复制到托管内存,或者,托管内存复制到非托管内存;
3、内存释放。
结构体的数据封送
API以结构体作为输入参数或输出参数。
必要的工作:
1、非托管函数定义一个结构体;
2、托管函数定义一个“等价”的结构体。
所以,封送结构体最大的难点在于:确保结构体在托管和非托管中是一致的,也就是参数的数据类型转换。
实例:
C++中定义结构体
typedef struct _DEMOSTRUCT{int a; short b; float c; double d;}DEMOSTRUCT,*pDEMOSTRUCT;C#中定义等价结构体
private struct ManagedDemoStruct{publicint a;publicshort b;publicfloat c;publicdouble d;}
等价的含义是,除了字段的名称可以不一样以外,以下内容必须保持一致:
1、字段声明顺序;
2、字段的类型;
3、字段在内存中的大小。
C++定义API
void Func(DEMOSTRUCT m_demoStruct){printf("\n int = %d, short = %d, float = $f, double = %f \n", m_demoStruct.a, m_demoStruct.b, m_demoStruct.c, m_demoStruct.d, );m_demoStruct.a +=10; //将是无效的}编译得到 myDLL.dll
C#中调用API
...[DllImport("myDLL.dll",EntryPoint = "Func")]private extern static void myAPI(ManagedDemoStruct argStruct)private static void myTest(){ManagedDemoStruct demoStruct= new ManagedDemoStruct();demoStruct.a = 10;demoStruct.b = 20;demoStruct.c = 3.5f;demoStruct.d = 6.8f;myAPI(demoStruct);}...
运行一遍myAPI后,demoStruct.a的值将依然为10?
以上例子仅仅是值传递,不能修改结构体的内容,想要实现修改就要用到结构体指针。对上述例子进行修改,参数改为传结构体指针。
C++
void Func(pDEMOSTRUCT p_demoStruct){printf("\n int = %d, short = %d, float = $f, double = %f \n", p_demoStruct->a, m_demoStruct->b, m_demoStruct->c, m_demoStruct->d, );p_demoStruct->a +=10; //有效的修改}
C#
[DllImport("myDLL.dll",EntryPoint = "Func")]private extern static void myAPI(ref ManagedDemoStruct argStruct) //ref
总结
对于含有结构体参数的API,必须先在C++和C#中分别定义一个等价的结构体;在定义托管结构体时,可能需要使用StructLayout属性来指定对象中的内存布局。正确地声明托管结构体,是封送的关键。
带有传出参数的API,要使用指针传递参数,在C#里要声明ref
- C#与C++交互之——参数传递
- 关于C#与(C++)Com交互之数组传递
- C++与C#交互的参数传递
- [C#] C#中的参数传递
- JAVA C# C/C++之比较学:参数传递
- Spring MVC 系列(三)——Spring MVC 参数传递与表单交互
- Spring MVC 系列(三)——Spring MVC 参数传递与表单交互
- Spring MVC 系列(三)——Spring MVC 参数传递与表单交互
- <iOS和Unity交互>之参数传递
- matlab与c#混合编程之图像参数传递
- C#与c++参数传递
- C语言之struct参数传递与结构匹配
- C语言之struct参数传递与结构匹配
- java/c/c++/c#参数传递问题
- 外界与Flex Application的交互处理(之传递参数)
- 外界与Flex Application的交互处理(之传递参数)
- 外界与Flex Application的交互处理(之传递参数)
- c#参数传递之引用参数
- equalse函数的作用
- Hadoop运行程序报空指针的原因
- BST二叉排序树的查找和删除的完整C代码
- 设计模式的七大原则
- 简单内存泄漏检测方法,解决Detected memory leaks!问题
- C#与C++交互之——参数传递
- Alamofire网络库基础教程:使用 Alamofire 轻松实现 Swift 网络请求(一)
- CAS单点登录
- 解决fusionCharts显示不全,经常挤在一起的问题
- Spring Web Flow 2简化页面流的开发,结合Spring MVC更俊,Spirng Security 3添加安全机制
- 【DP+预处理|最长连续子序列】HDU-1506 Largest Rectangle in a Histogram
- ucos II 内核学习之六:ucos II初始化及启动
- 空谈误国/空想误家
- poj2400 KM算法二分图的完美匹配