您的位置:首页 > 编程语言 > C语言/C++

VS2005 C++/CLI的托管代码与非托管代码的互操作性

2015-04-21 16:11 423 查看
转自:http://blog.sina.com.cn/s/blog_53a1f2d60100pt2l.html

近来试了试VS2005 C++/CLI中托管代码与非托管代码的互相调用,总结如下:

(在/clr编译选项下,编译器默认编译成托管代码[对非CLI扩展语法的代码而言,CLI扩展语法的自然是要编译为托管代码的],只有在无法编译为托管代码时才会编译成原生代码,可以在代码中使用#pragma unmanaged与#pragma managed预处理指令来改变)

1、在非托管代码中无法使用托管类型及原型包含了无法被自动排列的托管类型的函数;

2、在托管代码中可以使用大多数非托管类型,如类、结构、指针、函数调用等,但结构有__declspec( align(#) )修饰的与函数有__declspec(naked)修饰的无法在托管代码中使用,使用会倒致编译器出错,不知道将来版本的VS是否可以允许这些;

3、在托管类中,不能用非托管类定义实例数据成员,但可以定义指针数据成员,不过在函数原型中却可以使用非托管类实例参数与返回值(这时不要求是指针),在CLI文档中的解释说实例数据成员会要求mixed type的能力,看起来将来版本应该会提供这种能力。

可以看出C++中两类代码的互操作实际上主要是托管代码对非托管代码的使用,非托管对托管的使用仅限于可排列参数的函数调用。(这一点从编译器翻译出的代码来看,可能原因是将非托管类型封装成托管类型比将托管类型封装为非托管类型相对比较容易[非托管代码没有元数据,不像托管代码有很多元数据描述,如果要将托管封装成非托管类型,则需要大量的THUNK来为非托管代码解释元数据,而反过来,编译器只要为非托管生成元数据,托管代码本身对元数据的支持能够自动解析调用非托管代码,而为非托管生成元数据正是编译器将代码编译为托管代码的功能,是自然扩展的])

C++/CLI目前看来主要的作用是将C++库采用所谓C++互操作封装为托管代码供.NET平台使用,典型例子是Dx9的托管库,反编译它的代码可以很明显发现它是采用C++/CLI来编译的,它的托管代码是直接使用C++虚函数表来调用底层DX的COM接口的,按MS的说法,这种方式能提高性能,因为看起来没有经过.NET运行时RCW COM封装(对平台API[比如MDX中有Driect3DCreate9的调用]则是没有通过PINVOKE机制,不过我想来想去没发现C++解决互操作与PINVOKE,RCW COM封装有什么本质区别,估计只是少了些额外的元数据解析的工作)。

(无意间发现一点,将一个C++工程(主函数不明确设成非托管的话)按/clr选项编译后,生成的EXE的入口直接调用CorExeMain,这样子使得原生EXE的大多数反编译器失效,因为它们按照PE格式找到的入口点是跳转到.NET运行时库的,如果要反编译这样的EXE,需要先用ILDASM这样的.NET反编译器反出.NET代码,然后再通过.NET元数据寻找非托管代码的入口,然后再按片断反编译非托管代码[这种片断似的反编译显然不好玩,所以目前这样子可以是一种软件保护方法,不过也许很快会有反编译商家做出能反编译这种混合.NET与原生代码的反编译软件来,现在我还不知道谁能做到,因为IDA
PRO 9好象还没有这种能力])

附带的研究了一下.NET的范型支持,按MSDN的说明,这种范型是在JIT级实例化的,而且只有值类型会按每个类型生成独立的实例代码,引用类型则只生成一份实例代码,起初想不明白它是怎么实现的,费了些时间研究了一下,发现原来主要是依赖元数据,元数据中除了对每个类有一个元数据描述(说明了该类的范型参数等信息)外,所有对该类的引用(.NET中引用的范型必然是closed type,也就是范型参数都已实例化)也都有一个元数据描述它,而引用部分生成的CIL指令里有一个对前述元数据的引用(称为元数据令牌),这样子一个范型就被完全实例化了,现在从CIL的角度来看,它有了范型实例化的所有信息,而且只有一份范型定义代码,剩下的工作就是JIT的了,因为CIL只有一份定义,所以只要能将此定义翻译为原生代码就OK了,这个时候开始区分值类型与引用类型了,往后我没有深究,大致原因是引用在32位机器上总是32位的,所以可以翻译为一份代码,而值类型的大小与具体的类型相关,所以没办法翻译为一份代码,而只有每个类型翻译为一份,不过我觉得这种差别从本质上说只是因为缺少了一层间接性而倒致的,就像前面CIL中将范型实例化信息存储在元数据中一样,如果值类型与引用类型的差异也被描述一下,应该也是完全可以抽象成一样的东东的(间接的间接的间接...看来又出现高阶情况了,再不能用大脑想了,估计是需要某种形式化的论证了)。不过多一层间接意味着执行性能的损失,估计这也是JIT的一种折衷结论。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: