托管与非托管间的代码级桥梁——C++/CLI

时间:2022-09-01 15:54:38

注:此文转自begtostudy的博客

我们知道托管与非托管程序之间的桥梁有很多,PIvoke和Mashel,COM和CLR API都算是。然而这些都是模块(assembly)间的桥梁,好处就是方便直接,缺点就是细节上处理不了。是啊,毕竟是两类语言,两类运行环境。如果要更为细腻的处理二者之间的衔接,看来还要署C++/CLI最经典了。

当然,C++/CLI也有缺点,就是他两边都站,但两边都不得意他,因此它成为口碑最不好的语言了。用它开发非托管程序,一堆托管代码,加上被人诟病的效率问题,颇受质疑;用它开发托管程序,程序的安全性(就是内存溢出)就程序托管程序最瞧不起的地方。最麻烦的是IDE对其支持的非常不好,没有智能感知,只能自己查找各种语法问题,对程序员的要求很苛刻。即便如此,正如本文所说,作为二者之间的桥梁,其地位举足轻重!

关于C++/CLI的语法,建议看看该文, http://www.cppblog.com/golq/category/11113.html。其实,如果有C#基础,看这些语法就很小儿科的。(是的,现在看来,不是说从C++到CLI学习更方便,相反,倒是从C#学习C++/CLI更容易!)

本文的重点不在于介绍C++/CLI,而是介绍它与C++的混合编程——也就是本文所说的“代码级的桥梁”。 

下面的部分转载自 http://www.cnblogs.com/deerchao/archive/2007/12/01/979460.html

没有使用C++/CLI之前,我很怀疑它存在的意义.因为C#的语法更清爽,运行效率也不比C++差多少.C++本身就很复杂了,再乘以CLI的复杂度, 我不能想出人们为什么会学习它,使用它. 

但是在使用C#的过程中,渐渐发现.Net类库不够丰富,有很多功能必须通过P/Invoke来实现.一般常用的Windows API函数还好说,接口通常比较简单,DllImport + IntPtr已经足够了,而且还有www.pinvoke.net这个很大的资源库,使用起来还是相当方便的. 虽然有时看到那个日渐庞大的NativeMethods类不爽,但是整体来说,能解决问题. 

等到我必须使用第三方C/C++类库时,我发现使用C#与它们交互实在太痛苦了.普通的对整型数的指针,引用这些好说,但是一碰到复杂的(尤其是嵌套的) 数据结构,我就发现自己面对着成百上千行的.h不想动手--天哪,我只想调用一个函数,为什么要用C#重写这么些复杂的struct定义?就连最简单最常用的byte[],在托管与非托管代码间传递也要大耗周折. 

在这两天使用Intel JPEG Library(ijl15.dll)时,我终于忍受不了了,于是想到用C++包装一下对它的调用,简化一下传入传出的参数.完成后,对着那个20K的原生dll,想着我还得在C#里弄DllImport之类的东西,终于觉悟了:干吗不用C++/CLI? 虽然对它的了解不是很深(只在05年看过Stan Lippman在<<程序员>>上发表的两篇文章),但是实际做起来真的很爽! 

一个pin_ptr关键字,直接抹去了托管与非托管之间的边界;而且居然能用CopyMemory从原生unsigned char*里往System.Byte[]里拷贝内容!我的天!原来就算像我这样了解得这么少的人,也能从C++/CLI里获得这么大的好处! 

以前因为没有.Net版本而放弃的类库,现在我都可以拿来用了.直到现在我才明白,错过C++/CLI的这些日子里,我错过了多少东西.

附, 有C#及C++背景的人使用C++/CLI的必备知识:
    1, C++/CLI里的new等于C++里的new, gcnew等于C#里的new
    2, 原生指针用*表示,托管引用使用^表示
        如: Stream^ stream = gcnew Stream();
    3, array^ 等于 System.Byte[]
    4, pin_ptr关键字能把托管引用转换为原生指针:
        如: pin_ptr pBytes = & byteArray[0];
        然后pBytes就可以当作原生的BYTE* 使用了.
        等代码执行完pBytes的有效范围,byteArray就会恢复可被GC处理的状态.
只需要知道简单的这几点,就可以开始获得 C++/CLI带来的巨大便利了! 
 

还有几篇文章介绍的也不错:
C#的Form通过CLI调用C++的DLL
NativeC++ 通过CLI调用C#的Form
C++ CLI 程序编写注意事项
转换指南: 将程序从托管扩展 C++ 迁移到 C++/CLI