Delphi.NET 内部实现分析(1)
来源:百度文库 编辑:神马文学网 时间:2024/04/28 18:32:56
Delphi.NET 内部实现分析
0.概述
自M$发布.NET以来,业界厂商态度大相径庭。但不可否认的是,
在M$雄厚实力和充足资金的保障下.NET架构已经逐渐站稳脚跟,
开始向Java等既得利益者发起冲击。
而作为开发工具领跑者的Borland公司,也于2002年末,
伴随其并没有太大新意的Delphi 7,一同发布了Delphi.NET预览版。
本文就是基于这个预览版本,针对其内部实现原理进行分析,
帮助读者在了解Delphi的基础上,过渡到.NET时代。
1. Hello Delphi!
1.1. 初见 Delphi.NET
在详细分析Delphi.NET实现之前,让我们先从感性上认识一下它:
//-----------------------------------------HelloWorld.dpr--
Program HelloWorld;
{$APPTYPE CONSOLE}
begin
Writeln(‘Hello Delphi!‘);
end.
//-----------------------------------------HelloWorld.dpr--
看上去是否很眼熟?没错,这是一个标准的Delphi控制台程序,
同时也可以直接使用Delphi.NET编译成一个真正的.NET程序
E:\Borland\Delphi.Net\demos\Hello>dccil HelloWorld.dpr
Borland Delphi Version 16.0
Copyright (c) 1983,2002 Borland Software Corporation
Confidential pre-release version built Nov 14 2002 17:05:31
HelloWorld.dpr(8)
9 lines, 0.28 seconds, 4816 bytes code, 0 bytes data.
E:\Borland\Delphi.Net\demos\Hello>peverify HelloWorld.exe
Microsoft (R) .NET Framework PE Verifier Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
All Classes and Methods in HelloWorld.exe Verified
E:\Borland\Delphi.Net\demos\Hello>HelloWorld
Hello Delphi!
先使用 dccil,Borland经典Delphi编译器DCC32的IL版本,
将Delphi的Object Pascal代码编译成.NET架构的IL中间语言文件,
类似Java中的ByteCode;
再使用.NET Framework SDK附带的peverify验证程序有效性,
确认此HelloWorld.exe的确是.NET兼容的程序;
最后运行HelloWorld.exe程序,得到我们期望的结果。
看上去很美……不是吗?
不过在这看上去简单的代码背后,Borland做了大量底层工作,提供Delphi在.NET架构上
最大限度的源代码级兼容性,甚至不惜增加新语言特性(Delphi从Delphi3/4开始,语法上就
已经很稳定了,或者说已经很成熟了)。
1.2. 结构
用.NET Framework SDK附带的ILDASM工具打开HelloWorld.exe文件,
可以看到有两个名字空间Borland.Delphi.System和HelloWorld存在,
而MANIFEST里面是配件(Assembly)一级信息,详细含义请参加笔者另一系列文章
《MS.Net CLR扩展PE结构分析》,里面有详细解析。(.NET是M$的.NET架构的名称,
在实现一级其程序运行在CLR Common Language Runtime的环境中,类似Java中
虚拟机VM的概念,因此下文中对实现一级不再以.NET而以CLR称呼)
与Delphi一样,Delphi.NET自动引用System单元的内容,只不过单元名称
变成了Borland.Delphi.System而已。这是Object Pascal增加的语言特性之一
——命名空间(namespace),用于将类定义隔离在不同作用域中,以避免名字冲突。
而HelloWorld命名空间则是根据项目或单元名称自动生成的,实际代码一般保存在此
命名空间的类中。
我们先来看看代码所在的HelloWorld名字空间
.namespace HelloWorld
{
.class /*0200000B*/ public auto ansi Unit
extends [mscorlib/* 23000001 */]System.Object/* 01000001 */
{
...
} // end of class Unit
} // end of namespace HelloWorld
HelloWorld名字空间中只定义了一个Unit类。Delphi.NET中,每一个单元(Unit)
都在自己的命名空间下有一个自动生成的Unit类,用于实现全局变量、全局函数等等特性。
因为CLR中是不存在独立于类之外的元素的,所有元素都必须以类形式组织,所以对Delphi.NET/C++
之类支持全局变量、函数的语言,必须用一个自动生成的伪类来包装。Delphi.NET为每个单元
生成一个Unit类,Managed C++等语言中则使用其它诸如之类的名字。
因为我们的HelloWorld.dpr中没有定义自己的类,直接使用函数,所以在HelloWorld命名空间中,
只有一个Unit类,内容如下
.namespace HelloWorld
{
.class /*0200000B*/ public auto ansi Unit
extends [mscorlib/* 23000001 */]System.Object/* 01000001 */
{
.method /*06000027*/ private hidebysig specialname rtspecialname static
void .cctor() cil managed
.method /*06000025*/ public hidebysig specialname rtspecialname
instance void .ctor() cil managed
.method /*06000026*/ public hidebysig static void $WakeUp() cil managed
.method /*06000023*/ public static void Finalization() cil managed
.method /*06000024*/ public static void HelloWorld() cil managed
}
}
其中.cctor()和.ctor()函数分别是类Unit的静态/动态构造函数,负责对Unit
进行类和对象一级的构造工作。
对Delphi来说,构造函数所在级别是介于类和对象之间的。
TMyClass = class
public
constructor Create;
end;
var
Obj: TObject;
begin
Obj := TMyClass.Create;
try
//...
finally
FreeAndNil(Obj);
end;
end;
这里的Create由constructor关键字定义为构造函数,实现上类似类函数
(class function),隐含传入一个指向其元类(MetaClass)的指针和一个标志,
相对的普通成员函数隐含传入一个指向其实例的指针,也就是众所周知的Self。
而在构造函数中,调用时类似调用类函数传入其元类指针,函数中由编译器自动添加
_ClassCreate函数调用TObject.NewInstance分配内存并初始化对象,
将Self改为指向真正的对象。
在Delphi.NET中,.ctor()类似于Delphi中的构造函数,用于在分配内存空间后
构造对象实例,其被调用时,对象所需内存已经分配完毕,所有成员变量被初始化为
0、false或null。也就是说Delphi中构造函数的功能在CLR中被分为两部分,
分配和初始化内存功能由IL指令newobj完成,调用用户代码初始化对象功能由其构造函数
被newobj或initobj指令调用完成,前者用于在堆中分配并初始化对象,后者用于
调用构造函数初始化在堆栈上分配好的内存。
而.cctor()则是CLR中特有的静态构造函数概念,其代码由CLR保证在此类的任意成员
被使用之前调用,初始化类的静态成员。因而可以存在至多一个不使用参数的静态构造函数。
因为.ctor()和.cctor()函数都是有CLR内部使用的,因而定义其函数标志为
hidebysig specialname rtspecialname,分别表示此函数以函数整个定义而并非
仅仅以名字来区分,避免命名冲突;函数名对系统和CLR有特殊意义。
详细介绍请参加笔者另一系列文章《MS.Net CLR扩展PE结构分析》,里面有详细解析.
0.概述
自M$发布.NET以来,业界厂商态度大相径庭。但不可否认的是,
在M$雄厚实力和充足资金的保障下.NET架构已经逐渐站稳脚跟,
开始向Java等既得利益者发起冲击。
而作为开发工具领跑者的Borland公司,也于2002年末,
伴随其并没有太大新意的Delphi 7,一同发布了Delphi.NET预览版。
本文就是基于这个预览版本,针对其内部实现原理进行分析,
帮助读者在了解Delphi的基础上,过渡到.NET时代。
1. Hello Delphi!
1.1. 初见 Delphi.NET
在详细分析Delphi.NET实现之前,让我们先从感性上认识一下它:
//-----------------------------------------HelloWorld.dpr--
Program HelloWorld;
{$APPTYPE CONSOLE}
begin
Writeln(‘Hello Delphi!‘);
end.
//-----------------------------------------HelloWorld.dpr--
看上去是否很眼熟?没错,这是一个标准的Delphi控制台程序,
同时也可以直接使用Delphi.NET编译成一个真正的.NET程序
E:\Borland\Delphi.Net\demos\Hello>dccil HelloWorld.dpr
Borland Delphi Version 16.0
Copyright (c) 1983,2002 Borland Software Corporation
Confidential pre-release version built Nov 14 2002 17:05:31
HelloWorld.dpr(8)
9 lines, 0.28 seconds, 4816 bytes code, 0 bytes data.
E:\Borland\Delphi.Net\demos\Hello>peverify HelloWorld.exe
Microsoft (R) .NET Framework PE Verifier Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.
All Classes and Methods in HelloWorld.exe Verified
E:\Borland\Delphi.Net\demos\Hello>HelloWorld
Hello Delphi!
先使用 dccil,Borland经典Delphi编译器DCC32的IL版本,
将Delphi的Object Pascal代码编译成.NET架构的IL中间语言文件,
类似Java中的ByteCode;
再使用.NET Framework SDK附带的peverify验证程序有效性,
确认此HelloWorld.exe的确是.NET兼容的程序;
最后运行HelloWorld.exe程序,得到我们期望的结果。
看上去很美……不是吗?
不过在这看上去简单的代码背后,Borland做了大量底层工作,提供Delphi在.NET架构上
最大限度的源代码级兼容性,甚至不惜增加新语言特性(Delphi从Delphi3/4开始,语法上就
已经很稳定了,或者说已经很成熟了)。
1.2. 结构
用.NET Framework SDK附带的ILDASM工具打开HelloWorld.exe文件,
可以看到有两个名字空间Borland.Delphi.System和HelloWorld存在,
而MANIFEST里面是配件(Assembly)一级信息,详细含义请参加笔者另一系列文章
《MS.Net CLR扩展PE结构分析》,里面有详细解析。(.NET是M$的.NET架构的名称,
在实现一级其程序运行在CLR Common Language Runtime的环境中,类似Java中
虚拟机VM的概念,因此下文中对实现一级不再以.NET而以CLR称呼)
与Delphi一样,Delphi.NET自动引用System单元的内容,只不过单元名称
变成了Borland.Delphi.System而已。这是Object Pascal增加的语言特性之一
——命名空间(namespace),用于将类定义隔离在不同作用域中,以避免名字冲突。
而HelloWorld命名空间则是根据项目或单元名称自动生成的,实际代码一般保存在此
命名空间的类中。
我们先来看看代码所在的HelloWorld名字空间
.namespace HelloWorld
{
.class /*0200000B*/ public auto ansi Unit
extends [mscorlib/* 23000001 */]System.Object/* 01000001 */
{
...
} // end of class Unit
} // end of namespace HelloWorld
HelloWorld名字空间中只定义了一个Unit类。Delphi.NET中,每一个单元(Unit)
都在自己的命名空间下有一个自动生成的Unit类,用于实现全局变量、全局函数等等特性。
因为CLR中是不存在独立于类之外的元素的,所有元素都必须以类形式组织,所以对Delphi.NET/C++
之类支持全局变量、函数的语言,必须用一个自动生成的伪类来包装。Delphi.NET为每个单元
生成一个Unit类,Managed C++等语言中则使用其它诸如
因为我们的HelloWorld.dpr中没有定义自己的类,直接使用函数,所以在HelloWorld命名空间中,
只有一个Unit类,内容如下
.namespace HelloWorld
{
.class /*0200000B*/ public auto ansi Unit
extends [mscorlib/* 23000001 */]System.Object/* 01000001 */
{
.method /*06000027*/ private hidebysig specialname rtspecialname static
void .cctor() cil managed
.method /*06000025*/ public hidebysig specialname rtspecialname
instance void .ctor() cil managed
.method /*06000026*/ public hidebysig static void $WakeUp() cil managed
.method /*06000023*/ public static void Finalization() cil managed
.method /*06000024*/ public static void HelloWorld() cil managed
}
}
其中.cctor()和.ctor()函数分别是类Unit的静态/动态构造函数,负责对Unit
进行类和对象一级的构造工作。
对Delphi来说,构造函数所在级别是介于类和对象之间的。
TMyClass = class
public
constructor Create;
end;
var
Obj: TObject;
begin
Obj := TMyClass.Create;
try
//...
finally
FreeAndNil(Obj);
end;
end;
这里的Create由constructor关键字定义为构造函数,实现上类似类函数
(class function),隐含传入一个指向其元类(MetaClass)的指针和一个标志,
相对的普通成员函数隐含传入一个指向其实例的指针,也就是众所周知的Self。
而在构造函数中,调用时类似调用类函数传入其元类指针,函数中由编译器自动添加
_ClassCreate函数调用TObject.NewInstance分配内存并初始化对象,
将Self改为指向真正的对象。
在Delphi.NET中,.ctor()类似于Delphi中的构造函数,用于在分配内存空间后
构造对象实例,其被调用时,对象所需内存已经分配完毕,所有成员变量被初始化为
0、false或null。也就是说Delphi中构造函数的功能在CLR中被分为两部分,
分配和初始化内存功能由IL指令newobj完成,调用用户代码初始化对象功能由其构造函数
被newobj或initobj指令调用完成,前者用于在堆中分配并初始化对象,后者用于
调用构造函数初始化在堆栈上分配好的内存。
而.cctor()则是CLR中特有的静态构造函数概念,其代码由CLR保证在此类的任意成员
被使用之前调用,初始化类的静态成员。因而可以存在至多一个不使用参数的静态构造函数。
因为.ctor()和.cctor()函数都是有CLR内部使用的,因而定义其函数标志为
hidebysig specialname rtspecialname,分别表示此函数以函数整个定义而并非
仅仅以名字来区分,避免命名冲突;函数名对系统和CLR有特殊意义。
详细介绍请参加笔者另一系列文章《MS.Net CLR扩展PE结构分析》,里面有详细解析.
Delphi.NET 内部实现分析(1)
Delphi.NET 内部实现分析(2)
Delphi.NET 内部实现分析(3.1)
Delphi.NET 内部实现分析(3.2)
Delphi.NET 内部实现分析(3.3)
Delphi.NET 内部实现分析(3.4)
Delphi.NET 内部实现分析(4)
Delphi.NET 内部实现分析(5)
Delphi.NET 内部实现分析(5)
Delphi.NET 内部实现分析(4)
Delphi.NET 内部实现分析(3.4)
PAM 的应用开发和内部实现源码分析
Delphi中PING的实现
Delphi和Java实现webservice
用DELPHI实现为NT添加用户
Delphi中PING的实现ewe
Delphi中PING的实现a
Delphi屏幕截图技术实现2
Delphi屏幕截图技术实现d
使用.NET实现断点续传
在Delphi中实现VFP6的查询速度 - Delphi - 文档中心 - 源码天空
影响地勘单位发展的内部因素分析1
影响地勘单位发展的内部因素分析1
浅析多层结构及其在Delphi中的实现<一>