在C#代码中调用C++和VB编写的组件2007-11-10 本站 如果不能和用别的编程语言编写的组件进行交互,这种编程技术的含金量就会大打折扣。.NET环境为我们提供了不同语言编写的组件之间相互调用的良好机制。只要按照.NET可操控代码的标准来编写组件,对于客户程序来说,调用者的组件是哪种语言编写的都无关紧要,调用的方式实际上没有什么区别。下面我们先后使用C++、VB和C#编写了自己的组件。这是一个简化的字典组件,字典在构造时没有装载语言库,需要使用LoadLibrary来完成。使用FreeLibrary方法把语言库卸载。属性CurrentLibrary表示当前的语言库。在C#中同时调用了用三种语言编写的组件,通过比较相信读者将会一目了然。
18.2.1 C++组件先看看C++中的组件程序清单18-3:
//DICTVC.cpp#usingusing namespace System;namespace DICTVE{ __gc public class DictionaryComponent //定义字典组件 { private: String* LanguageName; String* AvailableLanguage[]; public: DictionaryComponent() { LanguageName=null; AvailableLanguage=new String*[4]; AvailableLanguage[0]=new String(L"Chinese"); AvailableLanguage[1]=new String(L"English"); AvailableLanguage[2]=new String(L"German"); AvailableLanguage[3]=new String(L"French"); } bool LoadLibrary(String* Language) {for(int i=0;i<4;i++){if(language==AvailableLanguage[i]) break;}if(i==4){ return false;}LanguageName=language;return true; }__property string* get_CurrentLibrary{ return LanguageName; }}}
首先,我们声明了一个新的名字空间,用来封装创建的新的类。namespace DICTVC{...};注意到,名字空间不能被嵌套,但可以被分离在多个文件中。一个简单地源代码文件也可以包含多个没有嵌套名字空间。VB和C#中,所有的类都是可操控的。但在C++定义的名字空间中,我们可以包含可操控的和未操控的代码,所以我们需要特别指定我们新建的类是可操近代的。__gc public class DictionaryComponent{...};这个声明表示类将被在运行时创建,而且受控于垃圾收集器管理的堆中。我们也可能在编译时指定/CLR选项来保证程序中所有的类都是可操控的。类的构造函数在每次创建类的实例时都会被调用,构造函数的名称与类的名称相同,而且没有返回类型。
public:DictionaryComponent{...};
而且,因为类应该是可操控的,所以我们必须显式地通知编译器数组是一个可操控的对象。因此,在指派字符串时,我们使用了修饰符__gc。注意:C++没有对变量进行默认的初始化功能,必须自己手动设置LanguageNamed的值。LanguageName=null;
Availablelanguage=new String*[4];下面是LoadLibrary方法,带有一个字符串类型的参数,返回一个布尔值:
bool LoadLibrary(String* language){...... if(i==4)return false; LanguageName=language; return true;}下面是FreeLibrary方法,没有参数,也没有返回值。void FreeLibrary(){LanguageName=null;}最后,我们创建了一个只读属性Count:__property string* get_CurrentLibrary{return LanguageName;}
编译这个C++组件时的命令选项稍微有些复杂:cl/CLR/c DICTVC.cpp
link -noentry-dll/out...BinDICTVC.dll DICTVC这里,我们需要使用/CLR选项来通知编译器,生成的代码装配必须是可操控的。我们还需要一条独立的命令来执行链接(和C#中直接编译产生目标代码不同,C++中必须经过编译和链接两个过程)。装配是指在.NET结构框架中能够被部署、进行版本定义、可重用的物理单元。每一个装配都建立了一个类型的集合,集合的元素包含基于运行时的类和其它的资源,它们将按照装配的指定协同工作。装配的指定说明了哪些组件是装配的一部分,哪些类型是从装配中导出的,以及类型的独立性。运行时环境将使用装配来定位和绑定你所引用到的类型。为了方便起见,我们假设组件在当前目录的“//Bin”子目录中被创建。为了指定组件的创建位置,我们使用/out选项来指定输出文件的路径全名。注意,即使我们在指定的输出文件名中包含了.dll扩展名,我们还必须要附加的-dll选项来告诉编译器我们将要创建的是一个DLL,而不是一个可执行文件。