Delphi7中单元文件内各个部分的执行顺序

注:本文主要是讨论delphi程序启动时和退出时的执行顺序,期间有些知识来源于Delphi帮助,有些来自《Delphi7程序设计教程》(这本书只告诉我有initialization 和 finalization 这两个关键字,但是没讲明白)(唉,现在的书只讨论框框架架,不讨论细节,写出来的东西让你看能看懂,别人一问或者自己一想,就是什么都不懂!讲的不细致呀!唉,自己琢磨吧!!)。代码用两排‘*’标明。


好了,进入正题,首先说明initialization 和 finalization 在代码单元中的位置:
************************************************************
unit Unit1;

interface

uses
  Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  ShowMessage('1 FormCreate');
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  ShowMessage('1 Destroy');
end;

initialization
  ShowMessage('1 ini');{单元初始化代码}
finalization
  ShowMessage('1 final');{单元退出时的代码}

end.
************************************************************
initialization —— 在单元中放在文件结尾前,包含用来初始化单元的代码,它在主程序运行前运行并且只运行一次。
finalization —— 在单元中放在 initialization 和 end. 之间,包含了单元退出时的代码。在程序退出时运行并且只运行一次。
OnClose —— 在点击关闭按钮或执行该事件时调用。
OnCreate —— 在窗体创建时调用。(我的感觉:该事件是在窗体创建之后,即执行构造函数后才执行的)
OnDestroy —— 在窗体销毁时调用,一般用来销毁程序员自己定义(自己定义、创建,而不是直接从控件板拖拉过来的控件)的对象、变量、指针等等。(与析构函数的关系我还没弄清)

下面是执行顺序(如果程序中没有 initialization、 OnCreate、 OnClose、 OnDestroy、 finalization 中的任何一项,则相应跳过即可):
程序启动 --> 执行 initialization 处的代码 --> 执行窗体的构造函数并创建相应窗体和单元中的对象(如拖拉的控件对象,全局变量等) --> 执行 OnCreate 事件 --> 程序运行 --> 关闭主窗体(此处指调用主窗体的Close或点击主窗体的关闭按钮) --> 执行 OnClose 事件 --> 执行 OnDestroy 事件 --> 执行 finalization 处的代码

以上是对于单个窗体而言,下面是对于多个窗体:
新建一工程,创建3个Form,分别是form1、form2、form3,默认情况下form1为主窗体。
<1 begin>
程序启动 --> 执行 initialization 处的代码(先 form1 然后 form2 最后 form3 ) --> 执行窗体的构造函数并创建相应窗体和单元中的对象(如拖拉的控件对象,全局变量等) --> 执行 OnCreate 事件(先 form1 然后 form2 最后 form3 ) --> 程序运行 --> 关闭主窗体(此处指调用主窗体的Close或点击主窗体的关闭按钮) --> 执行主窗体的 OnClose 事件 --> 执行 OnDestroy 事件(先 form3 然后 form2 最后 form1 ,注意哟,顺序倒过来了。) --> 执行 finalization 处的代码(先 form3 然后 form2 最后 form1 ,注意哟,顺序倒过来了。)
<1 end>
为什么 OnDestroy 和 OnCreate 的顺序相反?为什么  finalization和 initialization 的顺序相反?大家好好想想吧!


另外:如果我在form1中uses 一下Unit2(form2的代码单元)执行顺序如下:
<2 begin>
程序启动 --> 执行 initialization 处的代码(先 form2 然后 form1 最后 form3 ) --> 执行窗体的构造函数并创建相应窗体和单元中的对象(如拖拉的控件对象,全局变量等) --> 执行 OnCreate 事件(先 form1 然后 form2 最后 form3 ) --> 程序运行 --> 关闭主窗体(此处指调用主窗体的Close或点击主窗体的关闭按钮) --> 执行主窗体的 OnClose 事件 --> 执行 OnDestroy 事件(先 form3 然后 form1 最后 form2 ,注意注意,不一样了。) --> 执行 finalization 处的代码(先 form3 然后 form1 最后 form2 ,注意注意,不一样了。)
<2 end>


多个窗体(单元)一些细节性的东西:
1)initialization
initialization 的执行顺序取决于哪个窗体先被调用,对于<1>,由于3个窗体之间没有 uses 和被 uses 的关系,所以按照工程单元uses 中的顺序执行(在工程单元中,如下):
************************************************************
program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2},
  Unit3 in 'Unit3.pas' {Form3};

{$R *.res}

begin
  Application.Initialize;
  Application.CreateForm(TForm1,Form1);
  Application.CreateForm(TForm2,Form2);
  Application.CreateForm(TForm3,Form3);
  Application.Run;
end.
************************************************************
如果改变
uses
  Forms,u5b8bu4f53; font-size:16px"> 成为
uses
  Forms,
  Unit3 in 'Unit3.pas' {Form3},
  Unit1 in 'Unit1.pas' {Form1};
那么就是(先form2后form3最后form1)
对于<2>,由于form1中uses了Unit2,那么在编译Unit1之前必须先编译Unit2。顺序自然是(先 form2 然后 form1 最后 form3)
所以 initialization 的执行顺序首先看彼此单元之间是否有uses和被uses关系(简单的说就是:调用关系), 然后再看工程文件的uses的顺序。(呵呵,不要被uses弄混了!)

2)OnCreate
OnCreate 的执行顺序由工程单元中的如下类似代码决定
************************************************************
  Application.CreateForm(TForm1,Form3);
************************************************************
改变之后则相应发生改变。

3)OnDestroy
与OnCreate的顺序相反。(相反时一种对应,创建的顺序与销毁的顺序是相反的,这样是为了避免发生错误,这样也体现了编程要求思维严谨。)

4)finalization
与 initialization 的顺序相反。

再说说OnClose,
当调用窗体的Close或点击关闭按钮时调用该事件。
主窗体Close后,程序就退出。
非主窗体Close,仅仅是Close本窗体。(别说你在OnClose中调用其他窗体的关闭,那些不再讨论范围)

直接用Application.Terminate强制退出程序时,不调用OnClose事件。但 OnDestroy 和 finalization  要执行。

说了这么多,不知道有没有说明白问题。希望大家能领悟(俺表达能力比较差,呵呵~~~)。

 


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=575307

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都是大家转来转去,原文出处我已经找不到了。这篇文章写的很不错,但最后部分“PermuteFunction 的终极版本”描述的不太清楚,完全按照该文章代码执行,是不行的。可能是作者故意这样做的?本文最后提供修正后的下载地址。原文如下:一、关于API Hook1.什么是API Hook不知道大家是否还记得,在DO
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都是大家转来转去,原文出处我已经找不到了。 这篇文章写的很不错,但最后部分“PermuteFunction 的终极版本”描述的不太清楚,完全按照该文章代码执行,是不行的。需要修改mess.pas中代码才行。其实文中提到的一个结构,代码中并没有使用typePIMAGE_IMPORT_DESCRIPTOR = ^IMA
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c++ 调用, 抽空研究了一下该库的最新版 ,把部分api 翻译成了dephi版的 记录一下 地址 ffmpegvcl.zip
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄存器(ESP和EBP)6个段寄存器(ES、CS、SS、DS、FS和GS)
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:(dst) &lt;--(src) 1.dst和src类型必须匹配,即必须同为字节
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因为使用复杂,比较少用。 2.WinExec主要运行EXE文件。如:WinExec('Notepad.exe Readme.txt', SW_SHOW); 3.ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。 首先必须引用shellapi
API原型: Declare Function MoveFileEx& Lib "kernel32" Alias "MoveFileExA" (ByVal lpExistingFileName As String, ByVal lpNewFileName As String, ByVal dwFlags As Long) 参数 类型及说明 lpExistingFileName String,欲移
附带通用控件安装方法: ---------- 基本安装 1、对于单个控件,Componet-->install component..-->PAS或DCU文件-->install; 2、对于带*.dpk文件的控件包,File-->Open(下拉列表框中选*.dpk)-->install即可; 3、对于带*.bpl文件的控件包,Install Packages-->Add-->bpl文件名即可; 4
type   TRec=Record     msg:string;     pic:TMemoryStream; end; procedure TForm2.BitBtn1Click(Sender: TObject); var   ms:TMemoryStream;   Rec1,Rec2:TRec;   cc:tmemorystream;   jpg:TJPEGImage; begin   R
program Project1; { Types and Structures Definition } type   WNDCLASSEX = packed record     cbSize: LongWord;     style: LongWord;     lpfnWndProc: Pointer;     cbClsExtra: Integer;     cbWndExtra: In
   在Windows大行其道的今天,windows界面程序受到广大用户的欢迎。对这些程序的操作不外乎两种,键盘输入控制和鼠标输入控制。有时,对于繁杂 的,或重复性的操作,我们能否通过编制程序来代替手工输入,而用程序来模拟键盘及鼠标的输入呢?答案是肯定的。这主要是通过两个API函数来实现的。      下面以Delphi为例来介绍一下如何实现这两个功能。模拟键盘我们用Keybd_event这个ap
delphi中经常见到以下两种定义 Type TMouseProc = procedure (X,Y:integer); TMouseEvent = procedure (X,Y:integer) of Object; 两者样子差不多但实际意义却不一样, TMouseProc只是单一的函数指针类型; TMouseEvent是对象的函数指针,也就是对象/类的函数/方法 区
Windows 2000/XP和2003等支持一种叫做"服务程序"的东西.程序作为服务启动有以下几个好处:     (1)不用登陆进系统即可运行.     (2)具有SYSTEM特权.所以你在进程管理器里面是无法结束它的.     笔者在2003年为一公司开发机顶盒项目的时候,曾经写过课件上传和媒体服务,下面就介绍一下如何用Delphi7创建一个Service程序.     运行Delphi7,选
方法一: 1.调试delphi 写的服务程序,有这么一个办法。原来每次都是用attach to process方法,很麻烦。并且按照服务线程的执行线路,可能会停不到想要的断点。笨办法是,在procedure TsvcFrm.ServiceExecute(Sender: TService);中想要下断的语句前加个人定胜天的sleep(20000),但实际上这种办法是主观臆测的。可行,没问题。记得大学
Delphi For iOS开发指南(17):让应用程序禁止竖屏(也就是只显示横屏)     最近好多人问,怎么样让Delphi For iOS开发的应用程序禁止竖屏,也就是想让它一直横屏显示,横屏是好,一行可以放好几个控件,表格的话也可以多显示几列,看起来方便。 只要一句代码就可以让Delphi For iOS开发的应用程序禁止竖屏,如下: Application.FormFactor.Orie
一个比较完整的Inno Setup 安装脚本,增加了对ini文件设置的功能,一个安装包常用的功能都具备了。 [Setup] ; 注: AppId的值为单独标识该应用程序。 ; 不要为其他安装程序使用相同的AppId值。 ; (生成新的GUID,点击 工具|在IDE中生成GUID。) AppId={{A9861883-31C5-4324-BD9A-DC3271EEB675} ;程序名 AppName
在Delphi自带的Indy控件中其实是提供了MD2,MD4,MD5对象的,我们可以直接使用它们来完成MD5的签名算法。而不需要再去找其它的DLL或是Pas了。 在Uses单元中引用 IdHashMessageDigest,IdGlobal, IdHash 单元,再写如下代码即可以达到MD5的实现。 示例代码 procedure TForm1.Button1Click(Sender: TObjec
在Delphi 7下要制作系统托盘,只能制作一个比较简单的系统托盘,因为ShellAPI文件定义的TNotifyIconData结构体是比较早的版本。定义如下: 1 2 3 4 5 6 7 8 9 _NOTIFYICONDATAA = record    cbSize: DWORD;    Wnd: HWND;    uID: UINT;    uFlags: UINT;    uCallback
声明: 1. type Name = Existing type; 2. type Name = type Existing type; 3. type Name = (EnumValue1 [=value], EnumValue2 [=value] ...); 4. type Name = Expression1..Expression2; 5. type Name = ^Existing ty