• Dephil之使用程序包(Using Packages)


    应用程序编写完后,可以用两种方法展开(deploy)它(“展开”( Deploying)的含义是指把应用程序分发给用户)。可将应用程序分发给公众,或者分发给某个公司内的用户。不论用何种方法,都需要知道哪些选项是可用的。从根本上讲,有两种选择:静态链接或动态链接使用程序包,下面将讨论这些选项,以便编程人员作出适当的选择来展开其应用程序。下面先讲讲选项。

    什么是程序包(What's a Package?)

    在讨论选项之前,先给出程序包的定义。

    一个程序包(package)就是一段编译过的代码,驻留在BPL扩展名的文件中。

    这个解释可能还是让人不好明白,下面来进一步讲解。移去外表包装,程序包实质上就是带bpl扩展名的DLL(这样讲可能有点过,但在这里还是很贴切的)。Delphi中有两种类型的程序包:运行阶段(runtime)程序包和设计阶段(design)程序包。下面分别讲述这两种类型的程序包,以便大家理解程序包是如何工作的。

    1、 运行阶段程序包(Runtime Packages)

    运行阶段程序包包含应用程序需要运行的代码。虽然Delphi提供了众多不同的程序包,但最主要的程序包是VCL70.BPL,这个程序包包含了全部的基础VCL代码。如果要在应用程序中使用程序包,就要装入VCL70.BPL程序包并根据需要从中调用例程。如果应用程序是数据库应用程序,同样也要装入VCLDB70.BPL,并按需要从中调用例程。除这里提到的两个程序包外,还有其他的Delphi程序包。

    除VCL程序包外,应用程序可能要用到其他程序包,当使用第三方组件或任何自己编写的组件时,就会出现这种情况。必须查看第三方组件的文档,搞清楚应用程序需要运行哪些程序包。下面先介绍设计阶段程序包,然后回过头来展开使用程序包的应用程序。

    2、 设计阶段程序包(Design Packages)

    大多数的Delphi组件都包含一个运行阶段程序包和一个设计阶段程序包。运行阶段程序包包含组件要运行的全部代码;设计阶段程序包包含组件在设计时要在窗体上运行的代码,包括属性编辑器和组件编辑器。

    设计阶段程序包有一个Requires列表,用以通知Delphi要运行哪些程序包。设计阶段程序包总是要用运行时程序包中的代码,还可能需要一个或多个VCL程序包中的代码。一个程序包可以包含多个组件的代码,运行阶段程序包与设计阶段程序包都是如此,没有必要一个组件对应一个单独的程序包。

    由于设计阶段程序包只包含在设计时显示组件所需的代码,所以它通常比相应的运行阶段程序包要小很多。Delphi仅仅在设计时使用设计阶段程序包,应用程序不使用设计阶段程序包。

    静态链接与动态链接(Static Linking Versus Dynamic Linking)

    上面,已经对程序包有了一些基本的了解,下面开始学静态链接和动态链接。

    1、 静态链接(Static Linking)

    当应用程序使用VCL静态链接时,它不再需要使用程序包;应用程序要运行的全部代码都直接链接到应用程序的可执行文件中,它是一个独立的程序,不需要任何的支持文件(程序包或DLLs)。

    Note

    任何规则都有例外,静态链接应用程序不需要任何DLLs支持的二个前提条件:

    1. 假定应用程序不是数据库应用程序。Delphi数据库应用程序运行时需要Borland Database Engine(BDE),BDE主要是由DLLs组成的集合,因此该应用程序是静态链接,也是需要使用DLLs的。
    2. 假定应用程序不使用任何的ActiveX控件。实际上ActiveX控件是DLL的一种形式,因此,当应用程序使用ActiveX控件时,它就不再是一个独立的应用程序。

    Delphi提供了链接选项,可对其进行选择。静态链接是缺省选择,与动态链接相比,静态链接有两条主要优点:

    1. 编程人员不需要操心附件文件的安装,应用程序包含了全部要运行的代码,不需要运行时程序库的支持。
    2. 静态链接的应用程序一般总比需要程序包的应用程序要小。在讲动态链接的优点和缺点时还要谈到这一点。

    静态链接有一个重要缺陷,但它只在使用到很多用户定义的DLLs的应用给程序中显露出来。这一缺陷是:在每个模块(主应用程序本身)和每个DLL中,VCL和RTL代码是重复的,这意味着代码中有不必要的重复。

    例如,假设每个模块至少要200KB的VCL基本代码和RTL代码,并假定一个主应用程序要求10个支持它的DLLs(动态链接库)。这意味着当实际只用200KB的代码时,却要使用2200KB的代码(11个模块x 200KB)。应用程序和DLLs都是静态链接,在它们之间不能共享VCL和RTL代码。

    2、 动态链接(Dynamic Linking)

    动态链接,是指应用程序在运行阶段动态地装入它要用的程序库代码。对于Delphi应用程序,这意味着任何需要的程序包都是在运行阶段装入。需要的程序包中肯定会包括一个或多个VCL程序包,并且可能还要用第三方程序包。

    Note

    应用程序装入程序包是自动进行的,不必编写代码来装入程序包,Delphi负责程序包装入的工作。在静态链接的基础上选择动态链接不需要对代码做任何修改,只需要改变一下分发应用程序的方式。这一点在后面很快就会讲到。

    动态链接相对于静态链接有一个主要优点:多个模块可共享代码。还记得前面举的“一个应用程序与10个支持它的DLLs”的例子么?使用动态链接,应用程序和它所有的DLLs可共享来自VCL程序包中的全部代码。每个模块至少可以减少200KB,因为所有的基本代码都包含在运行阶段DLLs中。当大型软件产品包含多个应用程序或许多DLLs时,这一优点就更加明显。

    动态链接也存在两个问题。第一个问题是需要与应用程序一起传送的程序包和DLLs可能非常大,光一个主要的VCL程序包VCL70.BPL就要1.3MB。除基本VCL程序包外,应用程序可能还需要用到其他的程序包,这意味应用程序至少需要1.3MB的DLLs才可以运行。第二个问题是动态链接更加难以捉摸、更麻烦,这个问题可以归结成“版本问题”。为了讲清楚这个问题可以打个比方。假定有两个版本的Delphi,用Delphi7.02创建了一个应用程序,并选择动态链接,这就要求传送VCL程序包和RTL DLL,客户在他的机器上安装上这个应用程序后一切工作正常。与此同时,可用Delphi4.0创建一个应用程序,也采用动态链接。客户购买了该应用程序并安装它。这个安装程序是家庭制作的,不那么正规,它会覆盖原有的应用程序安装的程序包和DLLs。由于用Delphi4.0创建的程序包版本比另一种的低,两者不兼容,应用程序会突然退出运行。是否看出问题所在?

    现实中,诸如Inprise的商用软件公司是这样解决这一个问题的:对一个软件的不同版本,用不同的文件名来命名其程序包和DLLs,并将版本信息嵌入到程序包和DLLs中(一个好的安装程序会自动检查版本号,并且只安装版本比系统中已存在的程序包版本高的程序包)。Borland公司的程序包不会出问题。

    如果使用的组件出自一家不负责任的公司,那就很可能出问题。随着Internet的迅速发展,组件的来源范围非常广,更要重视这个问题。在很多情况下,无法预料会出什么乱子,所以在购买便宜组件或使用免费组件时要特别小心。

    3、 到底哪个好?(So Which Is Better?)

    大家可能会问:应该用静态链接还是动态链接?这个问题的答案取决于所编写的应用程序的类型。一般来说,如果编写小规模或中等规模的应用程序,应该用静态链接;如果编写大规模的应用给程序或用到很多DLLs的应用给程序,则应该用动态链接。

    考察一个简单例子可能会使这个问题更直观些。前面我们创建了程序ScratchPad,使用静态链接,该程序编译后是427KB左右;如果使用动态链接,则EXE文件大小可降至22KB左右,但必须传送1.3MB的程序包。在这种情况下,动态链接不是一个好的选择。

    在应用程序中使用运行阶段程序包(Using Runtime Packages in Your Applications)

    如果选择使用动态链接,则只需修改工程选项中的一个设置。请按以下步骤操作:

    (1)从主菜单上选【Project | Options】菜单项,弹出“Project Options”对话框;

    (2)点击“Project Options”对话框中的Packages页面,并选中位于对于对话框底部的“Build with runtime package”选项;

    0254

    (3)点击OK关闭“Project Options”对话框;

    (4)重建(Rebuilt)该程序;

    这就是全部要做的事情。切记:使用动态链接,不需要对代码作任何修改。

    分发使用程序包的应用程序(Deploying Applications Using Packages)

    要分发采用动态链接的应用程序,必须知道应用程序使用了哪些程序包。如果按照上一步的步骤,则可以肯定知道需要VCL70.BPL,可能还需要其他的VCL程序包,这取决于应用程序中使用的组件。

    要照抄应用程序中用到的程序包,必须运行诸如TDUMP.EXE的工具并检查EXE引用的入口;TDUMP在Delphi安装目录的Bin目录下,要运行TDUMP,只需要打开命令提示符并转到应用程序所在目录,然后在命令行输入以下命令:

    tdump scratchPad.exe

    TDUMP立即以滚屏方式显示出信息,可按Pause键暂停以便查看显示信息。当然滚屏可能太快,可将TDUMP的输出定向到一个文本文件,这样查看文本文件即可。例如:

    tdump scratchPad.exe > dump.txt

    然后可在Code Editor中打开dump.txt文件查看其中的内容。

    在TDUMP生成的文件中能看到类似下面的内容:

    Section:             Import
      ImportLookUpTblRVA:00000000
      Time Stamp:        00000000
      Forwarder Chain:   00000000 (index of first forwarder reference)
    
    Imports from rtl70.bpl
                      __fastcall System::initialization()
                      __fastcall System::Finalization()
                      __fastcall System::RegisterModule(System::TLibModule *)
                      System::__linkproc__ __fastcall LStrAsg(void *, const void *)
                      System::__linkproc__ __fastcall LStrArrayClr(void *, int)
                      System::__linkproc__ __fastcall LStrClr(void *)
                      System::__linkproc__ __fastcall Halt0()
                      System::__linkproc__ __fastcall StartExe(System::PackageInfoTable *, System::TLibModule *)
                      System::__linkproc__ __fastcall HandleFinally()
                      __fastcall System::TObject::Dispatch(void *)
                      __fastcall System::TObject::FreeInstance()
                      __fastcall System::TObject::NewInstance(System::TMetaClass *)
    
    Imports from kernel32.dll
                      GetModuleHandleA
    
    Imports from vcl70.bpl
                      __fastcall Forms::initialization()
                      __fastcall Forms::Finalization()
                      __fastcall Forms::TApplication::MessageBox(const char *, const char *, int)
                      __fastcall Forms::TApplication::Run()
                      __fastcall Forms::TApplication::CreateForm(System::TMetaClass *, void *)
                      __fastcall Forms::TApplication::Initialize()
                      __fastcall Forms::TApplication::SetTitle(const System::AnsiString)
                      __stdcall Forms::TCustomForm::QueryInterface(const _GUID&, void *)
                      __fastcall Forms::TCustomForm::UpdateActions()
                      __fastcall Forms::TCustomForm::ShowModal()
                      __fastcall Forms::TCustomForm::SetFocus()
                      __fastcall Forms::TCustomForm::CloseQuery()

    从这里面找出所有带.bpl扩展名的文件并记录下它们的文件名。记录下的文件名就是那些必须与应用程序一起分发的程序包。

    Note

    拥有一个好的安装程序可以节省很多时间并省去许多麻烦,Delphi7专业版和企业版中带有InstallShield Express打包程序,Wise Install打包程序也不错。好的安装程序能指示出应用程序所需的程序包,并自动将它们包括进去。不建议在任何环境下都自己编写安装程序,因为编写安装程序要考虑的问题太多,很容易因考虑不周而出问题。

    大多数时候不需要在应用程序中使用运行阶段程序包,但有时候却又非使用程序包不可。

  • 相关阅读:
    笔试复习题《三》
    笔试复习题《二》
    《数据结构(C#语言描述)》
    设计模式《一》
    笔试复习题《一》之常用的排序算法
    序列模型(1)----简单介绍
    梯度消失、爆炸原因及其解决方法
    算法66------计算各个位数不同的数字个数【动态规划】
    TensorFlow实战学习笔记(14)------VGGNet
    TensorFlow技术解析与实战学习笔记(13)------Mnist识别和卷积神经网络AlexNet
  • 原文地址:https://www.cnblogs.com/pchmonster/p/2336743.html
Copyright © 2020-2023  润新知