您现在的位置是: 首页 > 硬件配置 硬件配置

delphi 硬件信息_delphi配件

ysladmin 2024-05-27 人已围观

简介delphi 硬件信息_delphi配件       delphi 硬件信息的今日更新不仅仅是技术上的更新,更是人们生活方式的改变。今天,我将和大家探讨关于delphi 硬件信息的今日更新,让我们一起探讨它对我们生活的影响。1.汇编和

delphi 硬件信息_delphi配件

       delphi 硬件信息的今日更新不仅仅是技术上的更新,更是人们生活方式的改变。今天,我将和大家探讨关于delphi 硬件信息的今日更新,让我们一起探讨它对我们生活的影响。

1.汇编和Delphi是一回事吗?在线等.

2.什么是delphi FireMonkey

3.delphi编程 实现选择控制多个声卡的切换

4.delphi的tinterfacedobject怎么释放

5.delphi托盘弹出信息

6.为什么 activex控件可以获取硬件信息

delphi 硬件信息_delphi配件

汇编和Delphi是一回事吗?在线等.

       Delphi一种程序设计高级语言,由PASCAL语言发展而来,有自己的数据库类型,也可以和常用的多种数据库连接。

       上手难易程度比VB困难些;

       数据处理能力不如ORACAL;

       但是,做中小型的数据库类程序开发很适用。

       ■什么是汇编语言

       汇编语言(Assembly Language)是面向机器的程序设计语言。

       在汇编语合中,用助记符(Memoni)代替操作码,用地址符号(Symbol)或标号(Label)代替地址妈。这样用符号代替机器语盲的二进制码,就把机器语音变成了汇编语言。于是汇编语言亦称为符号语言。

       使用汇编语言编写的程序,机器个能直接识别,要由一种程序将汇编语言翻译成机器语言,这种起翻译作用的程序叫汇编程序,汇编程序是系统软件中语言处理系统软件。汇编语言把汇编程序翻译成机器语言的过程称为f汇编。

       汇编语言比机器语言易于读写、易于调试和修改,同时也具有机器语言执行速度快,占内存空间少等优点,但在编写复杂程序时具有明显的局限性,汇编语言依赖于具体的机型,不能通用,也不能在不同机型之间移植。

       ■对于不同型号的计算机,有着不同的结构的汇编语言

       汇编语言由于采用了助记符号来编写程序,比用机器语言的二进制代码编程要方便些,在一定程度上简化了编程过程。汇编语言的特点是用符号代替了机器指令代码,而且助记符与指令代码一一对应,基本保留了机器语言的灵活性。使用汇编语言能面向机器并较好地发挥机器的特性,得到质量较高的程序。

       汇编语言是面向具体机型的,它离不开具体计算机的指令系统,因此,对于不同型号的计算机,有着不同的结构的汇编语言,而且,对于同一问题所编制的汇编语言程序在不同种类的计算机间是互不相通的。

       汇编语言中由于使用了助记符号,用汇编语言编制的程序输入计算机,计算机不能象用机器语言编写的程序一样直接识别和执行,必须通过预先放入计算机的"汇编程序"的加工和翻译,才能变成能够被计算机识别和处理的二进制代码程序。用汇编语言等非机器语言书写好的符号程序称为源程序,运行时汇编程序要将源程序翻译成目标程序。目标程序是机器语言程序,它一经被安置在内存的预定位置上,就能被计算机的CPU处理和执行。

       汇编语言像机器指令一样,是硬件操作的控制信息,因而仍然是面向机器的语言,使用起来还是比较繁琐费时,通用性也差。但是,汇编语言用来编制系统软件和过程控制软件,其目标程序占用内存空间少,运行速度快,有着高级语言不可替代的用途。

       ■html属于汇编吗?

       不属于汇编语言。它是Hypertext Markup Language的缩写,用来编写网页的语言.通常一个网页的网址最后面有.html或者.htm都是用这种语言编写的.

       另外,它一般用来编写静态网页,现在最流行的动态语言有ASP,.NET和PHP等等.

什么是delphi FireMonkey

       首先声明:在网上贴来的 希望对你有用吧。

       Access Violation(非法访问)错误的解决方法

       Access Violation(非法访问),General Protection Fault(一般保护性错误)或者Invalid Page Fault(无

       效页面错误),虽然说法不一样,但本质上总是由同一种错误引起的。Access Violation常常在计算机

       用户运行的程序试图存取未被指定使用的存储区时遇到。

       Access violation at address <十六进制值>

       in module <应用程序名>

       Read of address <十六进制值>

        Windows用户可能经常会看到类似于错误提示:“Error:Access violation at address 836556F8

       (004096da). Read of address 836556F8(00401000)”。作为一个Delphi程序开发者,遇到这种错

       误的机会比其他用户更多(^_^)。

        一旦Windows要在它被分配的存储区之外写数据信息,它就会覆盖其他程序甚至操作系统的命令或数

       据。一旦发生了这种情况,操作系统将会瘫痪或者以某种形式关闭,你必须重新启动计算机。例如,在

       Windows NT/2000下一个程序遇到这种错误时,Dr. Watson出现并且停止了该程序,捕获了一些快速的细

       节状态,再把它们用文本形式记录下来。Access Violation是某些最令人气恼的Windows程序遇到的错误

       之一。本文的目的就是让你找到Delphi中Access Violation的解决之道。首先声明一点,Access

       Violation和Microsoft Access没有任何关系。

        用Delphi开发程序时,我们可以把遇到的Access Violation分成两大类:运行期和设计期。

       一、设计期的Access Violation

       1.硬件原因

        在启动或关闭Delphi IDE以及编译一个Delphi工程时容易出现设计期的Access Violation。在你的

       计算机运行中出现Access Violation信息可能由各种各样的原因引起,包括系统BIOS、操作系统或者是

       硬件驱动线,有些声卡、显卡、网卡实际上也会导致这种错误。为什么这么说?计算机里的每一块卡都

       有它的设备驱动程序。对于不同的制造商、不同版本的Windows或者不同版本的Delphi都可能会遇到不同

       的问题。如下的几个步骤可能有助于你解决遇到的这些问题:

        1. 按照必要的步骤来证实你安装的驱动程序之间没有冲突。

        2. 有时降低显示分辨率可能会使某些古怪的显卡驱动程序稳定一些。

        3. 如果使用双处理器的主板,则保证对每个处理器的修改步骤一样。

        4. 对于计算机上的所有硬件注意使用最新的驱动程序。

       2.软件原因

        尽管Intel的计算机中Windows是最流行的操作系统,由于Windows系统天生的脆弱性和BUG,应用程

       序的误操作可能导致操作系统的迅速瘫痪(有时操作系统本身也会莫名其妙的瘫痪)。选择一个更稳定

       的程序开发环境是解决之道,如下几个步骤可以帮助你防止某些Access Violation的发生:

        (1)尽管Windows 9X相当流行,Windows NT/2000还是从多方面被证实是一个稳定得多的环境,几

       乎对于所有的Windows代码平台而言都是这样。

       (2) 确保对于Windows NT/2000已经安装了最新的service pack。每次安装完新版的service pack,你

       会发现机器变得稳定了。

       (3) 为你使用的各种版本的Delphi装上当前的更新或补丁(BDE、ADO……),这是提前预防错误的好

       办法。尽量使用最新的Delphi补丁——Access Violation错误数量尤其是设计期的错误数会大大减少。

       (4)如果你在IDE中经常随机遇到Access Violation错误,很有可能是你安装了一个不好的控件、包或

       者一个向导,它不是你使用的版本的Delphi所编写或编译的。试着一个一个卸载定制的控件(或者包)

       直到问题被解决,然后联系控件厂商关注这个问题的结果。

       (5) 检查一下计算机里是否有没用的东西和程序冲突。奇怪的软件程序和测试版的产品常常会导致

       Access Violation错误。

       (6) 如果系统设置有错误,那么Access Violation错误可能也会经常出现。如果你不停地遇到一个错

       误提示信息一样的Access Violation,记录下这些细节,然后通知可能导致这个错误的软件制造厂商。

       这些就是我对设计期Access Violation错误的全部建议。

       二、运行期的Access Violation

       Delphi常见的运行期Access Violation错误有哪些?如何防止?

       任何软件开发都会遇到这样的情况:你写好程序并测试,然后到处发送,结果用户告诉你它失败了。

       你可能考虑用编译指令{$D}编译你的程序——Delphi可以建立一个有助于定位Access Violation错误的

       源代码的镜像文件。工程选项对话框(Project|Options|Linker & Compiler)让你指定你所需要的一切

       。对于单元文件,debug信息和单元的对象代码一起记录在unit文件里了。编译使用这个单元的程序时,

       debug信息会增加单元文件的大小而且会增加额外的内存开销,但是它不会影响最终可执行文件的大小和

       运行速度。包含debug信息和镜像文件(Project|Options|Linker)选项的产品只有在{$D+} 编译指令下

       才会完成行信息。

       Access violation通常只在程序的某一个方面表现出来。当问题第一次出现时,考虑一下用户进行了什

       么操作是很重要的,然后从这里寻找突破口。从用户的角度来看,你的程序中止了他们的工作,由他们

       来告诉你出现的问题似乎让你延期解决这个问题了。然而,与用户交流是你发现问题和改善程序的惟一

       有效方法。

       现在你将可以知道在只给你冲突地址的情况下,如何轻松发现准确路径、源代码文件、发生Access

       violation错误的行:

       “Search - Find Error…”。

       当一个运行期Access violation出现时,你的用户得到的错误信息类似于如下情况:

       Access violation at address <十六进制值>

       in module <应用程序名>

       Read of address <十六进制值>

       如果你的程序在Delphi IDE里包含debug信息编译,你可以定位到导致这个错误源代码这一行。

       在Delphi程序中,一个最普遍导致Access Violation错误的原因是使用了一个没有被创建的对象。如果

       第二个地址<十六进制值>是FFFFFFF或0000000,十有八九就是你访问? 了一个没有被建立的对象。例如

       ,你调用了一个表单的事件,但这个表单不是自动创建的,也没有代码实例化。

procedure TfrMain.OnCreate(Sender: TObject);

       var BadForm: TBadForm;

       begin

       //这里将会产生Access violation

       BadForm.Refresh;

       end;

       假设BadForm在工程选项“Available Forms”窗口列表里——这个窗口是需要手工创建和释放的。在上

       面的代码里调用BadForm窗口的Refresh方法就会导致Access violation。

       如果你在Debugger选项窗口使“Stop on Delphi Exceptions”生效,那么就会弹出下面的信息:

       The message states that the EAccessViolation has occurred. The EAccessViolation is the

       exception class for invalid memory access errors.

       这是你在设计程序时将会看到的信息,下一个信息框将会出现,然后程序失败了:

       Access violation at address 0043F193

       in module ’Project1.exe’

       Read of address 000000.

       第一个十六进制数0043F193是发生Access violation的编译代码(Project1.exe)的运行期错误的地址

       。在IDE里选择菜单项“Search|Find Error…”,在对话框里输入错误发生的地址(0043F193)后点击

       “OK”按钮。Delphi将会重新编译你的工程文件,然后显示发生运行期错误的那一行代码,这里就是

       BadForm.Refresh这一行了。

       下面列出了Delphi环境下导致Access violation错误的大部分常见原因。这个列表不是也不可能覆盖所

       有可能出现的Access violation的情况。请在论坛上发送你的Access violation信息,大家可以试着一

       起解决这个问题——真正的实际事例一般情况下比列出来的错误隐晦得多。

       1. 调用一个不存在的对象

       如上所述,大部分Access violation的合理原因是使用了没有被创建或者已经被释放的对象。为了防止

       这种类型的Access violation的发生,请确保你访问的任何对象都首先被创建了。例如,当一个Table定

       位在一个没有被创建的data module(从auto-crete窗口里移走了)里,你可能在窗体的OnCreate事件里

       打开这个表。

       在下面的代码里,在调用一个已经被删除了的对象(b:TBitmap)事件后,一个Access violation出现了

       :

       var b:TBitmap;

       begin

       b:=TBitmap.Create;

       try

       //对b对象进行一些操作

       finally

       b.free;

       end;

       ...

       //由于b已经被释放,一个Access violation错误将会出现

       b.Canvas.TextOut(0,0,’这是一个 Access Violation’);

       end;

       2. 不存在的API参数

       如果你试图给Win API函数传递一个不存在的参数将会出现一个Access violation错误。解决此类Access

       violation错误的最好方法是查阅Win API帮助,看看这个API函数调用的参数信息以及参数类型。例如,

       总是保证不给一个缓冲参数传递一个无效指针。

       3. 让Delphi释放

       当一个对象拥有另一个对象时,让它给你做删除工作。因为默认情况下,所有的窗体(自动创建的)都

       属于Application对象。当一个应用程序结束时,它释放了Application对象,也就释放了所有窗体。例

       如,如果你在程序开始时自动创建了两个窗体(Form1/Unit1和Form2/Unit2),下面的代码就会导致

       Access violation错误的出现:

       unit Unit1;

       ...

       uses unit2;

       ...

       procedure TForm1.Call_Form2

       begin

       Form2.ShowModal;

       Form2.Free;

       //Access violation错误将会出现

       Form2.ShowModal;

       end;

       4. 杀死异常

       永远不要破坏临时异常对象(E),处理一个异常会自动释放异常对象。如果你自己手动释放了异常对象

       ,程序会试图再次释放它,那么就会出现Access violation错误:

       Zero:=0;

       try

       dummy:= 10 / Zero;

       except

       on E: EZeroDivide do

       MessageDlg(’不能用0做除数!’,mtError, [mbOK], 0);

       E.free. ////Access violation错误将会出现

       end;

       5. 检索一个空字符串

       一个空字符串是没有任何数据的。就是说,检索一个空字符串相当于访问一个不存在的对象,这将导致

       Access violation错误:

       var s: string;

       begin

       s:=’’;

       s[1]:=’a’;

       //Access violation错误将会出现

       end;

       6. 直接引用指针

       你必须间接引用指针,否则你会改变指针地址并可能会破坏其他存储单元 :

       procedure TForm1.Button1Click(Sender: TObject);

       var

       p1 : pointer;

       p2 : pointer;

       begin

       GetMem(p1, 128);

       GetMem(p2, 128);

       //下一行导致Access violation错误

       Move(p1, p2, 128);

       //下一行方法正确

       Move(p1^, p2^, 128);

       FreeMem(p1, 128);

       FreeMem(p2, 128);

       end;

       这些就是我对运行期Access Violation错误的全部建议,我希望你们也能对你们程序出现的Access Violation错误提出一些看法。

delphi编程 实现选择控制多个声卡的切换

       什么是delphi FireMonkey

       Embarcadero(英巴卡迪诺)公司正式推出Firemonkey。Firemonkey是一个基于CPU/GPU混合架构的业务应用平台,能够帮助开发人员设计出Windows、Android、Mac和iOS设备上的视觉绚丽的本地应用程序。

       Firemonkey允许开发人员创建具有快速的本地性能、动画和图像效果、企业级的数据连接以及交互式数据可视化的富HD和3D的图形应用程序,并且可以使用亚马逊和Azure云服务。

       Embarcadero公司认为,目前,丰富的用户体验已经在网络娱乐、广告和媒体中占有重要地位。它宣称,Firemonkey是第一款“能够在所有主要平台和设备上创建下一代的、可以满足商业软件的性能、连接及平台要求的富用户体验”的业务平台。

       使用Firemonkey,开发人员可以为Windows、Android、MAC OS X和iOS操作系统编写应用程序,这些应用程序可以在本地进行编译,节省了大量时间和资源。

       此外,Embarcadero称,通过其GPU构建的HD可缩放矢量和3D用户界面、动画和特效,使用Firemonkey创建数据和硬件密集型的应用程序,如科学、金融、医疗、地理信息系统、通信和机械制造方面的,可以带来更快、更直观的用户体验。

       Firemonkey的Livebindings还允许用户把任何类型的数据或信息连接到任意Firemonkey用户界面(UI)或图形对象上。

       用户还可以将实时数据绑定到标准的UI控件或者高清3D图形,通过这种方法使得任何的数据类型都可见。同时,已连接的应用程序,很容易利用Firemonkey组件在数据库、云或Web服务上创建和扩展。

       Firemonkey包括Delphi XE5、C++ Builder XE5,以及RAD Studio XE5工具套件,后者中包含了RadPHP和Embarcadero的Prism。

delphi的tinterfacedobject怎么释放

       以前编写过一些基于Direct Sound的程序,不知道你是否也用同样或类似的接口,我觉得对多设备可用时的选择问题的处理策略也许都是类似的。

       我在一开始使用 Direct Sound 接口时就注意到了多设备问题,它的API提供了获取设备信息的调用函数,在使用时要自己指定设备,或者使用系统默认设备,你在做完了大部分程序才发现这问题的话,那么估计你一直在选择使用系统默认设备,只是你可能没意识到,请仔细查看你的API的帮助文档和参数。

       解决多设备切换,你的程序是不能自动选择什么是最合适的设备的——这是根本不可能的,无论音频还是视频设备都一样,你没办法通过从API获得的信息确定哪个更适用。你能做的,是让用户界面选择,然后你保存配置(下次运行还默认用它)。最简单的实现方式,大概是设置界面上弄个ComboBox下拉框,你用API把所有音频设备及描述信息弄到,然后把描述信息填到ComboBox中去,用户选择哪个,你就用哪个。

       不是多声卡才有这问题,对视频和音频设备,单个的物理设备可能产生多个逻辑设备(它们往往是不同软件层次上的硬件访问接口),对你的程序而言,你也不易(也不需要)分辨什么是物理的和逻辑的设备,把API获得的设备全盘推给用户就成。

delphi托盘弹出信息

       悟透delphi 第四章 接口

       前不久,有位搞软件的朋友给我出了个谜语。谜面是“相亲”,让我猜一软件术语。我大约想了一分钟,猜出谜底是“面向对象”。我觉得挺有趣,灵机一动想了一个谜语回敬他。谜面是“吻”,也让他猜一软件术语。一分钟之后,他风趣地说:“你在面向你美丽的对象时,当然忍不住要和她接口!”。我们同时哈哈大笑起来。谈笑间,似乎我们与自己的程序之间的感情又深了一层。对我们来说,软件就是生活。

       第一节 接口的概念

       “接口”一词的含义太广泛,容易引起误解。我们在这里所说的接口,不是讨论程序模块化设计中的程序接口,更不是计算机硬件设备之间的接口。现在要说的接口,是一种类似于类的程序语言概念,也是实现分布式对象软件的基础技术。

       在DELPHI中,接口有着象类一样的定义方式,但不是用保留字class,而是用interface。虽然接口和类有着相似的定义方式,但其概念的内涵却有很大的不同。

       我们知道,类是对具有相同属性和行为的对象的抽象描述。类的描述是针对现实世界中的对象的。而接口不描述对象,只描述行为。接口是针对行为方法的描述,而不管他实现这种行为方法的是对象还是别的什么东西。因此,接口和类的出发点是不一样的,是在不同的角度看问题。

       可以说,接口是在跨进程或分布式程序设计技术发展中,产生的一种纯技术的概念。类的概念是一种具有普遍性的思想方法,是面向对象思想的核心。但是,接口概念也的确是伴随面向对象的软件思想发展起来的。用接口的概念去理解和构造跨进程或分布式的软件结构,比起早期直接使用的远过程调用(RPC)等低级概念更直观和简单。因为可以象理解一个对象一样理解一个接口,而不再关心这个对象是本地的或远程的。

       在DELPHI中,接口被声明为interface。其命名原则是:接口都以字母I开头命名,正如类都以字母T开头一样。在接口的声明中只能定义方法,而不能定义数据成员。因为,接口只是对方法和行为的描述,不存储对象的属性状态。尽管在DELPHI中可以为接口定义属性,但这些属性必须是基于方法来存取的。

       所有的接口都是直接或间接地从IUnknown 继承的。IUnknown是所有接口类型的原始祖先,有着类概念中TObject的相同地位。“一个接口继承另一个接口”的说法其实是不对的,而因该说“一个接口扩充了另一个接口”。接口的扩充体现的是一种“兼容性”,这种“兼容”是单一的,绝不会存在一个接口同时兼容两个父接口的情况。

       由于接口只描述了一组方法和行为,而实现这些方法和行为必须靠类。接口是不能创建实例的,根本就不存在接口实例之说,只有类才能创建对象实例。但一个接口的背后一定会有一个对象实例,这个对象就是接口方法的实现者,而接口是该对象一组方法的引用。

       从概念上讲,一个对象的类可以实现一个或多个接口。类对接口的责任只是实现接口,而不应该说类继承了一个或多个接口。“实现”一词和“继承”一词有不同的含义,应该从概念上区分开来。

       一般情况下,声明接口时需要一个能唯一标识该接口类型的GUID标识符。接口类型是要被分布在不同进程空间或计算机上的程序使用的,不象类的类型只是在一个程序空间内标识和使用。为了保证一种接口类型在任何地方都能被唯一识别,就必须要一种有效标识不同接口的方法。用人工命名的方法是不行的,没有谁能保证你开发的接口不会与别人重名。于是,一种所谓“全球唯一标识符”GUID(Globally Unique Identifier)应运而生。它是通过一种复杂的算法随机产生的标识符,有16个字节长,可以保证全世界任和地方产生的标识是不同的。在DELPHI的编辑环境中,你可以用Ctrl+Shift+G轻松产生一个GUID标识符,来作为接口的唯一标识。

       为接口指定GUID是必要的。虽然,不指定接口的GUID也可以常常可以编译通过,但在使用一些与接口识别和转换相关的功能时一定会有问题。特别是在基于COM的程序开发中,GUID一定不可少。

       接口的概念其实很简单,但却在分布式软件开发中起了关键作用。有的朋友之所以认为接口比较复杂,主要是因为不了解接口的概念和原理。因为人们总是对自己未知的东西有一种神秘感。这种神秘感往往会使人对未知世界产生畏惧心理。要揭开接口的神秘面纱,就必须不断的去学习和理解接口的奥秘。其实,在探索的过程中还会有许多的乐趣,你说对吧。

       第二节 IUnknown

       因为IUnknown是所有接口的共同祖先,所以一定要首先了解它。知道事情的起因,可以有效地帮助我们理解事情的过程和结果。IUnknown的原始定义是在System.pas单元中。因为定义在System.pas单元,那么一定是与系统或编译器相关的原始东西。一看IUnknown的定义,很简单,一共才6行。

       IUnknown = interface

       ['{00000000-0000-0000-C000-000000000046}']

       function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

       function _AddRef: Integer; stdcall;

       function _Release: Integer; stdcall;

       end;

       不过,这6行定义代码可是接口世界的基础。其中的三个接口方法蕴涵着简单而又博大精深的哲理,理解这些哲理将使我们在编写基于接口的程序时受益非浅。

       IUnknown的这三个接口方法是每一个接口对象类必须实现的方法,是接口机制的基础方法。为什么说这三个方法是接口机制的基础?且听我漫漫道来。

       首先来谈谈QueryInterface接口方法。我们知道一个对象类是可以实现多个接口的。任何接口对象都一定实现了IUnknown接口。因此,只要你获得了一个接口指针,那一定可以通过这个接口指针调用QueryInterface方法。而调用QueryInterface就可以知道这个接口指针还实现了一些什么接口。这对接口编程机制来说非常重要。判断一个接口指针是否实现了某接口功能,不同接口类型之间的接口匹配和转换,都与QueryInterface方法相关。

       QueryInterface有两个参数和一个返回值。第一个参数是接口类型的标识,即一个16字节的GUID标识。由于DELPHI编译器知道每种接口对应什么GUID,所以你可以直接使用象ImyInterface之类的标识符作为第一个参数。如果,该接口支持第一个参数指定的接口类型,则将获得的接口指针通过第二个参数Obj送回给调用程序,同时返回值为S_OK。

       从这里也可以看出,为什么为接口指定GUID标识是必要的。因为,QueryInterface方法需要这样的标识,而它又是接口和匹配和转换机制的基础。

       接下来我们再谈谈_AddRef和_Release极口方法。_AddRef和_Release接口方法是每一种要接口对象类必须实现的方法。_AddRef是增加对该接口对象的引用计数,而_Release是减少对接口对象的引用。如果接口对象的引用计数为零,则要消灭该接口对象并释放空间。这本是接口机制要求的一个基本原则,就好象1+1=2这样简单的道理,不需要深奥的解释。数学家才会有兴趣去研究一加一为什么会等于二?但数学家对1+1=2的理解是透彻的。同样,对接口对象引用机制的深刻理解,会让我们明白许多道理,这些道理将为我们的开发工作带来益处。

       有位大师曾说过:接口是被计数的引用!

       要理解这句话,我们首先要理解“引用”的概念。“引用”有“借用”的意思,表明一种参考关系。引用的一方只存在找到被引用一方的联系,而被引用的一方才是真正的中心。由于,通过这种引用关系可以找到对象,因此,引用实际就是该对象的身份代表。在程序设计中,引用实际上是一种指针,是用对象的地址作为对象的身份代表。

       在不是基于接口机制的程序中,本不需要就对象的引用关系进行管理。因为,非接口对象的实例都在同一个进程空间中,是可以用程序严格控制对象的建立、使用和释放过程的。可是,在基于接口机制的程序中,对象的建立、使用和释放可能出现在同一进程空间中,也可能出现在不同的进程空间,甚至是Internet上相隔千里的两台计算机中。在一个地方建立一个接口,可能实现这个接口的对象又存在于另一个地方;一个接口在一个地方建立后,又可能会在另一个地方被使用。在这种情况下,要想使用传统的程序来控制对象的建立和释放就显得非常困难。必须要又一种约定的机制来处理对象的建立和释放。因此,这一重任就落到了IUnknown的_AddRef和_Release的身上。

       这种接口对象引用机制要求,接口对象的建立和释放由对象实例所在的程序负责,也就是由实现接口的对象类负责。任何地方引用该对象的接口时,必须调用接口的_AddRef方法。不再引用该对象时,也必须调用接口的_Release方法。对象实例一旦发现再也没有被任何地方引用时,就释放自己。

       正是为了解决接口对象实例空间管理的问题,_AddRef和_Release方法才成为所有接口对象类必须实现的方法。

       第三节 接口对象的生死

       初看本节的标题似乎有点吓人。接口对象怎么会和生与死联系起来呢?接口对象的生死真的那么重要吗?一个好的统治者应该关心百姓的生死,同样,一个好的程序员也应该关心对象的生死。而接口对象又是流浪在分布式网络中的游子,我们更应该关心他们的生死!

       由于,接口对象是伴随接口引用的产生而建立,又伴随接口引用的完结而消亡。在DELPHI 中使用接口,似乎没有人关心,实现接口的对象是怎样出身又怎样死亡的。这正是DELPHI中使用接口的简单性,也是其在解决接口机制的使用问题上所追求的目标。需要接口时总有一个对象会为她而生,一旦不再引用任何接口时这个对象又无怨无艾的死去,绝不拖累系统一个字节的资源。真有点“春蚕到死丝方尽,蜡炬成灰泪始干”的凄情。

       因为接口对象的生死直接和引用该对象的接口数目有关,所以研究在什么情况下会增加一次接口引用,又在什么情况下会减少一次接口引用,是了解接口对象生死的关键。

       现在我们来实现一个最简单的接口对象类TIntfObj,它只实现了IUnknown接口中定义的三个基本方法。有的朋友一看就知道,这个类实际抄袭了DELPHI中TInterfacedObject类的部分代码。只是我们分别在_AddRef和_Release方法中增加了一些信息输出语句,以便于我们探索接口对象的生死问题。请看下面的程序:

       program ProgramA;

       uses

       SysUtils, Dialogs;

       type

       TIntfObj = class(TObject, IUnknown)

       protected

       FRefCount: Integer;

       function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

       function _AddRef: Integer; stdcall;

       function _Release: Integer; stdcall;

       end;

       function TIntfObj.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

       const

       E_NOINTERFACE = HResult($80004002);

       begin

       if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE;

       end;

       function TIntfObj._AddRef: Integer; stdcall;

       begin

       INC(FRefCount);

       ShowMessage(Format('Increase reference count to %d.', [FRefCount]));

       result:=FRefCount;

       end;

       function TIntfObj._Release: Integer; stdcall;

       begin

       DEC(FRefCount);

       if FRefCount <> 0 then

       ShowMessage(Format('Decrease reference count to %d.', [FRefCount]))

       else begin

       Destroy;

       ShowMessage('Decrease reference count to 0, and destroy the object.');

       end;

       result:=FRefCount;

       end;

       var

       aObject:TIntfObj;

       aInterface:IUnknown;

       procedure IntfObjLife;

       begin

       aObject:=TIntfObj.Create;

       aInterface:=aObject; //增加一次引用

       aInterface:=nil; //减少一次引用

       end;

       begin

       IntfObjLife;

       end.

       我们需要用单步调试功能来研究接口引用计数的增减与接口生死的关系。因此,建议你将Options选项中Complier页的Optimization项清除,以避免编译器会优化掉我们需要的指令。

       当程序执行到IntfObjLife子程序的三行代码时,请一步一步的调试代码。你会发现,当发生一次对接口类型变量的赋值行为时,就会引发对接口引用计数的增减。

       执行语句

       aInterface:=aObject;

       就会出现“Reference count increase to 1.”的信息,表明增加了一次接口引用。

       而执行语句

       aInterface:=nil;

       就会出现“Reference count decrease to 0, and destroy the object.”,表明接口引用减少到零并且删除了接口对象。

       所以,我们可以得出结论:当将引用值赋值给接口类型的变量时,会增加对接口对象的引用计数;而当清除接口类型变量的引用值时(赋nil),就会减少对接口对象的引用计数。

       在看看下面的代码,加深一下对这一结论的理解。

       var

       aObject : TIntfObj;

       InterfaceA, InterfaceB : IUnknown;

       ……

       aObject := TIntfObj.Create;

       InterfaceA := aObject; //引用增加至1

       InterfaceA := InterfaceA; //引用增加至2,但立即又减少至1

       InterfaceB := InterfaceA; //引用增加至2

       InterfaceA := nil; //引用减少至1

       InterfaceB := InterfaceA; //引用减少至0,释放对象

       ……

       无论是将接口对象赋值给变量,还是将接口变量赋值给接口变量,以及将nil赋值给接口变量,都印证这一结论。有趣的是,其中的InterfaceA := InterfaceA一句执行时,接口对象的引用先增加然后立即减少。为什么会这样呢?留给你自己去思考吧!

       接着,我们再来看看下面的代码:

       procedure IntfObjLife;

       var

       aObject:TIntfObj;

       aInterface:IUnknown;

       begin

       aObject:=TIntfObj.Create;

       aInterface:=aObject;

       end;

       这个过程与前面那个过程不同的是,将变量定义为局部变量,并且最后没有给接口变量赋nil值。单步调试这段代码我们发现,在程序运行到子程序end语句之前,接口对象的引用还是减少为0并被释放。这是为什么呢?

       我们知道,变量是有作用域的。全局变量的作用域是程序的任何地方,而局部变量的作用域只是在相应的子程序内。一旦变量离开它的作用域,变量本身已经不存在,它存储的值更是失去意义了。所以,当程序即将离开子程序时,局部变量aInterface将不在存在,而其所存储的接口对象引用值也将失去意义。聪明的DELPHI自动减少对接口对象的引用计数,以确保程序在层层调用和返回中都能正确地管理接口对象的内存空间。

       因此,我们又可以得出新的结论:当任何接口变量超出其作用域范围的时候,都会减少相关接口对象的引用计数。

       要注意的是,子程序的参数变量也是一种变量,它的作用域也是在该子程序范围内。调用一个含有接口类型参数的子程序时,由于参数的传递,相关接口对象的引用计数会被增加,子程序返回时又被减少。

       同样,如果子程序的反回值是接口类型时,返回值的作用域是从主调程序的返回点开始,直到主调程序最后的end语句之前的范围。这种情况同样会引起对接口对象引用计数的增减。

       该总结一下对象的生与死了。盖棺论定后我们可以得出以下原则:

       1. 将接口对象的引用值赋值给全局变量、局部变量、参数变量和返回值等元素时,一定会增加接口对象的引用计数。

       2. 变量原来存储的接口引用值被更改之前,将减少其关联对象的引用计数。将nil赋值给变量是一个赋值和修改接口引用的特例,它只减少原来接口对象引用计数,不涉及新接口引用。

       3. 存储接口引用值的全局变量、局部变量、参数变量和返回值等元素,超出其作用域范围时,将自动减少接口对象的引用计数。

       4. 接口对象的引用计数为零时,自动释放接口对象的内存空间。(在一些采用了对象缓存技术的中间件系统中,如MTS,可能并不遵循这一原则)

       需要提醒你的是,一旦你将建立的接口对象交给接口,对象的生死就托付给接口了。就好象将宝贝女儿嫁给忠厚的男人一样,你应该完全信任他,相信他能照顾好她。从此,与对象的联系都要通过接口,而不要直接与对象打交道。要知道,绕过女婿直接干预女儿的事情有可能会出大问题的。不信,我们看看下面的代码:

       program HusbandOfWife;

       type

       IHusband = interface

       function GetSomething:string;

       end;

       TWife = class(TInterfacedObject, IHusband)

       private

       FSomething:string;

       public

       constructor Create(Something:string);

       function GetSomething:string;

       end;

       constructor TWife.Create(Something:string);

       begin

       inherited Create;

       FSomething:=Something;

       end;

       function TWife.GetSomething:string;

       begin

       result := FSomething;

       end;

       procedure HusbandDoing(aHusband:IHusband);

       begin

       end;

       var

       TheWife : TWife;

       TheHusband : IHusband;

       begin

       TheWife := TWife.Create('万贯家财');

       TheHusband := TheWife; //对象TheWife委托给一般接口变量TheHusband

       TheHusband := nil; //清除接口引用,对象消失

       TheWife.GetSomething; //直接访问对象,一定出错!

       TheWife := TWife.Create('万贯家财');

       HusbandDoing(TheWife); //对象委托给参数接口变量aHusband,返回时对象消失

       TheWife.GetSomething; //直接访问对象,一定出错!

       end.

为什么 activex控件可以获取硬件信息

       你用的什么版本的Delphi啊?Delphi2005以上系统已经自带的托盘控件,如果是之前版本的,可以找第三方控件,下面的代码是Delphi2006自带的控件的源码,你可以保存成文件,直接引用,也可以注册成控件,直接放控件到Form上:

       TCustomTrayIcon = class(TComponent)

        private

        FAnimate: Boolean;

        FData: TNotifyIconData;

        FIsClicked: Boolean;

        FCurrentIcon: TIcon;

        FIcon: TIcon;

        FIconList: TImageList;

        FPopupMenu: TPopupMenu;

        FTimer: TTimer;

        FHint: String;

        FIconIndex: Integer;

        FVisible: Boolean;

        FOnMouseMove: TMouseMoveEvent;

        FOnClick: TNotifyEvent;

        FOnDblClick: TNotifyEvent;

        FOnMouseDown: TMouseEvent;

        FOnMouseUp: TMouseEvent;

        FOnAnimate: TNotifyEvent;

        FBalloonHint: string;

        FBalloonTitle: string;

        FBalloonFlags: TBalloonFlags;

        class var

        RM_TaskbarCreated: DWORD;

        protected

        procedure SetHint(const Value: string);

        function GetAnimateInterval: Cardinal;

        procedure SetAnimateInterval(Value: Cardinal);

        procedure SetAnimate(Value: Boolean);

        procedure SetBalloonHint(const Value: string);

        function GetBalloonTimeout: Integer;

        procedure SetBalloonTimeout(Value: Integer);

        procedure SetBalloonTitle(const Value: string);

        procedure SetVisible(Value: Boolean); virtual;

        procedure SetIconIndex(Value: Integer); virtual;

        procedure SetIcon(Value: TIcon);

        procedure SetIconList(Value: TImageList);

        procedure WindowProc(var Message: TMessage); virtual;

        procedure DoOnAnimate(Sender: TObject); virtual;

        property Data: TNotifyIconData read FData;

        function Refresh(Message: Integer): Boolean; overload;

        public

        constructor Create(Owner: TComponent); override;

        destructor Destroy; override;

        procedure Refresh; overload;

        procedure SetDefaultIcon;

        procedure ShowBalloonHint; virtual;

        property Animate: Boolean read FAnimate write SetAnimate default False;

        property AnimateInterval: Cardinal read GetAnimateInterval write SetAnimateInterval default 1000;

        property Hint: string read FHint write SetHint;

        property BalloonHint: string read FBalloonHint write SetBalloonHint;

        property BalloonTitle: string read FBalloonTitle write SetBalloonTitle;

        property BalloonTimeout: Integer read GetBalloonTimeout write SetBalloonTimeout default 3000;

        property BalloonFlags: TBalloonFlags read FBalloonFlags write FBalloonFlags default bfNone;

        property Icon: TIcon read FIcon write SetIcon;

        property Icons: TImageList read FIconList write SetIconList;

        property IconIndex: Integer read FIconIndex write SetIconIndex default 0;

        property PopupMenu: TPopupMenu read FPopupMenu write FPopupMenu;

        property Visible: Boolean read FVisible write SetVisible default False;

        property OnClick: TNotifyEvent read FOnClick write FOnClick;

        property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;

        property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;

        property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;

        property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;

        property OnAnimate: TNotifyEvent read FOnAnimate write FOnAnimate;

        end;

       TTrayIcon = class(TCustomTrayIcon)

        published

        property Animate;

        property AnimateInterval;

        property Hint;

        property BalloonHint;

        property BalloonTitle;

        property BalloonTimeout;

        property BalloonFlags;

        property Icon;

        property Icons;

        property IconIndex;

        property PopupMenu;

        property Visible;

        property OnClick;

        property OnDblClick;

        property OnMouseMove;

        property OnMouseUp;

        property OnMouseDown;

        property OnAnimate;

        end;

       { TTrayIcon}

       constructor TCustomTrayIcon.Create(Owner: TComponent);

       begin

        inherited;

        FAnimate := False;

        FBalloonFlags := bfNone;

        BalloonTimeout := 3000;

        FIcon := TIcon.Create;

        FCurrentIcon := TIcon.Create;

        FTimer := TTimer.Create(Nil);

        FIconIndex := 0;

        FVisible := False;

        FIsClicked := False;

        FTimer.Enabled := False;

        FTimer.OnTimer := DoOnAnimate;

        FTimer.Interval := 1000;

        if not (csDesigning in ComponentState) then

        begin

        FillChar(FData, SizeOf(FData), 0);

        FData.cbSize := SizeOf(FData);

        FData.Wnd := Classes.AllocateHwnd(WindowProc);

        FData.uID := FData.Wnd;

        FData.uTimeout := 3000;

        FData.hIcon := FCurrentIcon.Handle;

        FData.uFlags := NIF_ICON or NIF_MESSAGE;

        FData.uCallbackMessage := WM_SYSTEM_TRAY_MESSAGE;

        StrPLCopy(FData.szTip, Application.Title, SizeOf(FData.szTip) - 1);

        if Length(Application.Title) > 0 then

        FData.uFlags := FData.uFlags or NIF_TIP;

        Refresh;

        end;

       end;

       destructor TCustomTrayIcon.Destroy;

       begin

        if not (csDesigning in ComponentState) then

        Refresh(NIM_DELETE);

        FCurrentIcon.Free;

        FIcon.Free;

        FTimer.Free;

        Classes.DeallocateHWnd(FData.Wnd);

        inherited;

       end;

       procedure TCustomTrayIcon.SetVisible(Value: Boolean);

       begin

        if FVisible <> Value then

        begin

        FVisible := Value;

        if (not FAnimate) or (FAnimate and FCurrentIcon.Empty) then

        SetDefaultIcon;

        if not (csDesigning in ComponentState) then

        begin

        if FVisible then

        begin

        if not Refresh(NIM_ADD) then

        raise EOutOfResources.Create(STrayIconCreateError);

        end

        else if not (csLoading in ComponentState) then

        begin

        if not Refresh(NIM_DELETE) then

        raise EOutOfResources.Create(STrayIconRemoveError);

        end;

        if FAnimate then

        FTimer.Enabled := Value;

        end;

        end;

       end;

       procedure TCustomTrayIcon.SetIconList(Value: TImageList);

       begin

        if FIconList <> Value then

        begin

        FIconList := Value;

        if not (csDesigning in ComponentState) then

        begin

        if Assigned(FIconList) then

        FIconList.GetIcon(FIconIndex, FCurrentIcon)

        else

        SetDefaultIcon;

        Refresh;

        end;

        end;

       end;

       procedure TCustomTrayIcon.SetHint(const Value: string);

       begin

        if CompareStr(FHint, Value) <> 0 then

        begin

        FHint := Value;

        StrPLCopy(FData.szTip, FHint, SizeOf(FData.szTip) - 1);

        if Length(Hint) > 0 then

        FData.uFlags := FData.uFlags or NIF_TIP

        else

        FData.uFlags := FData.uFlags and not NIF_TIP;

        Refresh;

        end;

       end;

       function TCustomTrayIcon.GetAnimateInterval: Cardinal;

       begin

        Result := FTimer.Interval;

       end;

       procedure TCustomTrayIcon.SetAnimateInterval(Value: Cardinal);

       begin

        FTimer.Interval := Value;

       end;

       procedure TCustomTrayIcon.SetAnimate(Value: Boolean);

       begin

        if FAnimate <> Value then

        begin

        FAnimate := Value;

        if not (csDesigning in ComponentState) then

        begin

        if (FIconList <> nil) and (FIconList.Count > 0) and Visible then

        FTimer.Enabled := Value;

        if (not FAnimate) and (not FCurrentIcon.Empty) then

        FIcon.Assign(FCurrentIcon);

        end;

        end;

       end;

       { Message handler for the hidden shell notification window. Most messages

        use WM_SYSTEM_TRAY_MESSAGE as the Message ID, with WParam as the ID of the

        shell notify icon data. LParam is a message ID for the actual message, e.g.,

        WM_MOUSEMOVE. Another important message is WM_ENDSESSION, telling the shell

        notify icon to delete itself, so Windows can shut down.

        Send the usual events for the mouse messages. Also interpolate the OnClick

        event when the user clicks the left button, and popup the menu, if there is

        one, for right click events. }

       procedure TCustomTrayIcon.WindowProc(var Message: TMessage);

        { Return the state of the shift keys. }

        function ShiftState: TShiftState;

        begin

        Result := [];

        if GetKeyState(VK_SHIFT) < 0 then

        Include(Result, ssShift);

        if GetKeyState(VK_CONTROL) < 0 then

        Include(Result, ssCtrl);

        if GetKeyState(VK_MENU) < 0 then

        Include(Result, ssAlt);

        end;

       var

        Point: TPoint;

        Shift: TShiftState;

       begin

        case Message.Msg of

        WM_QUERYENDSESSION:

        Message.Result := 1;

        WM_ENDSESSION:

        begin

        if TWmEndSession(Message).EndSession then

        Refresh(NIM_DELETE);

        end;

        WM_SYSTEM_TRAY_MESSAGE:

        begin

        case Message.lParam of

        WM_MOUSEMOVE:

        begin

        if Assigned(FOnMouseMove) then

        begin

        Shift := ShiftState;

        GetCursorPos(Point);

        FOnMouseMove(Self, Shift, Point.X, Point.Y);

        end;

        end;

        WM_LBUTTONDOWN:

        begin

        if Assigned(FOnMouseDown) then

        begin

        Shift := ShiftState + [ssLeft];

        GetCursorPos(Point);

        FOnMouseDown(Self, mbMiddle, Shift, Point.X, Point.Y);

        end;

        FIsClicked := True;

        end;

        WM_LBUTTONUP:

        begin

        Shift := ShiftState + [ssLeft];

        GetCursorPos(Point);

        if FIsClicked and Assigned(FOnClick) then

        begin

        FOnClick(Self);

        FIsClicked := False;

        end;

        if Assigned(FOnMouseUp) then

        FOnMouseUp(Self, mbLeft, Shift, Point.X, Point.Y);

        end;

        WM_RBUTTONDOWN:

        begin

        if Assigned(FOnMouseDown) then

        begin

        Shift := ShiftState + [ssRight];

        GetCursorPos(Point);

        FOnMouseDown(Self, mbRight, Shift, Point.X, Point.Y);

        end;

        end;

        WM_RBUTTONUP:

        begin

        Shift := ShiftState + [ssRight];

        GetCursorPos(Point);

        if Assigned(FOnMouseUp) then

        FOnMouseUp(Self, mbRight, Shift, Point.X, Point.Y);

        if Assigned(FPopupMenu) then

        begin

        SetForegroundWindow(Application.Handle);

        Application.ProcessMessages;

        FPopupMenu.AutoPopup := False;

        FPopupMenu.PopupComponent := Owner;

        FPopupMenu.Popup(Point.x, Point.y);

        end;

        end;

        WM_LBUTTONDBLCLK, WM_MBUTTONDBLCLK, WM_RBUTTONDBLCLK:

        if Assigned(FOnDblClick) then

        FOnDblClick(Self);

        WM_MBUTTONDOWN:

        begin

        if Assigned(FOnMouseDown) then

        begin

        Shift := ShiftState + [ssMiddle];

        GetCursorPos(Point);

        FOnMouseDown(Self, mbMiddle, Shift, Point.X, Point.Y);

        end;

        end;

        WM_MBUTTONUP:

        begin

        if Assigned(FOnMouseUp) then

        begin

        Shift := ShiftState + [ssMiddle];

        GetCursorPos(Point);

        FOnMouseUp(Self, mbMiddle, Shift, Point.X, Point.Y);

        end;

        end;

        NIN_BALLOONHIDE, NIN_BALLOONTIMEOUT:

        begin

        FData.uFlags := FData.uFlags and not NIF_INFO;

        end;

        end;

        end;

        else if (Message.Msg = RM_TaskBarCreated) and Visible then

        Refresh(NIM_ADD);

        end;

       end;

       procedure TCustomTrayIcon.Refresh;

       begin

        if not (csDesigning in ComponentState) then

        begin

        FData.hIcon := FCurrentIcon.Handle;

        if Visible then

        Refresh(NIM_MODIFY);

        end;

       end;

       function TCustomTrayIcon.Refresh(Message: Integer): Boolean;

       begin

        Result := Shell_NotifyIcon(Message, @FData);

       end;

       procedure TCustomTrayIcon.SetIconIndex(Value: Integer);

       begin

        if FIconIndex <> Value then

        begin

        FIconIndex := Value;

        if not (csDesigning in ComponentState) then

        begin

        if Assigned(FIconList) then

        FIconList.GetIcon(FIconIndex, FCurrentIcon);

        Refresh;

        end;

        end;

       end;

       procedure TCustomTrayIcon.DoOnAnimate(Sender: TObject);

       begin

        if Assigned(FOnAnimate) then

        FOnAnimate(Self);

        if Assigned(FIconList) and (FIconIndex < FIconList.Count - 1) then

        IconIndex := FIconIndex + 1

        else

        IconIndex := 0;

        Refresh;

       end;

       procedure TCustomTrayIcon.SetIcon(Value: TIcon);

       begin

        FIcon.Assign(Value);

        FCurrentIcon.Assign(Value);

        Refresh;

       end;

       procedure TCustomTrayIcon.SetBalloonHint(const Value: string);

       begin

        if CompareStr(FBalloonHint, Value) <> 0 then

        begin

        FBalloonHint := Value;

        StrPLCopy(FData.szInfo, FBalloonHint, SizeOf(FData.szInfo) - 1);

        Refresh(NIM_MODIFY);

        end;

       end;

       procedure TCustomTrayIcon.SetDefaultIcon;

       begin

        if not FIcon.Empty then

        FCurrentIcon.Assign(FIcon)

        else

        FCurrentIcon.Assign(Application.Icon);

        Refresh;

       end;

       procedure TCustomTrayIcon.SetBalloonTimeout(Value: Integer);

       begin

        FData.uTimeout := Value;

       end;

       function TCustomTrayIcon.GetBalloonTimeout: Integer;

       begin

        Result := FData.uTimeout;

       end;

       procedure TCustomTrayIcon.ShowBalloonHint;

       begin

        FData.uFlags := FData.uFlags or NIF_INFO;

        FData.dwInfoFlags := Integer(FBalloonFlags);

        Refresh(NIM_MODIFY);

       end;

       procedure TCustomTrayIcon.SetBalloonTitle(const Value: string);

       begin

        if CompareStr(FBalloonTitle, Value) <> 0 then

        begin

        FBalloonTitle := Value;

        StrPLCopy(FData.szInfoTitle, FBalloonTitle, SizeOf(FData.szInfoTitle) - 1);

        Refresh(NIM_MODIFY);

        end;

       end;

       initialization

        // 这段代码是为了让通知窗口重建的时候通知应用程序

        TCustomTrayIcon.RM_TaskBarCreated := RegisterWindowMessage('TaskbarCreated');

Delphi的命令行编译命令

       Authorware作为一种主要面向非程序员的多媒体创作工具,具有简单易用、编程灵活的特点,但其软件功能相对比较简单。为了满足一些高级设计人员进行复杂程序创作的需要,Authorware从4.0版本开始提供了对ActiveX控件的支持,允许用户在Authorware文件中嵌入ActiveX控件,与其它支持ActiveX控件的环境中一样方便快捷地使用。由于有许多软件厂商支持ActiveX技术,所以大多数功能都能找到相应的ActiveX控件。这意味着在Authorware中,通过调用ActiveX控件来直接使用现成的程序模块,从而省掉许多繁琐的编程工作。所能使用的ActiveX控件,除了Windows操作系统本身提供的以外,.还可以根据需要,利用编程语言如VB、VC、Delphi等,制作具有特殊功能的ActiveX控件,然后在Authorware中使用它们。

       Borland出品的Delphi,有着闪电般的编译速度,但是在界面控件使用较多、工程项目较大的时候,编译一个工程仍需要一段时间,打开庞大的Delphi IDE,也需要时间。其实,在一个工程开发结束,调试完成之后的Release编译,完全可以用命令行来执行,因为Delphi的编译器参数不像C++编译器那样复杂。

       笔者把Delphi联机手册中关于命令行编译(command-line compiler)的几篇主题作了翻译,希望对Delphi开发人员有帮助。

       目录

       1. Command-line compiler

        命令行编译器

       2. Command-line compiler options

        命令行编译器选项

       3. Compiler directive options

        编译器指令选项

       4. Compiler mode options

        编译模式选项

       5. DCC32.CFG file

        编译器配置文件DCC32.CFG

       6. Debug options

        调试选项

       7. Directory options

        目录选项

       8. IDE command-line options

        IDE命令行选项

       9. Generated files

        几个IDE自动生成的文件介绍

       Command-line compiler

       命令行编译器

        Delphi's command-line compiler (dcc32.EXE) lets you invoke all the functions of the IDE compiler (DELPHI32.EXE) from the DOS command line (see IDE command-line options. Run the command-line compiler from the DOS prompt using the syntax:

        Delphi’s命令行编译器(dcc32.exe)允许你从DOS命令行方式(参照:IDE命令行选项)实现IDE编译器(delphi32.exe)的所有功能。用DOS命令运行命令行编译器语法如下:

        dcc32 [options] filename [options]

        dcc32 [选项] [文件名] [选项]

        where options are zero or more parameters that provide information to the compiler and filename is the name of the source file to compile. If you type dcc32 alone, it displays a help screen of command-line options and syntax.

        零或多个参数给编译器提供信息,文件名指定需要编译的源文件名。如果你单独输入dcc32,它会显示一个关于命令行编译的选项和语法的屏幕。

        If filename does not have an extension, the command-line compiler assumes .dpr, then .pas, if no .dpr is found. If the file you're compiling to doesn't have an extension, you must append a period (.) to the end of the filename.

        如果文件名没有扩展名,命令行编译器会查找扩展名为.dpr的同名文件,如果找不到,则查找扩展名为.pas的同名文件。如果你的源文件确实没有扩展名,你需要在文件名的末尾添加(.)。

        If the source text contained in filename is a program, the compiler creates an executable file named filename.EXE. If filename contains a library, the compiler creates a file named filename.DLL. If filename contains a package, the compiler creates a file named filename.BPL. If filename contains a unit, the compiler creates a unit file named filename.dcu.

        如果指定的源文件是一个工程文件,编译器会创建一个扩展名为.EXE的同名可执行文件。如果指定的源文件是一个库文件,编译器创建一个扩展名为.DLL的同名动态链接库文件。如果指定的源文件是一个包文件,编译器会创建一个扩展名为.BPL的同名包。如果指定的源文件是一个单元文件,编译器会创建一个扩展名为.dcu的目标代码文件。

        You can specify a number of options for the command-line compiler. An option consists of a slash (/) or immediately followed by an option letter. In some cases, the option letter is followed by additional information, such as a number, a symbol, or a directory name. Options can be given in any order and can come before or after the file name.

        你可以为命令行编译器指定多个参数。一个参数包含一个破折号“-”(或“/”)和紧跟着的一个选项字符构成。通常情况下,选项字符后面会跟一些附加的信息,如一个数字、一个符号、一个目录等。选项可以是任意顺序并且可以在源文件名前面或后面。

       Command-line compiler options

       命令行编译选项

        The IDE lets you set various options through the menus; the command-line compiler gives you access to these options using the slash (/) delimiter. You can also precede options with a hyphen (-) instead of a slash (/), but those options that start with a hyphen must be separated by blanks. For example, the following two command lines are equivalent and legal:

        IDE允许你使用菜单来设置各种编译选项,而命令行编译器允许你使用字符“/”作为分隔符来设定这些编译选项。你也可以使用连字符“-”来代替“/”,但是用“-”引出的参数之间必须用空格隔开。例如,下面两个命令都是等同的也是合法的:

        DCC -IC:\DELPHI -DDEBUG SORTNAME -$R- -$U+

        DCC /IC:\DELPHI/DDEBUG SORTNAME /$R-/$U+

        The first command line uses hyphens with at least one blank separating options. The second uses slashes and no separation is needed.

        第一个编译命令用“-”引出参数,且参数之间有多个空格分隔。第二个编译命令用“/”引出参数,参数之间不必要分隔。

        The following table lists the command-line options. In addition to the listed options, all single-letter compiler directives can be specified on the command line, as described in Compiler directive options.

        下列表中列出所有的命令行参数。在附加的选项列表中,所有的单字符编译器指令都可以在命令行编译中使用,详情请参照:编译器指令。

       Option Description

       选项 描述

       Aunit=alias 设置单元别名

       B 编译所有单元

       CC 编译控制台程序

       CG 编译图形界面程序

       Ddefines 编译条件符号定义

       Epath 可执行文件输出路径

       Foffset 查找运行期间错误

       GD 生成完整.Map文件

       GP 生成.Map文件Public段

       GS 生成.Map文件Segment段

       H 输出提示信息

       Ipaths 文件包含路径

       J 生成.Obj目标文件

       JP 生成C++类型.Obj目标文件

       Kaddress Set image base address

       LEpath 包.BPL文件输出路径

       LNpath .dcp文件输出路径

       LUpackage 使用运行期间包列表

       M 编译有改动的源文件

       Npath dcu/dpu文件输出目录

       Opaths .Obj文件(汇编目标代码文件)路径

       P 按8.3格式文件名查找

       Q 安静模式

       Rpaths 资源文件(.RES)路径

       TXext 目标文件扩展名

       Upaths 单元文件路径

       V 为Turbo Debugger生成调试信息文件

       VN 以.Giant格式生成包含命名空间的调试信息文件(将用于C++Builder)

       VR 生成调试信息文件.rsm

       W 输出警告信息

       Z Disable implicit compilation

       $directive Compiler directives

       --Help 显示编译选项的帮助。同样的,如果你在命令行单独输入dcc32,也会显示编译选项的帮助。

       --version 显示产品名称和版本

       Compiler directive options

       编译器指令选项

        Delphi supports the compiler directives described in Compiler directives. The $ and D command-line options allow you to change the default states of most compiler directives. Using $ and D on the command line is equivalent to inserting the corresponding compiler directive at the beginning of each source file compiled.

        Delphi支持用编译器指令关键字描述的编译器指令。使用“$”和“D”命令行选项可以改变所有的默认编译器状态。用“$”和“D”命令行选项等同于在源文件的前面添加编译器指令。

       Switch directive option

        编译器指令选项开关

        The $ option lets you change the default state of all of the switch directives. The syntax of a switch directive option is $ followed by the directive letter, followed by a plus (+) or a minus (-). For example:

        “$”允许你改变每一种编译器指令默认状态。编译器指令的语法是“$”后紧跟一个指令字符,再跟一个“-”或“+”。例如:

        dcc32 MYSTUFF -$R-

        compiles MYSTUFF.pas with range-checking turned off, while:

        不使用边界检查编译MYSTUFF.pas单元:

        dcc32 MYSTUFF -$R+

        compiles it with range checking turned on. Note that if a {$R+} or {$R-} compiler directive appears in the source text, it overrides the -$R command-line option.

        使用界面检查编译MYSTUFF.pas单元。如果将编译器指令{$R+}或{$R-}添加到源文件的开始,它将覆盖从命令行传入的参数。

        You can repeat the -$ option in order to specify multiple compiler directives:

        你可以用多个“$”来指定多个编译器指令,如:

        dcc32 MYSTUFF -$R--$I--$V--$U+

        Alternately, the command-line compiler lets you write a list of directives (except for $M), separated by commas:

        命令行编译器允许作用逗号分隔的编译器指定列表,如:

        dcc32 MYSTUFF -$R-,I-,V-,U+

        只需要用一个“$”符号。

        Only one dollar sign ($) is needed.

        注意,因为$M的格式不一样,你不能在逗号分隔的指令列表中使用$M

        Note that, because of its format, you cannot use the $M directive in a list of directives separated by commas.

        Conditional defines option

        条件编译选项

        The -D option lets you define conditional symbols, corresponding to the {$DEFINE symbol} compiler directive. The -D option must be followed by one or more conditional symbols separated by semicolons (;). For example, the following command line:

        “-D”选项允许你定义一个编译条件,符合你用{$DEFINE symbol}定义的编译器指令。“-D”选项后必须跟随一或多个用分号分隔的编译条件符号,如下命令:

        dcc32 MYSTUFF -DIOCHECK;DEBUG;LIST

        defines three conditional symbols, iocheck, debug, and list, for the compilation of MYSTUFF.pas. This is equivalent to inserting:

        定义了三个编译条件符号:IOCHECK,DEBUG,LIST,用于MYSTUFF.pas单元中。这等同于在源文件中插入以下语句:

        {$DEFINE IOCHECK}

        {$DEFINE DEBUG}

        {$DEFINE LIST}

        at the beginning of MYSTUFF.pas. If you specify multiple -D directives, you can concatenate the symbol lists. Therefore:

        如果你指定了多个“-D”选项,你可以联接它们,如下:

        dcc32 MYSTUFF -DIOCHECK-DDEBUG-DLIST

        is equivalent to the first example.

        等同于第一个例子。

       Compiler mode options

       编译模式选项

        A few options affect how the compiler itself functions. As with the other options, you can use these with either the hyphen or the slash format. Remember to separate the options with at least one blank.

        有几个选项能影响编译器自身的功能。像其它选项一个,你可以使用“/”或“-”的格式。别忘了用至少一个空格分隔这些选项。

        Make (-M) option

        选项(-M)

        The command-line compiler has built-in MAKE logic to aid in project maintenance. The -M option instructs command-line compiler to check all units upon which the file being compiled depends. Using this option results in a much quicker compile time.

        命令行编译器使用构造逻辑的方式来维护工程。“-M”选项指示编译器检查所有与编译文件相关联的文件。用这个参数会导致编译时间增大。

        A unit is recompiled under the following conditions:

        一个源文件在下列情况下会重新编译:

        The source file for that unit has been modified since the unit file was created.

        源文件被创建以来被修改过;

        用“$I”指令包含的任何文件,用“$L”包含的任何.Obj文件,或用“$R”关联的任何资源文件.Res,比源文件中的要新;

        Any file included with the $I directive, any .OBJ file linked in by the $L directive, or any .res file referenced by the $R directive, is newer than the unit file.

        The interface section of a unit referenced in a uses statement has changed.

        单元接口部分interface的uses段有改动。

        Units compiled with the -Z option are excluded from the make logic.

        在单元编译时指令“-Z”在构造逻辑期不被接受。

        If you were applying this option to the previous example, the command would be:

        如果你在上一个例子中使用这个指令,编译命令就应该是:

        dcc32 MYSTUFF -M

        Build all (-B) option

        编译所有 选项(-B)

        Instead of relying on the -M option to determine what needs to be updated, you can tell command-line compiler to update all units upon which your program depends using the -B option. You can't use -M and -B at the same time. The -B option is slower than the -M option and is usually unnecessary.

        用于取代要知道哪些单元需要更新-M的选项,你可以使用-B选项来更新所有你的程序中关联的单元。你不能在程序中同时使用-M和-B。选项-B比-M速度更慢,而且它并不是必需的。

        If you were using this option in the previous example, the command would be

        如果你在前一个例子中使用这个参数,编译命令就应该是:

        dcc32 MYSTUFF -B

        Find error (-F) option

        查找错误 选项(-F)

        When a program terminates due to a runtime error, it displays an error code and the address at which the error occurred. By specifying that address in a -Faddress option, you can locate the statement in the source text that caused the error, provided your program and units were compiled with debug information enabled (via the $D compiler directive).

        当一个程序由于运行期间错误而终止时,它会显示一个错误号和错误地址在错误发生时。用-Faddress选项来指定错误地址,你在源文件中能找到引发错误的位置,如果你的程序和单元编译时附加了调试信息(使用$D编译器指令)。

        In order for the command-line compiler to find the runtime error with -F, you must compile the program with all the same command-line parameters you used the first time you compiled it.

        为了命令行编译器能用-F选项查找运行期间错误,你必须传递与第一次编译时相同的指令列表。

        As mentioned previously, you must compile your program and units with debug information enabled for the command-line compiler to be able to find runtime errors. By default, all programs and units are compiled with debug information enabled, but if you turn it off, using a {$D-} compiler directive or a -$D- option, the command-line compiler will not be able to locate runtime errors.

        先前提到过,你的程序和单元必须启用调试信息,命令行编译器才能查找运行期间错误。默认情况下,所有的程序和单都是启用调试信息的,除非你用{-D}或-$D-指令关闭它,这样,命令行编译器就不能查找运行期间错误了。

       Use packages (-LU) option

        使用包(-LU)选项

        Use the -LU option to list additional runtime packages that you want to use in the application being compiled. Runtime packages already listed in the Project Options dialog box need not be repeated on the command line.

        使用-LU选项来在编译时添加你应用程序中要用到的运行期间包。运行期间包已经在“工程选项”对话框中列举的,不必再在命令行中添加。

        Disable implicit compilation (-Z) option

        (此选项在delphi6.0/7.0中有不同描述,在此不作翻译)

        The -Z option prevents packages and units from being implicitly recompiled later. With packages, it is equivalent to placing {$ IMPLICITBUILD OFF} in the .dpk file. Use -Z when compiling packages that provide low-level functionality, that change infrequently between builds, or whose source code will not be distributed.

        Target file extension (-TX) option

        目标文件扩展名(-TX)选项

        The -TX option lets you override the default extension for the output file. For example,

        选项-TX允许你改写默认的输出文件扩展名。例如:

        dcc32 MYSTUFF -TXSYS

        generates compiled output in a file called MYSTUFF.SYS.

        生成的将是一个叫做MYSTUFF.SYS的文件。

        Quiet (-Q) option

        安静模式(-Q)选项

        The quiet mode option suppresses the printing of file names and line numbers during compilation. When the command-line compiler is invoked with the quiet mode option

        安静模式选项禁止在编译时显示文件名及代码行数,如果命令行编译器调用这个选项的话。

        dcc32 MYSTUFF -Q its output is limited to the startup copyright message and the usual statistics at the end of compilation. If any errors occur, they will be reported.

        它的输出仅限于起始时行版权信息以及结尾的统计信息。当然,如果发生错误,它也会输出。

       DCC32.CFG file

       DCC32.CFG配置文件

        You can set up a list of options in a configuration file called DCC32.CFG, which will then be used in addition to the options entered on the command line. Each line in configuration file corresponds to an extra command-line argument inserted before the actual command-line arguments. Thus, by creating a configuration file, you can change the default setting of any command-line option.

        你可以设置一个编译选项列表到一个叫做DCC32.CFG的配置文件中,它将用于编译时附加到命令行参数后。配置文件的每一行都相当于一个额外的命令行参数插入到实际的命令行参数前(注意,是实际参数前)。因而,你可以使用这个配置文件改变一些命令行参数的默认设置。

        The command-line compiler lets you enter the same command-line option several times, ignoring all but the last occurrence. This way, even though you've changed some settings with a configuration file, you can still override them on the command line.

        命令行编译器允许你输入相同的命令行参数,它将忽略所有除最后一个之外。这个的话,尽管通过配置文件你可以改变一些设置,你仍然可以覆盖它使用命令行参数。

        When dcc32 starts, it looks for DCC32.CFG in the current directory. If the file isn't found there, dcc32 looks in the directory where DCC32.EXE resides.

        当dcc32启动时,它查找DCC32.CFG文件在当前目录。如果文件没有找到,dcc32会查找它所在的目录。

        Here's an example DCC32.CFG file, defining some default directories for include, object, and unit files, and changing the default states of the $O and $R compiler directives:

        以下是一个DCC32.CFG配置文件的例子,定义了关于文件包含、OBJ文件包含、单元文件搜索路径信息,并改变了编译器指令$O和$R的默认值。

        -IC:\DELPHI\INC;C:\DELPHI\SRC

        -OC:\DELPHI\ASM

        -UC:\DELPHI\UNITS

        -$R+

        -$O-

        Now, if you type:

        现在,如果你输入:

        dcc32 MYSTUFF

        the compiler performs as if you had typed the following:

        编译器把它当作你输入如下命令:

        dcc32 -IC:\DELPHI\INC;C:\DELPHI\SRC -OC:\DELPHI\ASM -UC:\DELPHI\UNITS -$R+ -$O- MYSTUFF

       Debug options

       调试选项

        The compiler has two sets of command-line options that enable you to generate external debugging information: the map file options and the debug info options.

        编译器有两个命令行参数可以生成外部调试信息:MAP文件选项和调试信息选项。

        Map file (-G) options

        Map文件(-G)选项

        The -G option instructs the command-line compiler to generate a .map file that shows the layout of the executable file. Unlike the binary format of executable and .dcu files, a .map file is a legible text file that can be output on a printer or loaded into the editor. The -G option must be followed by the letter S, P, or D to indicate the desired level of information in the .map file. A .MAP file is divided into three sections:

        选项-G指示命令行编译器生成一个.map文件来查看一个可执行文件的布局。不同于可二进制的可执行文件和.dcu文件,.map文件是一个可读的文本文件,可以被打印或是其它文本编辑器编辑。选项-G后必须跟字符S、P或D,去决定你想要在.map文件列出的信息。一个.MAP文件被分成三个节:

        Segment

        Publics

        Line Numbers

        -GS outputs only the Segment section, -GP outputs the Segment and Publics section, and -GD outputs all three sections. -GD also generates a .DRC file that contains tables of all string constants declared using the resourcestring keyword.

        -GS选项只输出Segment Section,-GS选项输出Segment和Publics,-GD输出所有的三个Sections.-GD选项也生成一个扩展名为.DRC的文件包含所有的用resourcestring关键字声明的字符串常量。

        For modules (program and units) compiled in the {$D+,L+} state (the default), the Publics section shows all global variables, procedures, and functions, and the Line Numbers section shows line numbers for all procedures and functions in the module. In the {$D+,L-} state, only symbols defined in a unit's interface part are listed in the Publics section. For modules compiled in the {$D-} state, there are no entries in the Line Numbers section.

        用默认的编译选项{$D+,L+}编译模块(程序或单元),Publics Section列举所有的全局变量、过程和函数,Line Numbers Section列举模块中所有的过程和函数的行号。如果用{$D+,L-}编译选项编译模块,Publics Section中仅列举在单元的interface部分定义的符号。如果用{$D-}选项编译模块,在Line Numbers Section没有任何入口。

        Debug info (-V) options

        调度选项(-V)

        The -V options (-V, -VN. and -VR), which cause the compiler to generate debug information, can be combined on the command line.

        选项-V、-VN、-VR会指示编译器生成调试信息,它们能在命令行中组合使用。

        Generate Turbo Debugger debug info (-V) option

        生成Turbo Debugger使用的调试信息的选项(-V)

        When you specify the -V option on the command line, the compiler appends Turbo Debugger 5.0-compatible external debug information at the end of the executable file. Turbo Debugger includes both source- and machine-level debugging and powerful breakpoints.

        当你在命令行中使用-V选项时,编译器会在可执行文件的末尾附加与Turbo Debugger5.0一致的外部调试信息。Turbo Debugger包含代码和硬件级别的强大的断点。

        Even though the debug information generated by -V makes the resulting executable file larger, it does not affect the actual code in the executable, and does not require additional memory to run the program.

        虽然附加调试信息到查执行文件中会使可执行文件增大,但是它并不影响实际可执行文件中的可执行代码,也不需要额外的内存来启动程序。

        The extent of debug information appended to the executable file depends on the setting of the $D and $L compiler directives in each of the modules (program and units) that make up the application. For modules compiled in the {$D+,L+} state, which is the default, all constant, variable, type, procedure, and function symbols are known to the debugger. In the {$D+,L-} state, only symbols defined in a unit's interface section are known to the debugger. In the {$D-} state, no line-number records are generated, so the debugger cannot display source lines whe

       今天关于“delphi 硬件信息”的讲解就到这里了。希望大家能够更深入地了解这个主题,并从我的回答中找到需要的信息。如果您有任何问题或需要进一步的信息,请随时告诉我。