【混合编程】C#调用C++
来源:互联网 发布:历史大事年表知乎 编辑:程序博客网 时间:2024/06/17 03:20
之前在学校写写图个方便,现在上班了发现这种技术简直逆天,C++/CLR也写过,但是语法上就只好呵呵了,而且运行起来跟原生的C#感觉差很多。唯一的好处就是不用考虑托管与非托管的问题。
直接上代码吧,很实用
【C#端相关开发与配置】
<span style="white-space:pre"></span>static private IntPtr instance = IntPtr.Zero;<span style="white-space:pre"></span>//DLL实例变量,是个IntPtr [DllImport("Kernel32.dll")] public static extern IntPtr LoadLibrary(string lpFileName);<span style="white-space:pre"></span>//动态加载DLL的API [DllImport("kernel32.dll", SetLastError = true)] public static extern int GetProcAddress(IntPtr hModule, string lpProcName);<span style="white-space:pre"></span>//用于获取函数指针 [DllImport("kernel32.dll", EntryPoint = "FreeLibrary", SetLastError = true)]<span style="white-space:pre"></span>//动态卸载DLL的API public static extern bool FreeLibrary(IntPtr hModule);至此,是Windows平台的相关API导入。下面首先封装一个函数,获取函数指针的同时转为委托,因为C#里无法直接使用函数指针。
//获取函数指针 static private Delegate GetAddress(IntPtr dllModule, string functionname, Type t) { int addr = GetProcAddress(dllModule, functionname);<span style="white-space:pre"></span>//获取指针 if (addr == 0) return null; else return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t);<span style="white-space:pre"></span>//转成委托 }然后就是生成所需函数对应的委托声明组:
<span style="white-space:pre"></span>delegate int Delegate_int_initWithBmp(char[] filename,IntPtr memStream );<span style="white-space:pre"></span>//定义委托,注意签名与DLL函数要一直<span style="white-space:pre"></span>Delegate_int_initWithBmp VideoInitWithBmp;<span style="white-space:pre"></span>//声明一个委托变量OK,以上都是C#端在加载函数前的准备工作。下面就开始加载了,比如,在初始化函数里这么写:
<span style="white-space:pre"></span>void DLLInit()<span style="white-space:pre"></span>//默认私有,如果需要被外部类调用注意相关函数公有制 { instance = LoadLibrary(Application.StartupPath + "\\" + "FFCodecSupport.dll");<span style="white-space:pre"></span><span style="font-family: Arial, Helvetica, sans-serif;">//加载DLL</span> if (instance.ToInt32() == 0) { throw new Exception("加载失败,错误号:"+Marshal.GetLastWin32Error()); } //获取版本号<span style="white-space:pre"></span>//版本号验证有时候兼容性检验还是需要的 //获取函数地址,即加载<span style="white-space:pre"></span><pre name="code" class="csharp"><span></span>//使用了一个函数可以省了好多代码,尤其是在需要加载很多函数的时候。VideoInitWithBmp = (Delegate_int_initWithBmp)GetAddress(instance, "InitWithBmp", typeof(Delegate_int_initWithBmp));}
【C++端相关开发与配置】
建立工程,当然是DLL,记得勾选导出符号(X)选项,这样后面方便点。
然后会看到工程里有这么几个文件:dllmain.cpp、FFCodecSupport.cpp、stdafx.cpp、FFCodecSupport.def、FFCodecSupport.h、stdafx.h、targetver.h
许多文件都不需要动它,FFCodecSupport.cpp、FFCodecSupport.def、FFCodecSupport.h这三个是需要重点修改的。
FFCodecSupport.cpp
里主要写被调用的函数实现,写不写到类里都无所谓,写了反而麻烦。做好内存回收工作!因为GC真的管不到这儿!关键的地方就是函数签名:
不对外开放的函数签名该怎么来怎么来,需要被上层调用的函数签名得这么写:
FFCODECSUPPORT_API char * CALLBACK InitWithBmp(char * filename);InitWithBmp需要与上面GetAddress函数的第二个参数一样,
FFCODECSUPPORT_API 实际上是 #define FFCODECSUPPORT_API __declspec(dllexport)
FFCodecSupport.def
是导出符号表,像这样写:
LIBRARY "FFCodecSupport"EXPORTSInitWithBmp首行是库名,次行固定内容,第三行开始每一行写一个需要被上层调用的导出函数
FFCodecSupport.h
文件主要就是写函数签名,跟普通的头文件编写没什么太大区别,多注意些语法上的问题,比如typedef一般放在最前面,这个大家都懂的。
最后分享一些用过的传参参数表(仅供参考)
char *可直接对应char[]
void *用IntPtr,不过肯定要用unsafe了
byte **之类的二阶指针,最好还是用IntPtr
比如IntPtr Addr,Addr对应byte *,而&Addr对应byte **,但是传参的时候都用IntPtr。用的时候要格外小心就是了。
Dispose(void *ptr)这种直接传任意指针参数,然后delete ptr可以有效释放,但要注意是一阶指针,二阶的需要自己转成一阶的。
【其它一些语言共性】
C#与C++的输出目录要一致,可以省很多事。特别是C#上不需要配置任何东西,你只需要写一个Wrapper,因为LoadLibrary可以直接从当前路径搜索DLL。
- 【混合编程】C#调用C++
- C与C#混合编程
- C/C++ 混合编程 互相调用
- MATLAB调用C/C++进行混合编程
- 谈谈Matlab与C/C++或C#的互调用(混合编程)
- C/C++ 与 C#混合编程
- C#与C++/CLI混合编程
- C#与C++/CLI混合编程
- C++/C# 混合编程 (Mix code C++/C#)
- 【转贴】C++/C# 混合编程 (Mix code C++/C#)
- Matlab、C混合编程(Matlab调用C)
- C#与MATLAB混合编程--DLL动态调用
- [C++/CLI] C# C++/CLI 混合编程类型转化注意事项
- c与matlab混合编程之dll调用
- 【混合编程实例】C/C++调用FORTRAN编写的DLL
- Matlab与C/C++混合编程调用OpenCV
- Matlab与C/C++混合编程调用OpenCV
- extern在C和C++混合编程中调用注意
- UVA 156 - Ananagrams
- 杭电2535
- Android--五大布局
- Struts2框架的标签库
- 关于SpringMvc中的事务@Transactional
- 【混合编程】C#调用C++
- bzoj2134 单选错位 递推
- 清华1084,整数拆分
- NSURLSession 简单入门及断点下载续传实例
- 原始的爱情
- 层次聚类算法及其实现
- 主流WiFi芯片与性能简介
- Word自动编号多级标题设置
- 枚举