Delphi与C++Builder代码共享的实现

原文地址:
 http://blog.chinaunix.net/uid-16175364-id-2752232.html

分类: C/C++

一.引言 
  在当今计算机世界中,各种编程语言琳琅满目,从Basic、Pascal到C++、Java再到汇编语言,应有尽有。 Delphi和C++ Builder可以说是Inprise公司开发的编程语言系列中的“绝代双娇”。Delphi使用的是Object Pascal语法,它具有易学易用的特性,能使初学者迅速编写出表现力极强的程序;而C++Builder对于高水平的程序员而言无疑是优秀的开发工具, 它最大程度体现了C++语言的灵活性和适用性,大大提高了程序的运行效率。如果能够把这两种语言结合使用势必会大大提高程序的开发效率。 
   其实,用户完全可以在C++Builder和Delphi之随心所欲的进行多平台程序开发,Delphi和C++Builder之间具有十分密切的关系, 他们在性能上非常相似。你用Delphi编写的任何代码几乎都可用在C++Builder中,同样用C++Builder写的部分代码也可用在 Delphi中。这样在编写程序中,程序员们就可根据自己的喜好和特长决定实用哪种语言,而不必担心使用一种语言编写的代码不会被另一种语言接受。编好之 后只要遵从一定的规则把它们连接在一起即可使用。 二.理论依据 
  Delphi语言使用了面向对象的Pascal,而C++Builder使用的语言是C++,这两种工具编写的完全不同代 码是如何连接在一起的呢?这主要是因为两者使用相同的编译器后端,编译后产生的目标文件是一致的,不同之处仅仅是前端的语言分析差异而已。Delphi的 编译速度一般要比C++ Builder快,这是由于Delphi采用了以单元为基础的编译方式,生成一种更为灵活的二进制文件-DCU格式,但是C++Builder的增量编译 方式减少了二者编译速度上的差距。其次,C++Builder的VCL控件(Visual Component Library可视构件库,简称VCL)全部由Delphi编写,因此用Delphi编写的VCL控件可直接引入C++Builder的IDE中无须作任 何改动。第三,C++与Object Pascal语言的基本数据类型非常相似,这使的在编译时二者之间进行数据传送非常方便,以下为二者的基本数据类型的比较(表-1) 
表-1. C++与Object Pascal的基本数据类型比较
C++
Object Pascal
C++
Object Pascal
Unsigned Char
Byte
Char
Char
Char A[size]
Array[0..size-1]
Int
Integer
Unsigned int
Word
Long
Longint
Unsigned long
Longint
Float
Single
Double
Double
Char far*
Pchar
Struct
Record
Union
Record with variants
Ansistring
String
VARIANT
Variant

   第四,二者都具有相同调用约定格式Stdcall,无论是Object Pascal还是C++都规定,凡是要输出的例程必须采用Stdcall调用约定。由于Stdcall也是Windows95/98/NT的API采用的 调用约定。因此,用户可放心地使用Stdcall调用约定共享Object Pascal、C++以及Windows95/98/NT输出的例程。以下为C++和Object Pascal各自的调用约定(表-2)。其实,从本质上讲Object Pascal是C++的一个子集。 
表-2. C++和Object Pascal的调用约定
Object Pascal
C++
默认
Cdecl
Cdecl
C++的默认调用约定
Pascal
Pascal
Delphi1.0、Windows3.x的默认调用约定
Stdcall
Stdcall
Windows95/98/NT的默认调用约定
Register
_Fastcall
Delphi2.0/3.0/4.0/5.0的默认调用约定

三. 代码共享 
  面向对象编程的基本出发点就是代码重用。要实现Delphi与C++Builder之间的代码共享显然有两种方法:一是在C++Builder中使用Delphi写的代码,二是在Delphi中使用C++Builder写的代码。下面我们就这两种方式分别加以叙述。 
  3.1. 在C++Builder中使用Delphi的代码 
   Inprise公司推出C++Builder的时间要比推出Delphi的时间短,在推出C++Builder时中已经充分考虑到了Delphi优秀特 性,因此二者在开发环境(Integrated Development Environments,简称(IDEs)、可视组件库(Visual Component Library,简称VCL)、单元文件(Form Files)和组件包(Packages)上非常相似,C++Builder的整个VCL都是用Delphi写的,因此在在C++Builder中使用 Delphi的代码要比在Delphi中使用C++Builder的代码容易地多。以下就在C++Builder中使用Delphi代码方法的具体给予阐 述: 
  3.1.1.在C++Builder中直接使用Delphi的代码 
  C++Builder并不关心你加入在工程文件中的 单元文件(Unit)是用C++Builder编写的还是用Delphi编写的,C++ Builder将编译你加入的单元文件就象编译C++Builder的代码一样,尽管C++Builder不支持Delphi的某些语法格式,例如 try…finally 和with结构等,但这些语法格式都可以在C++Builder中找到相应的替代语法,你会发现你用Delphi写的大部分代码几乎不做任何改动就可以在 C++Builder中编译。你可以在C++Builder中直接加入以下Delphi代码: 
  1.Delphi的窗体(Forms)  
  2.Delphi的单元文件(Units)  
  3.包含有过程(Procedures)、函数、常量,数组等的Delphi单元文件(Units)  
  4.Delphi的组件(Components)  
  加入方法如下: 
  1.选择C++Builder的Project | Add 菜单  
  2. 在工程对话框中选择所要加入的文件(文件扩展名为*.pas)并确定C++Builder将会为所加入的Delphi文件自动生成头文件(*.hpp),但应当注意在C++Builder中直接使用Delphi的代码,应当遵循以下基本规则: 
  1. 不能在同一个单元(Unit)中既使用C++Builder的代码又使用Delphi 的代码,必须在各自单独的单元内使用。  
  2. 不能在C++Builder中使用Delphi DCU格式的二进制文件。  
  3. 在C++Builder中打开Delphi的表单(Form)后,不能对其进行编辑,但是可以先继承该表单,再进行编辑。  
   4.如果一个应用程序其工程文件(Projectname.cpp)用C++Builder写的,即使整个应用程序98%的代码是用Delphi编制 的,该应用程序仍然为C++Builder程序。这也意味着你不可以将Delphi的工程文件放入C++Builder中来编译。  
  3.1.2. 在C++Builder中使用Delphi的组件 
   组件是Delphi、C++Builder中代码重用的基础,几乎所有的Delphi组件都可以在C++Builder中使用而无须做任何改动,毕竟整 个C++Builder的组件都是由Delphi编写的。 通以下方法在C++Builder中使用Delphi的组件: 
  1.选择C++Builder的Component | Install菜单  
  2.选择添加组件(Add Components)  
  3.选择所要加入的组件并确定  
   C++Builder将会自动重新编译CMPLIB32.DLL文件, 你所加入的组件(Component)就会显示在组件模板(Component Palette)上。然后就可以象使用C++Builder的组件一样使用该组件。切记在操纵使用该组件时一定要使用C++Builder的语法而不是 Delphi的语法。因为在添加该组件时C++Builder已经为你自动作了转换。 
  3.1.3. 通过COM和OLE在C++Builder中使用Delphi的代码 
   Delphi内建了对COM的支持,由于COM 对象具有语言和平台无关性,用Delphi创建的COM对象可以与用C++Builder、Visual Basic、Java、Visual C++、Word、Excel,等其他OLE敏感控件之间的代码共享。此外,在多层Client/Server环境中,COM对象还可以封装商业规则,为 分布式的客户提供服务。有三种基本方法可以将Delphi COM 对象连接到C++Builder中:  
  1. 使用OLE自动化或双端接口(Interfaces).  
  2. 使用Delphi 创建ActiveX控件然后在C++Builder载入此控件  
  3. 编写原始的COM 或OLE代码来连接Delphi对象  
   C++Builder内建了对前两种方法的支持,第三种方法要求具备较高的OLE知识。操纵一个自动化对象有两种方法:一是通过COM 对象的Idispatch接口,C++Builder中通过VCL函数CreateOleObject和Variant数据类型内建了对 Idispatch接口的支持,这是使用自动化对象的最简单的方法;.二是通过COM 对象的双端接口(Dual Interface),使用双端接口可以获得较快的速度,但是该方法实现起来比较困难,需要具备很深的COM理论知识,具体方法和DLL中的虚拟方法表 (Mapping Virtual Method Tables)相似,限于篇幅本文不在起具体实现细节。先假设有一个Delphi的Idispatch接口,输出以下方法: 
  ITest = interface(IDispatch) 
  [`{1746E520-E2D4-11CF-BD2F-0020AF0E5B81}'] 
  function Get_Value: Integer; safecall; 
  procedure Set_Value(Value: Integer); safecall; 
  procedure Prompt(const text: WideString); safecall; 
  property Value: Integer read Get_Value write Set_Value; 
  ... 
  end; 
  再假设这个动态连接库(DLL)已经注册并且其工程表识为"TestLib.Test"。.以下为在C++Builder 中调用该接口的Prompt过程的程序: 
  void __fastcall TForm1::Button1Click(TObject *Sender) 
  { 
    Variant V = CreateOleObject("TestLib.Test"); 
    V.OleProcedure("Prompt", "Hello World!"); 
  } 
  当然你也可以通过以上方法调用该接口中的其他过程和函数。用户应当注意在C++Builder中Variant类型并不是一个数据类型,所以在使用Variant类型时应当在工程文件中加入Sysdefs.h.。  
  3.1.4. 在C++Builder中使用Delphi的ActiveX 控件 
   C++Builder和Delphi完全支持ActiveX,您可以很方便地创建、注册、安装、发布和使用ActiveX 控件、ActiveForm和OLE自动化对象, 这应当归功于“对象接口”技术和DAX 技术。通过以下方法在C++Builder中使用Delphi 的ActiveX 控件: 
  1. 选择Component | Install 菜单  
  2. 在添加组件对话框(Install Components dialog)中选择OCX按钮  
  3. 所有已经注册的组件都会列在添加OLE控件对话框中(Import OLE Control dialog),选择所要加入的控件并确定。(如要注册注册  新控件选择Register按钮)  
  4. 新的控件会出现在已安装的组件表中,选择确定退出。  
  C++Builder自动将控件的接口文件写入LIB目录下,并且自动重新编译CMPLIB32将你的控件加入到组件模板中(Component Palette)。新控件会默认的出现在组件模板的OCX页上。 
  3.1.5. 在C++Builder中使用动态连接库来共享Delphi代码 
   Windows引入一种重要机制——DLL,即动态连接库。DLL中包含有例程和资源,可以使应用程序之间共享例程和资源。使用DLL不但可以实现C ++Builder与Delphi之间代码共享,而且还实现C++Builder与Visual C++、Visual Basic、Borland C++等其他编程工具之间代码共享。在Delphi中编写一个DLL程序非常简单,在此本文不再祥述编写DLL的具体方法,着重介绍一下如何在DLL中实 现模式Form和无模式Form。 
  外部程序要访问DLL中的模式Form,DLL中必须建立和输出访问例程。外部程序调用访问例程,访问例程去建立Form类的实例,当用户单击OK、Cancal、Abort等按钮关闭Form时,访问例程返回相应的值。下面是一个典型的访问例程示例: 
  procedure ShowModuleForm(AppHandle:Thandle):Integer; 
  begin 
    Result:=-1; 
    Application.Handle:=AppHandle; 
    with TMoudleForm.Create(Application) do 
    try 
      Result:=ShowModal; 
    finally 
      Free; 
    end; 
  end; 
   访问例程至少要有一个Thandle类型的参数,用于传递调用DLL外部程序主窗口的句柄。如果应用程序是用Delphi开发的,就是 Application.Handle 。访问例程首先创建Form类的实例,然后调用ShowModal显示这个Form,最后调用Free删除这个Form实例。当然,根据不同的需要,访问 例程可以增加若干参数。在上例中,访问例程首先把返回值设为-1,这样即使Form类的实例没有创建成功,返回值总是一个确定数。函数最终的返回值由 ShowModal返回的。最后不要忘记在DLL中输出访问例程。 
  所谓无模式Form,就是即使Form没有关闭,用户也可以把输入焦点 移到其它窗口。要访问DLL中的无模式Form,DLL中需要建立和输出两个访问例程,一个用于创建Form类的实例和显示Form,另一个用于关闭 Form和删除类的实例。其它规则与访问模式Form基本相同。一个典型的创建和显示无模式Form的访问例程示例如下: 
  function CreateAndShow(AppHandle:THandle):Integer ; 
  var MyHandle:THandle; 
  begin 
    Application.Handle:=AppHandle; 
    MyHandle:=THandle(TNon-ModalForm.Create(Application)); 
    {创建TNon-ModalForm类的实例,并强制转换为THandle类型} 
    Result:=MyHandle;{把Form的句柄作为返回值} 
    with TNon-TMoudleForm(MyHandle) do 
    try 
      Show; 
    except 
      Free; 
      Result:=0; 
      Raise; 
    end; 
  end; 
  一个典型的关闭和释放类实例的访问例程示例如下: 
  procedure CloseAndFree(FormHandle:THandle); 
  begin 
    if FormHandle=0 then 
      Raise Exception.Create('Form类的实例没有创建!'); 
    else 
      with TNon-ModalForm(FormHandle) do 
      begin 
        Close; 
        Free; 
      end; 
  end; 
  我们也可以把类写成DLL,然后被其它程序或DLL共享,但要注意不能直接使用DLL中的类的方法和成员,而只能调用DLL中输出的类。同样DLL中也可以包含虚拟类,但是实现起来比较麻烦,限于篇幅本文不再叙述。 
  3.2.在Delphi中使用C++Builder的代码 
   从本质上讲Object Pascal是C++的一个子集,因此在Delphi中使用C++Builder的代码要比在C++Builder中使用Delphi的代码困难的多。在 Delphi中直接使用C++Builder的代码几乎是行不通的,但是由于OLE、COM、DLL都是Windows系统的规范,因此可以通过这三种方 法很方便在二者之间实现代码共享。在Delphi中通过这三种方法来使用C++Builder的代码和在C++Builder中通过这三种方法来使用 Delphi代码基本相同,在此本文不在另行叙述。 
  尽管Delphi也支持OBJ文件,在Delphi中连接C++Builder的 OBJ文件也很简单,只要用{$Link}或{$L}指示字指定要连接的OBJ,其格式为:{$L 文件名},但是Delphi的程序只能访问OBJ中很简单的例程。用户既不能访问OBJ中C++的类,也不能访问C++的RTL(运行期库),也不能访问 C++的几个全局变量。也就是说如果例程中包含对TRL的调用或者对Windows API的调用,或者OBJ中包含C++类的声明,Delphi的链接器都将失败。因此在Delphi中用C++的OBJ几乎没有任何实用价值。 
四.结论 
   本文详细叙述了实现C++Builder与Delphi代码共享的各种方法,通过比较可以发现在C++Builder中共享Delphi的代码,要比在 Delphi中共享C++Builder的代码容易得多。但是通过DLL、OLE和COM我们也可以很方便的在Delphi中共享C++Builder 的代码。 
  此外,还可以使用一些中间层方式来实现C++Builder和Delphi之间代码共享,所谓中间层方式是指将C++ Builder的代码和 Delphi的代码分开编译成两个可执行模块,然后通过中间层实现两个模块的数据共享和相互操纵。中间层可以是剪贴板、DDE、磁盘文件、BDE以及 Windows的消息。不过这已经不是真正意义上的代码共享了,只是程序间的数据交换,因而使用这种结构的程序执行速度比较慢,如果对程序执行的速度要求 不是很高,也可以考虑使用中间层结构。 
  综上所述,我们发现在C++Builder和Delphi之间实现代码的共享是比较容易的事,不过 实现的难度有所不同,在C++Builder中共享 Delphi的代码要比在Delphi中共享C++Builder的代码要容易一些,因此我们提倡尽量用C++Builder建立工程文件,充分利用两种 语言各自的优点,在C++Builder中共享Delphi的代码,以加快整个软件开发的速度

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值