组件包工程有三个选项:
design time only
design time and run time
run time only问题1;我们知道run time only的包无法安装到组件面板上,那么run time only的组件
如何使用?是不是只能在程序中动态的创建?问题2:design time only和design time and run time两者我搞不懂有何区别,我做了很多实
验,尝试他们在各种连接方式(静态连接和动态连接)下的区别,但我没发现这两者有任何分别。
哪位高手系统的指点一下!

解决方案 »

  1.   

    网上很多呀,呵呵实际上,用包有几种方式:
    1,设计期包,主要是给DELPHI的IDE用的。不在本讨论的范围内。
    2,运行期包,有两种用法,一种是DELPHI的BUILD WITH RUNTIME PACKAGE,
       在这种方式下,你的项目必须确认有几个包,所有调用包的细节,DELPHI
       在编译的时候会帮你编译到EXE里去,你只需要在你的unit里USE你要用的
       包里的某个unit,就可以在你的unit里直接使用该unit里的任何数据或方
       法,这种调用方法下,代码上,使用包与只有单独的一个EXE,没有什么
       区别。只是纯粹的可以把应用程序拆分成几部分。
    3,另一种运行期包的方法是,调用包的细节由自己来实现,也就是用LOADPACKAGE
       来调用包,在这种方法下,你必须在包里注册自己的类,然后,就可以在
       主程序里用LOADPACKAGE来调用包并用FINDCLASS来查找DELPHI流已注册的
       该包里的类对象,之后创建类的实例以使用这个类。这种方式里,包主要
       的实现方法是用类来与主程序通讯、交换数据。
    4,我不知道有没有人知道怎么样可以实现自己控制调用包的细节,但又能实
       现如第二种方式的方便使用???就是说可以直接用该包里的任何数据,
       而不一定要注册,或者说注册的细节是怎么样实现的?
      

  2.   

    还有下面的一篇文章,足够了吧:
    先声明,是抄自网上的:
    ===========================[篇头]了解BPL和DLL的关系将有助于我们更好地理解DELPHI在构件制作、运用和动态、静态编译的工作方式。对初学DELPHI但仍对DELPHI开发不甚清晰的朋友有一定帮助。
    BPL vs. DLL
    (原文http://www.delphi3000.com/ 翻译:房客)第一部分:有关包的介绍一般我们编写编译一个DELPHI应用程序时,会产生一个EXE文件,也就是一个独立的WINDOWS应用程序。很重要的一点:区别于Visual Basic,DELPHI产生的是预先包裹的应用程序是不需要大量的运行库(DLL's)。假设:打开Delphi默认的工程(只有一个空白form),F9她将编译生成一个大约295 KB (Delphi 5)的可执行文件。然后打开Project | Options,把‘Build with runtime packages’选上再编译一下,EXE文件大小就只有15 KB左右了。我们编译一个DELPHI应用程序时默认地没有选择'Build with runtime packages',编译器将把程序运行所需要的代码直接写入你的EXE文件中,因此产生的程序是一个相对独立的程序,并不需要任何附属的支持文件(例如动态运行库文件DLL),这也就知道了为什么DELPHI产生的应用程序为什么都那么大。要建立尽可能小的DELPHI程序,方法之一就要充分发挥Borland package libraries的作用,简称BPL。先说什么是包?
    简而言之,一个包就是一个在DELPHI的IDE环境中被DELPHI应用程序共享的特殊的动态链接库。包允许我们通过多级应用将我们的程序的一部分当做一个分离的模块供其他应用程序来共享。包大致可分为运行期包(Run-time packages)和设计期包(Design-time packages):
    运行期包-当运行程序时提供VCL和库函数的支持,操作上很类似标准的动态链接库。
    设计期包-用来在DELPHI的IDE环境安装控件和为控件建立特殊的属性编辑器。设计期包允许包含控件、属性和控件编辑器等等,在IDE环境中,这类包是程序设计所必需的,也仅仅是DELPHI使用,并不和开发的应用程序一起分发。
    知道这些包的运用,我们也就知道了运行期包是如何做处理和它们对DELPHI程序员有什么帮助了。有一点必须说明:想很好地运用包并不要求你先成为一个成熟的控件编写者。DELPHI编程初学者也可以和应该尝试去接触包的概念,这将有利于你更好地理解包和DELPHI的工作关系。
    第二部分:适时运用包裹和DLL
     
    一般都认为加入WINDOWS操作系统中的动态运行库是一种最有用最高效的应用。在WINDOWS系统中,很多应用程序同时运行可能会引起了内存方面的问题,很多程序执行相似的操作任务,但各自又由不同的代码来控制并完成任务,动态运行库的作用就是将你的执行程序中的这些代码放到一个系统共享环境下的DLL中去。可能最为直观的动态链接库例子就是WINDOWS操作系统自己和它本身所带的API了。动态链接库通常都是用来集合过程(procedure)和函数(function)以供程序调用。当然我们在编写动态链接库的同时,也可以把一个DELPHI FORM放到一个DLL中去(例如一个AboutBox FORM),此外我们也可以在DLL中存储程序所需要的资源(resources)。更多关于DELPHI如何操作使用动态链接库,请参考相关书籍,不再赘述。在比较DLLs 和BPLs之前,我们先要知道可执行文件的2种代码链接的方式:静态链接和动态链接。静态链接就是当一个DELPHI工程被编译的时候,工程所需要的所有代码将被直接链接入你的程序执行文件。结果就是执行文件将包含程序所需要使用到的所有单元(units),你也许会说这样代码有点冗长,因为在通常默认情况下,一个FORM单元的uses子句列举了至少5个基本单元(如:Windows, Messages, SysUtils,...),尽管如此,DELPHI还是能够智能地自动链接单元中真正要用到的代码到工程代码中,从而尽可能地减少了执行文件的大小。使用静态链接,我们的应用程序就是一个相对独立的程序,不需要任何额外的支持文件或动态链接库(暂时不考虑BDE和ActiveX构件)。DELPHI中默认使用的就是静态链接方式。动态链接就是应用程序将和标准的动态链接库(DLLs)一起运行。动态链接方式不需要将代码直接建立到每个应用程序中去,单独为多个应用程序提供多线程的库函数支持,任何程序运行期间才需用到的包才将被加载,更值得一提的是:程序在动态方式需要调用的包是自动加载的,因此你不需要专门写加载包的代码。
    方法:简单地选中在Project | Options 对话框中'Build with runtime packages'复选框后,再次编译你的程序,你的程序代码将自动链接到动态运行包,而不是将引用单元都静态链接入你的工程执行文件。是选择BPL 还是 DLL?区别又在哪里?
    你可能很奇怪为什么要选择使用运行期包,而不是DLL,或者还有其他什么方法。相对于DLL而言,包裹的概念是DELPHI开发中所特有的,就是说其他语言编写的应用程序不能引用DELPHI建立的包裹。即使包是一种被DELPHI编写的应用程序所使用的动态链接库,它也同时提供给了DELPHI程序员更多的库函数支持。通常我们在DELPHI中建立动态链接库(DLLs)是用来存储不同环境下应用程序所需要使用到的过程和函数,而包不仅能够包含代码单元(untits)、构件和FORMs,还能包含DELPHI中的类(classes)-这就使我们能够在其中引用对象向导编码(object oriented code)。在包裹中,我们可以保存完整的通用DELPHI构件,而动态运行库(DLL's)对此则无能为力了。此外,在缩减程序代码上,DLLs和BPLs扮演着同样重要的角色,其主要原因就是在使用包裹或动态链接库技术后,都直接地减少了程序的文件大小。当然,还要说明的是:执行程序需要加载的DLLs或BPLs也可能会是很庞大的。例如如果需要分发你的包裹文件(主要是VCL包,vcl50.BPL)至少有2MB左右。
    尽管如此,如果你是要分发共享同个包的多个应用程序,你就可以省很多事了。当用户方系统中已经存在程序运行需要的部分文件(如:标准的DELPHI BPLs)后,就只需要下载程序的最小执行文件了。如果你的程序工程主要是通过INTERNET等方式分发和开展,那效率显然有很大的提高。
    同时,包的应用也节省系统内存,因为动态链接的结果就是:只有一个VCL被读入内存供所有使用运行期包的DLEPHI应用程序使用。
      

  3.   

    包裹的版本问题
    当你想升级你的动态链接库时(改变其中一些执行函数),你可以简单地编译产生新的程序文件,并上载新版本文件,所有正在使用该动态链接库的应用程序仍将工作(除非你已经将存在的旧版本程序去除)。
    换个角度来讲,在升级新包裹文件的同时,不要忘记升级程序的执行文件。正如你所了解的,包裹文件就是一个单元文件(units)的集合,所有编译过的单元文件(DCU)都含有版本信息,因此,除非我们有单元文件的源码(source),否则我们不能在DELPHI4或5中使用编译过的单元,所以一旦我们改变了单元文件中接口部分uses子句中列举出的任一单元文件,该文件就需要重新编译。编译器将检查DCU文件的版本信息,并决定单元是否需要重新编译。因此我们不能在DELPHI5编译的应用程序中使用在DELPHI6下编译的包,任何为你的应用程序服务的包和你的应用程序必须在相同环境下编译。因此,当给包裹命名的时要保留包裹名中包含有DELPHI的版本信息(如'AboutDP50',其中50就代表Delphi 5)。这可以有效防止文件版本的冲突问题,也可以避免很多不必要的麻烦,包使用者可以更清楚包的版本和包裹适用于哪个DELPHI编译器。如果你要分发运行期或设计期包给其他DELPHI程序员,建议同时提供了.DCP(含有包的头信息和各个单元文件)和.BPL文件,还有包中所包含的所有单元文件的.DCU文件。第三部分:建立和使用运行期包
     
    建立一个包裹
    建立一个包很简单,但在建包之前要做一些准备工作。首先,你需要知道你准备建立哪种类型的包文件:运行期包还是设计期包,或两者都是;其次是,建立、调试,反复地测试你想放置到包中去的单元文件;最后,为建立的包裹文件命名,还有就是选择一个合适的地方来存放文件。建立一个新的运行期包,按照以下步骤:1.启动DELPHI,并选择File | Close All关闭默认的工程。2.选择File | New...,在"New items"对话框中的"new"页面中双击Package图标(如图),就会出现包裹编辑器(如图):包裹编辑器包含2个文件夹:Contains和Requires。3.点击Add按钮,可以增加一个单元文件(构件或是一个简单的代码单元文件)。注意:你添加的是PAS源码文件而不是编译后的DCU文件。当你添加单元文件的同时,包中的单元的名字就显示在包裹编辑器的Contains文件夹中了。如图中添加了FindFile和PictureClip的单元文件。
     
    4.打开Requires文件夹,展开的列表表示包裹所需要的包的DCP文件,包裹文件最基本的就需要引用含有绝大部分标准可视控件的vcl50.dcp文件。5.当你添加完单元文件,单击Options按钮,在Description面板中的Usage options组中你需要选择包裹种类:是设计期包,还是运行期包,或者两者都是。如果选择Runtime only(仅运行期包),其他包的使用者将无法将图示2个构件安装到IDE环境中去。6.使用File | Save保存包工程文件(DPK),然后保存包文件,如AboutDP50,包裹文件的命名将很重要。7.在包裹器中,单击Compile按钮来编译包。8.如果不出什么意外,编译包后将建立一个包裹文件(BPL文件),期间你可能还要确定你必须增加的其他包裹(例如VCLX50),这些包都将在Requires文件夹中列出。9.完成,Borland package library文件已经成功建立,就等着使用了。在包裹编辑器中有一个Install按钮,就是用来将当前包裹安装成一个设计期包的。如果包裹是run-time only(仅运行期包),那Install按钮将无法使用。关于所建立的这些文件
    除了DPK文件和那些单元源码文件,DELPHI还使用包裹的动态链接版本产生一个BPL文件和一个含有包内标识信息DCP文件,DCP文件就是包中所包含单元文件的编译文件(DCU)的标识信息的集合。使用运行期包设计程序
    开始使用动态链接编写应用程序时,不需要写代码去加载运行期包裹,只需要在Project | Options中做相关设置,选择在Packages页的Runtime Packages编辑框中的包裹列表,编译程序时将自动链接。应用程序要使用到一个运行期包时,使用ADD按钮来增加包裹文件。 
    注意:尽管一个应用程序被链接到运行期包,程序的USES子句所列出的单元文件也必须都是存在的,编译运行期包裹只是告诉应用程序哪里可以找到构件代码而已。当配置一个使用到运行期包裹的应用程序时,确定用户拥有可执行文件和程序所需的库文件(.BPL或.DLL)。如果库文件在和EXE文件不同的目录下,必须将其指定到系统所能到达的目录。因此,最好的选择就是Windows\System系统目录。总而言之
    包裹使你能够有弹性地选择应用程序的分发方式,也使构件的安装变简单了,此外,使用包裹也减少了应用程序的文件大小,因此,使用包裹的开发方式还是具有不小的意义的。
      

  4.   

    感谢 linzhengqun(风。爱的翔舞)
    但还没有让我解惑
    第一个问题:我其实是想问运行期的包中的组件如何被拖到窗体面板上,看来似乎不可能的。
    第二个问题:
    设计期的组件只能被IDE使用?连接的时候不会连接进exe吗?
    这个问题我做了下列试验:
    我做了一个组件包,design time only的,然后另开一个工程使用它,在不勾选build with run time package的时候,也就是静态连接的时候,很正常,这时候这个包一定是连接进exe中了。
    当我勾选了build with run time package的时候,也就是把bpl留在exe外面,也是一切正常。
    我就不明白了,这样看来design time only的包完全可以当作run time的包来用啊,这是怎么回事呢?
      

  5.   

    如果你使用运行时包,则程序发布的时候,必须带上这些包,因为这些包没有被编译进执行文件中,
    而如果用设计期包,则发布时不用任何包,因为已经被编译进执行文件了。-》当我勾选了build with run time package的时候,也就是把bpl留在exe外面,也是一切正常。
    就不明白了,这样看来design time only的包完全可以当作run time的包来用啊,这是怎么回事呢?〕Re:应该是可以的。
      

  6.   

    to  linzhengqun(风。爱的翔舞):
    这个我知道,只要勾了build with run time package,列表中的包都会留在BPL里面,不会连接进exe,发布的时候必须带上这些BPL
    我奇怪的是,design time only的包如果可以当作run time的包来用,那么design time and run time这个选项岂不是没有任何存在的必要了?很疑惑,呵呵
    希望能和你继续讨论一下,:)
      

  7.   

    其实这一方面我也是一知半解。 因为没有多少实际的经验。呵呵
    希望有其他有经验的人来讨论吧。呵呵
    下面是Delphi的帮助:Usage options Select Design Package if you want the package to be installable on the Component palette.
    Select Runtime Package if you want the package to be deployable with an application.
    Select both Design Package and Runtime Package if you want the package to be both installable and deployable.
    If neither Design Package nor Runtime Package is checked, the package cannot be installed on the Component palette or deployed with Delphi applications. Use this option for packages that exist only to be referenced (required) by other (design-time) packages.
      

  8.   

    >>我奇怪的是,design time only的包如果可以当作run time的包来用,那么design time and run time这个选项岂不是没有任何存在的必要了?很疑惑,呵呵design time only就是design time only,怎么能当run time的包来使用?一个组件包通常都会提供两个独立的包,一个是design time only, 一个是run time only,
    但是有些包没有使用到designIntf,它们只是调用Classes单元的函数来注册组件,这种包可以做成单一的designtime and runtime,简化分发,当然,both形式的包也可以拆分成两个包,但是使用包的人就要编译两次,1次是runtime,1次是designtime,实际上,这是不必要的,因为register代码占不了几k的空间
      

  9.   

    to alphax(???) :
    我做过如下试验:
    做一个design time only的包,只编译出BPL,不安装到面板上,然后像使用run time only的包那样去使用它,一切正常,呵呵!所以我非常疑惑!
      

  10.   

    这个选项实际上不会影响调用的程序,也就是调用包的程序不会考察包到底是那一类型的,所以一个runtime包,你即使打成其他形式的包,对调用的程序来说都是一样的。这个选项有两个作用,一个是给IDE分辨到底是否调用包里面的注册函数以便将包里的组件类收集起来并表示Palette上,另一个作用就是给包的使用者一个关于包的用法的提示,使用者通过查看这个选项就可以知道包的用法,到底是设计期的还是运行期的或者两者。你的问题就象,你做了一个EXE,然后把它的扩展名改成dll,然后你跟我说,你可以直接在命令行运行这个dll,我感到迷惑,但是你的确可以象普通exe那样运行它,对于你自己当然可以这么干,但是并不是所有人都知道你这个dll其实本来是exe
      

  11.   

    首先感谢alphax(???)的不吝赐教!
    但是:
    把一个runtime包打成其他形式的包是什么意思?
    难道包的类型并不取决于我选的选项,而是取决于程序的源代码?
    我做一个design time的包,然后我不改变任何源代码,把选项改成runtime only,这时候编译出来的BPL就不能安装到面板了,这不就说明选项影响了编译出的BPL吗?你说选项会影响IDE对register的调用,那么当选项分别是design time only和design time and runtime的时候,IDE或者编译器对包的处理有什么不同?这是我最不明白的地方
    这两个选项不会是仅仅起到提示用户的作用吧,如果那样,我可真是要晕倒了...还有,通常组件做两个包,一个design time only,一个run time only,如果design time only可以当作run time来用,那只作disign time only的不就行了吗?我确实做了无数次试验,design time only的包作为design time和runtime使用都没有问题呀
    希望能继续讨论,帮我弄清楚这个问题,我将万分感谢!
      

  12.   

    你有这样的疑惑主要是对包类型对于一个包编译后的BPL的具体影响,以及包的用法不清楚,我再给你说说,其实这个选项,在包的原码(.dpk)中就是一个编译选项,这个选项和包目标文件(bpl)的某个资源项相关联,基本上每一个bpl都有这样的一个资源项,用于描述包的一些基本信息,编译的时候,这个包类型会被反映到资源信息中,也就是,实际上在bpl中,包的类型信息其实是由这个资源项的包信息结构提供的。IDE可以利用编译器编译所有类型的包,但是只有design time或者both的包才能被install。当IDE在试图install一个包以前,它会检查这个包的类型,
    if PackageType = RuntimeOnly then
        raise Exeption.Create('The package is a runtime package');
    当包的类型不是runtime Only的时候,它大致会遍历包里面的所有单元,查找每个单元的在interface部分披露的(全局的)Register函数,对每一个找到的Register函数进行调用,完后Delphi告诉你,在这个包所对应的ClassGroup里面,总共发现了多少个组件,最后重新载入Palette,刷新所有设计界面,这时你看到Palette上多了组件,或者组件的设计菜单改变了
    这就是IDE载入包的大致工作方式,如果从包的用途的角度来分,包就design time和runtime两种,design time类型的用于扩展IDE设计环境,增加IDE的可用性,包括一般意义上说的expert,组件、属性编辑器等等,比如你开发了一个组件,这个组件有一个特殊的属性,但是IDE对这种属性很陌生,不能够提供友好的属性编辑支持,那么,为了方便设计期的工作,你可以按照Delphi的规范,为这个属性设计一个Editor,然后将这个Editor做成一个design time包,注册到IDE里面去,注册了以后,当你再一次试图编辑这个属性的时候,IDE注意到这个属性有相应的编辑支持界面,那么IDE就会调用你的Editor。这就是Design time包的概念。
    那么runtime呢?和designtime面向IDE不同,runtime包面向普通的应用程序,runtime通常是类库,用于提供一些组件类或者非组件类,应用程序的build with RTP选项中填选的内容就是这些包。runtime包旨在创建一个delphi friendly的DLL,并且这个包独立于IDE环境。刚才说的你设计了一个组件,然后又作了一个属性Editor,你可以将组件以及属性Editor都打入单一的一个包里面(designtime and runtime),这时候,使用这个组件的应用程序就不能build with this package了,why?因为支持属性编辑器的designtime包都需要一个属于Delphi IDE环境的包,而你的应用程序无法提供这个被依赖的包。这种情况下,要么,你的应用程序放弃Build with this package或者你的应用程序本来就没打算要build with this package,这时包的单元将直接link到你的EXE目标代码里面;要么,你将这个包拆分成两个,designtime only和runtime only,这样你的程序就可以携带runtime only那个包。还有一些包,没有用到象组件编辑器这样的东西(不需要DElphi IDE环境的包),包里只是提供了注册组件的register函数,那么这种包可以做成both模式,因为registerXXXX函数是RTL函数,任何Build with RTP的Delphi编译的应用程序都会带上RTL包。这种包也可以分成designtime only和runtime only两个,做法就是把designtime only那个包包含一个单元,把register函数移到这个单元,剩下的都是runtime only的。这样,design time only包实际就只有一个单元,and, 一个函数,而从体积上来看,runtime包则是少了一个register或多个register函数。这就是包类型的实际意义
      

  13.   

    非常感谢alphax(???) 的耐心指导,我以前一直是VC和BCB,最近受了d2005的诱惑,才涉足delphi以及组件,发现这片天空异常精彩。
    我觉得目前书店里delphi的教程初级的很多,高级的深入的实在很少,不像VC的资源那么丰富,BCB也是同样的问题。我仔细的读了你的帖子,受益匪浅,明白了很多以前不明白的细节。看完之后,我的理解是,design time only的选项主要作用是在使用了组件编辑器之类的东西的情况下用来提示用户不要用build with runtime package的方式使用它。
    而对于编译器的编译过程来说,选择design time only 和design time and runtime并没有区别,是这样吗?
    比如说我做一个design time and runtime的包,只有组件本身和register,没有任何与IDE相关的东西。然后把选项修改成design time only,然后使用它的时候选择build with runtime package,这样做也不会有任何问题,对吧?
      

  14.   

    >>而对于编译器的编译过程来说,选择design time only 和design time and runtime并没有区别,是这样吗?前面说了,影响了bpl的资源项,实际上,如果选了designtime only,那么包信息的某个结构就会有一个designtime only标志位,选了runtime only,则有一个相应的runtime only标志位出现,而both的,就不会出现前面说的两个标志位。其他的不会有什么区别。>>比如说我做一个design time and runtime的包,只有组件本身和register,没有任何与IDE相关的东西。然后把选项修改成design time only,然后使用它的时候选择build with runtime package,这样做也不会有任何问题,对吧?除了给别的使用者造成误解以外,在执行上是不会有其他区别。
      

  15.   

    alphax(???)对VCL的了解如此透彻,佩服佩服!
    讨论至此,我的疑惑全部解决,再次感谢!结贴,派分!
    同时也感谢linzhengqun(风。爱的翔舞)