翻译文章: 怎样编写DELPHI向导 / 李颖(0分)

  • 主题发起人 主题发起人 李颖
  • 开始时间 开始时间

李颖

Unregistered / Unconfirmed
GUEST, unregistred user!
<p align="center"><big><big><big>怎样编写DELPHI向导(一)</big></big></big></p>
<i><p>
本文没有完整的版权信息, 从内容看来, 应该是 The Revolutionary Guide to Delphi 2
一书的作者所著.
而且似乎很老, 看来是 Delphi 3 时期作写, 因此有些内容有点过时, 但仍然很有参考价值.
</p>
翻译: <a href=mailto:e.w@263.net>李颖(e.w@263.net)</a><br></i>
<p>
Delphi 和 C++Builder 是真正开放的开发环境, 在 Delphi 和 C++Builder 中提供了
接口, 使得用户可以将自己的工具和专家集成到 IDE 中.
本文将主要讨论 Delphi 向导(Wizards 以前也叫专家(Experts))的开发和集成.
本文产生的(32位)向导兼容于 Delphi 2.0 以上版本及 C++Builder.
Delphi 包括4种向导: 工程(Project)专家, 窗体(Form)专家, 标准专家, 及(仅限于32位)插入式(AddIn)专家.
前两种可以在专家库(Repository)中找到, 标准专家可以在 Help 菜单内找到(比如 Database Form Expert),
插入式专家则在 Delphi IDE 中提供它们自己的菜单界面(可以在菜单的任何位置, Help 菜单除外,
似乎Help 菜单被保留为只供标准专家使用). </p>
<p>
工程专家和窗体专家在你创建新的工程或新的窗体时被激活(就好象工程和窗体模板一样).
标准专家和插入式专家则不同, 一般不会创建新的工程或窗体,
而是提供某种类型的信息, 或者只创建新的文件或单元.
如果你曾经使用过向导, 你应该知道它为你带来的能力和方便. ease they can bring
工程向导根据你选择的参数为你创建完整的工程(比如 Application Wizard).
窗体向导则在你的当前工程中加入定制的窗体.
比如, Database Form Expert 产生一个显示外部数据库数据的窗体.
这些向导不仅仅是一种能被 Delphi 启动的外部工具,
它们实际上是作为开发环境的一部分与 Delphi 本身交互的.
这对于那些已经存在的 Delphi 专家来说并不奇怪(毕竟它们是由开发 Delphi 的同一组人编写并插入的,
而且我们都知道 Delphi IDE 本身也是用 Delphi 编写的),
但至少引起了我们的兴趣: 我们也可以编写 Delphi 向导, 并通过同样的方式与 Delphi 交互.
我们能够编写一个向导吗: 在 IDE 中打开文件, 开始一个新工程?
是的, 我们能够, 所有这些(以及更多的)问题我们都将很快看到!
</p>
<p>
1. TIExpert 接口
</p>
<p>
编写自己的向导的主要困难在于: 手册和在线帮助中都没有没有公开的文档,
(在我的书 The Revolutionary Guide to Delphi 2 和我在 The Delphi Magazine 专栏公开了这些文档).
如果你手中有包括这些文档的书, 硬盘上有这些源代码,
你会发现一些重要的文件, 甚至还有2个 Delphi 本身自动安装的向导示例.
重要的文件可以在子目录do
c, Source/VCL 和 Source/ToolsAPI 下找到,
主要件是 ExptIntf.pas, ToolIntf.pas, VirtIntf.pas 以及 ShareMem.pas.
ExptIntf.pas 展示了如何驱动并注册我们自己的向导,
ToolIntf.pas 则展示了如何使用 Delphi 的 Tool-Service 实现与 IDE 的集成.
</p>
<p>
要开始一个定制向导的工作, 我们先来看看 ExptIntf.pas 中定义的抽象基类 TIExpert,
在32位 Delphi 中定义如下:
</p>
Type &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;TExpertStyle&amp;nbsp;=&amp;nbsp;(esStandard,&amp;nbsp;esForm,&amp;nbsp;esProject,&amp;nbsp;esAddIn);
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;TExpertState&amp;nbsp;=&amp;nbsp;<b>set&amp;nbsp;of</b>&amp;nbsp;(esEnabled,&amp;nbsp;esChecked);
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;TIExpert&amp;nbsp;=&amp;nbsp;class(TInterface) &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;public<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Expert&amp;nbsp;UI&amp;nbsp;strings&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetIDString:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetName:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetAuthor:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetStyle:&amp;nbsp;TExpertStyle;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetMenuText:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetState:&amp;nbsp;TExpertState;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetGlyph:&amp;nbsp;HICON;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetComment:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetPage:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Launch&amp;nbsp;the&amp;nbsp;Expert&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;Execute;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end;
<br>
&amp;nbsp;<br>
 
<p align="center"><big><big><big>怎样编写DELPHI向导(二)</big></big></big></p>
<p>2. TGenericExpert: Hello, World!</p>
<p>
如果要驱动我们自己的向导(命名为 TGenericExpert), 我们必须从抽象基类 TIExpert 中继承,
TIExpert 中包括7个或9个抽象的成员函数(GetStyle, GetName, GetComment, GetGlyph, GetState,
GetIDString 以及GetMenuText, 对于32位版本的 Delphi 还有 GetAuthor 和 GetPage)
和1个抽象的成员过程 Execute.
由于 TIExpert 是一个抽象基类, 因此对于任何一个向导我们都需要重载所有需要的成员函数.
</p>
unit&amp;nbsp;Generic;
&amp;nbsp;<br>
interface &amp;nbsp;<br>
uses &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;Windows,&amp;nbsp;ExptIntf;
&amp;nbsp;<br>
&amp;nbsp;<br>
Type &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;TGenericExpert&amp;nbsp;=&amp;nbsp;class(TIExpert) &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;public &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Expert&amp;nbsp;Style&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetStyle:&amp;nbsp;TExpertStyle;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Expert&amp;nbsp;Strings&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetIDString:&amp;nbsp;string;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetName:&amp;nbsp;string;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetAuthor:&amp;nbsp;string;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetMenuText:&amp;nbsp;string;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetState:&amp;nbsp;TExpertState;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetGlyph:&amp;nbsp;HICON;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetComment:&amp;nbsp;string;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetPage:&amp;nbsp;string;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Expert&amp;nbsp;Action&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;Execute;&amp;nbsp;override;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;Register;
&amp;nbsp;<br>
&amp;nbsp;<br>
implementation &amp;nbsp;<br>
uses &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;Dialogs;
&amp;nbsp;<br>
&amp;nbsp;<br>
{ TGenericExpert 的实现细节在后面的文档中 }<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;Register;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RegisterLibraryExpert(TGenericExpert.Create) &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{Register};
&amp;nbsp;<br>
end.
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
现在我们更近地看一看我们这个派生的向导.
由于 TIExpert 是一个抽象基类, 我们需要为 TGenericExpert 重载所有需要用到的成员函数.
首先, 我们需要通过 GetStyle 方法指定向导类型
这个方法可以返回3(或4)个可能的值:
esStandard 告诉 IDE 将这个向导接口视为 Help 菜单中的一项,
esForm 告诉 IDE 将这个向导接口视为窗体模板,
esProject 告诉 IDE 将这个向导接口视为项目模板.
对于32位版本的 Delphi 向导, 还可以返回 esAddIn,
表示这是一个通过 TIToolServices 接口控制自身的界面的向导.
对于我们的 TGenericExpert, 只打算显示一个消息对话框, 因此使用 esStandard 类型.
</p>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetStyle:&amp;nbsp;TExpertState;&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;esStandard;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetStyle};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
设置向导类型之后, 我们需要设置其他信息.
GetName 方法应该返回一个唯一的描述名称标识这个向导, 比如 'Generic Wizard'.
</p>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetName:&amp;nbsp;String;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;'Generic&amp;nbsp;Wizard' &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetName};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
对于32位版本的 Delphi, 如果类型是 esForm 或 esProject,
那么, 我们需要返回一个有效的作者名称.
现在, 类型是 esStandard, 因此我们可以只返回一个空字符串.
对于 esForm 或 esProject 类型的向导, 这个名称将显示在32位版本的 Delphi 的专家库中.
</p>
{$IFDEF&amp;nbsp;WIN32} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetAuthor:&amp;nbsp;String;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;'Bob&amp;nbsp;Swart&amp;nbsp;(aka&amp;nbsp;Dr.Bob)'&amp;nbsp;{尽管对于 esStandard 类型不是必要的}<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetAuthor};
&amp;nbsp;<br>
{$ENDIF} &amp;nbsp;<br>
&amp;nbsp;<br>
<p>
如果类型是 esForm 或 esProject,
则 GetGlyph 方法应该返回一个 Bitmap(Delphi 1) 句柄或 Icon(Delphi 2.0x, 3) 句柄,
相应的位图或图标将显示在窗体或工程列表对话框中.
位图大小应该是 60x40 像素, 16色,
图标大小应该是 32x32 像素, 16色.
由于我们的 TGenericExpert 是 esStandard 类型, 因此我们在这里返回0.
下面的代码结合了16位和32位 Delphi 下的情况,
0是有效的, 表示位图/图标为空.
注意, 如果需要位图/图标, 但我们返回0, Delphi 将使用缺省的图象.
</p>
{$IFDEF&amp;nbsp;WIN32} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetGlyph:&amp;nbsp;HICON;
&amp;nbsp;<br>
{$else
} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetGlyph:&amp;nbsp;HBITMAP;
&amp;nbsp;<br>
{$ENDIF} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;{ 对于 esStandard 类型不需要}<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetGlyph};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
如果类型是 esForm 或 esProject,
则 GetComment 应该返回1到2行信息, 描述向导的功能.
由于是 esStandard 类型, 我们返回空字符串.
</p>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetComment:&amp;nbsp;String;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;''&amp;nbsp;{ 对于 esStandard 类型不需要}<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetComment};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
对于32位版本的 Delphi, 如果类型是 esForm 或 esProject,
通过 GetPage 方法我们可以指定向导在专家库中的所处的页面名称
如果不指定, 向导将放到缺省的 Form 页 或 Project 页.
由于我们编写的是一个 esStandard 类型的专家,
我们不需要指定页面名称, 因此返回空字符串.
</p>
{$IFDEF&amp;nbsp;WIN32} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetPage:&amp;nbsp;String;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;''&amp;nbsp;{ 对于 esStandard 类型不需要}<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetPage};
&amp;nbsp;<br>
{$ENDIF} &amp;nbsp;<br>
&amp;nbsp;<br>
<p>
如果类型是 esStandard,
则 GetMenuText 方法应该返回显示在菜单项上的实际文字, 比如 'Generic Wizard'.
由于菜单每次下拉时都会调用这个方法, 因此甚至可以提供上下文相关的文字.
</p>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetMenuText:&amp;nbsp;String;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;'&amp;amp;Generic&amp;nbsp;Wizard...' &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetMenuText};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
如果类型是 esStandard,
则如果 GetState 方法返回值包括 esChecked, 菜单项前将显示一个选择标记(Check Mark).
向导每次在菜单或列表中显示时会调用这个方法, 以便确定应该如何显示.
我们现在只返回 esEnabled.
</p>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;TGenericExpert.GetState:&amp;nbsp;TExpertState;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;[esEnabled] &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{GetState};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
最后, 当向导通过菜单, 窗体对话框, 工程对话框被调用时,
Execute 方法将被调用.
注意, 对于 esAddIn 类型的向导 Execute 方法绝对不会被调用.
esAddIn 类型的向导将通过 TIToolServices 接口控制自己的界面.
TIToolServices 接口后面将要讲到.
向导类型决定向导将如何被调用,
在这个例子中, 我们在 Execute 方法中只调用 MessageDlg, 表示向导的确在工作.
</p>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;TGenericExpert.Execute;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;MessageDlg('Hello&amp;nbsp;Nashville!',&amp;nbsp;mtInformation,&amp;nbsp;[mbOk],&amp;nbsp;0)
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{Execute};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
要安装我们的第一个向导, 就和安装一个新的组件一样, 需要做以下工作:
对于 Delphi 1.0, 选择 Options | Install,
对于 Delphi 2.0x, 3, 选择 Component | Install,
并将其加入到已安装的组件列表中.
Delphi 1, 2 只简单地将向导加入到组件库中,
Delphi 3 则需要将其加入到包中(缺省的包是DCLUSR30):
<br>(注: 这里似乎应该有图片, 但我手中的文件没有)
</p>
<p>
按下 OK 按钮, 将我们的 GenericExpert 的单元加入到 DCLUSR30 包之后,
我们需要确认 Delphi 重新编译包:
<br>(注: 这里似乎应该有图片, 但我手中的文件没有)
</p>
<p>
包被重新编译并安装到 Delphi IDE 中之后,
查看包编辑器, 可以看到 GenericExpert 的单元已经成为包的一部分了.
这个简单的例子表明了包不仅仅能用于组件, 也可以包含向导.
</p>
<p>
但 Delphi 完成了 COMPLIB.DCL 或 DCLUSR30.DPL 的编译和链接工作后,
你可以在 Help 菜单中看到我们的第一个新的向导:
<br>(注: 这里似乎应该有图片, 但我手中的文件没有)
</p>
<p>
选择 "Generic Wizard" 项, 向导将显示它的确在工作:
<br>(注: 这里似乎应该有图片, 但我手中的文件没有)
</p>
<p>
如我们所见的那样, 只有 Execute 方法包含有实际意义的代码,
后面的其他向导也是如此.
由于只有一个方法比较重要, 为了在这里不附加太多的源代码,
我计划使用下面这种方法: 用表格来表示上述9个方法,
而只列出 Execute 方法的细节.
我们的 TGenericExpert 将表示为:
</p>
TGenericExpert<br>
&amp;nbsp;&amp;nbsp;
GetStyle:&amp;nbsp;esStandard<br>
&amp;nbsp;&amp;nbsp;
GetIDString:&amp;nbsp;DrBob.TGenericExpert<br>
&amp;nbsp;&amp;nbsp;
GetName:&amp;nbsp;Generic&amp;nbsp;Wizard<br>
&amp;nbsp;&amp;nbsp;
GetAuthor&amp;nbsp;(win32):&amp;nbsp;Bob&amp;nbsp;Swart&amp;nbsp;(aka&amp;nbsp;Dr.Bob)<br>
&amp;nbsp;&amp;nbsp;
GetMenuText:&amp;nbsp;&amp;amp;Generic&amp;nbsp;Wizard...<br>
&amp;nbsp;&amp;nbsp;
GetState:&amp;nbsp;[esEnabled]<br>
&amp;nbsp;&amp;nbsp;
GetGlyph:&amp;nbsp;0<br>
&amp;nbsp;&amp;nbsp;
GetPage&amp;nbsp;(win32):<br>
&amp;nbsp;&amp;nbsp;
GetComment:<br>
<p>
而只列出 Execute 方法的细节(见前文).
我们将在本文的其余部分也使用这种方式.
</p>
 
<p align="center"><big><big><big>怎样编写DELPHI向导(三)</big></big></big></p>
<p>3. TSysInfoExpert</p>
<p>
除了简单的弹出消息框, 我们还能够显示根据需要显示窗体.
实际上, 有趣的事情就从这里开始.
一般来说, 可以认为我们的向导由两部分组成: 向导引擎和窗体界面.
我们已经讨论了如何编写向导引擎, 而且我们也知道如何编写窗体界面,
因此, 我们将把这两部分合在一起, 再来编写一个多少有点实际用途的向导.
我希望在这个向导中显示的信息可以在 SysUtils 单元中找到:
(与国家设置相关的)货币符号和日期/时间格式常数.
在线帮助中可以找到 SysUtils 单元中定义的这些常数, 但我们看不到它们的取值.
这很不幸, 但当我们进行时, 大多数情况下 Delphi 本身是处于运行状态的,
因此 SysUtils 单元是活动的(记住: Delphi 也是用 Delphi 编写的!)并且可以得到这些常数的取值.
</p>
<p>
因此, 使用 Dialog Expert, 我们可以创建一个多页的对话框,
使用一个 TabControl, 并给三各页面命名为 "Currency", "Date" 和 "Time".
然后, 我们在页面上放置几个 TLabel, 将 AutoSize 属性设置为 False,
并将其大小设置为和整个 TabControl 一样大(以便显示多行信息).
相应的源代码只负责在窗体创建后(在OnCreate 相应代码中)在适当的位置赋上适当的取值,
因此这个 SysInfo 向导的接口部分没有任何复杂之处.
TSysInfoExpert 的引擎部分如下:
</p>
&amp;nbsp;<br>
TSysInfoExpert<br>
&amp;nbsp;&amp;nbsp;
GetStyle:&amp;nbsp;esStandard<br>
&amp;nbsp;&amp;nbsp;
GetIDString:&amp;nbsp;DrBob.TSysInfoExpert<br>
&amp;nbsp;&amp;nbsp;
GetName:&amp;nbsp;SysInfo&amp;nbsp;Wizard<br>
&amp;nbsp;&amp;nbsp;
GetAuthor&amp;nbsp;(win32):&amp;nbsp;Bob&amp;nbsp;Swart&amp;nbsp;(aka&amp;nbsp;Dr.Bob)<br>
&amp;nbsp;&amp;nbsp;
GetMenuText:&amp;nbsp;&amp;amp;SysInfo&amp;nbsp;Wizard...<br>
&amp;nbsp;&amp;nbsp;
GetState:&amp;nbsp;[esEnabled]<br>
&amp;nbsp;&amp;nbsp;
GetGlyph:&amp;nbsp;0<br>
&amp;nbsp;&amp;nbsp;
GetPage&amp;nbsp;(win32):<br>
&amp;nbsp;&amp;nbsp;
GetComment:<br>
<br>
<p>
SysInfo 向导的 Execute 方法也很简单, 我们要作的就是创建, 显示, 并释放一个包含我们想要的信息的窗体.
Execute 过程的源代码如下:
</p>
<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;TSysInfoExpert.Execute;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;TSysInfoForm.Create(nil)&amp;nbsp;do &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ShowModal;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Free &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
end &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{Execute};
&amp;nbsp;<br>
<br>
<p>
很快, 我们得到了第一个"有用"的向导, 能在设计期间显示信息, 而不能其他任何方式使用.
</p>
<p>
这只是我们许多示例的第一个, 在后面的示例中我们将看到向导显示一个窗体界面,
并通过该窗体向用户显示(或设置)信息.
这些信息的来源(或设置的提交对象)之一是 Delphi 在 TIToolServices 类中提供给我们的称为为 ToolServices 的接口.
</p>
 
<p align="center"><big><big><big>怎样编写DELPHI向导(四)</big></big></big></p>
<p>4. ToolServices<br></p>
<p>
我们已经详细讨论了可爱但功能贫乏的向导,
为了编写真正有用的向导, 我们需要在 Execute 方法中做一些实际的事情.
比如显示一个(或者多个)有趣的窗体, 其中可能发生许多事情,
有点象我们介绍的 TSysInfoExpert.
你是否曾经觉得需要在 IDE 中载入不同于 .dpr 文件的工程? 没有过吗?
使用 Delphi 编写过 DLL 吗?
我就经常需要在 IDE 中把 .pas 或其他任何非 .dpr 文件作为一个工程打开.
实际上, 我的需求太大, 我希望编写一个向导,
能帮助我浏览整个磁盘, 目录, 搜索某些文件, 并作为新的工程打开.
可能作到吗? 要回答这个问题, 我们需要看看 Delphi 1.0 的 ToolIntf.pas 单元,
其中包含 TIToolServices 的定义("I" 表示接口), 如下:
</p>
unit&amp;nbsp;ToolIntf;
&amp;nbsp;<br>
interface &amp;nbsp;<br>
uses &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;WinTypes,&amp;nbsp;VirtIntf;
&amp;nbsp;<br>
&amp;nbsp;<br>
Type &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;TIToolServices&amp;nbsp;=&amp;nbsp;class(TInterface) &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;public &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Action&amp;nbsp;interfaces&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;CloseProject:&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;OpenProject(const&amp;nbsp;ProjName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;OpenProjectInfo(const&amp;nbsp;ProjName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;&amp;nbsp;<br>
export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;SaveProject:&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;CloseFile(const&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;SaveFile(const&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;OpenFile(const&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;ReloadFile(const&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;ModalDialogBox(Instance:&amp;nbsp;THandle;&amp;nbsp;TemplateName:&amp;nbsp;PChar;&amp;nbsp;&amp;nbsp;&amp;nbsp;<br>
WndParent:&amp;nbsp;HWnd;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DialogFunc:&amp;nbsp;TFarProc;&amp;nbsp;InitParam:&amp;nbsp;LongInt):&amp;nbsp;Integer;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;CreateModule(const&amp;nbsp;ModuleName:&amp;nbsp;string;&amp;nbsp;Source,&amp;nbsp;Form:&amp;nbsp;TIStream;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CreateFlags:&amp;nbsp;TCreateModuleFlags):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Project/UI&amp;nbsp;information&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetParentHandle:&amp;nbsp;HWND;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetProjectName:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetUnitCount:&amp;nbsp;Integer;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetUnitName(Index:&amp;nbsp;Integer):&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetFormCount:&amp;nbsp;Integer;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetFormName(Index:&amp;nbsp;Integer):&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetCurrentFile:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;IsFileOpen(const&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetNewModuleName(var&amp;nbsp;UnitIdent,&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;Boolean;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Component&amp;nbsp;Library&amp;nbsp;interface&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetModuleCount:&amp;nbsp;Integer;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetModuleName(Index:&amp;nbsp;Integer):&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetComponentCount(ModIndex:&amp;nbsp;Integer):&amp;nbsp;Integer;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetComponentName(ModIndex,CompIndex:&amp;nbsp;Integer):&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;&amp;nbsp;<br>
export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;{function&amp;nbsp;InstallModule(const&amp;nbsp;ModuleName:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;&amp;nbsp;<br>
export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;CompileLibrary:&amp;nbsp;Boolean;&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;Error&amp;nbsp;handling&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;RaiseException(const&amp;nbsp;Message:&amp;nbsp;string);&amp;nbsp;virtual;&amp;nbsp;export;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end;
&amp;nbsp;<br>
&amp;nbsp;<br>
implementation &amp;nbsp;<br>
&amp;nbsp;<br>
<p>
Tool services 对象在(Delphi/C++Builder)应用程序一方创建,
并在初始化时传递给负责 VCS/Expert 管理的 DLL.
注意, (Delphi/C++Builder)应用程序负责创建和释放接口对象, 而使用者绝对不要释放接口.
</p>
<p>
对使用者有效的 ToolServices 函数如下(对 Delphi 1.0, 2.0x, 3 都有效):
</p>
<br><big><big><i><b>动作:</b></i></big></big><br>
<b>CloseProject</b><br>
&amp;nbsp;&amp;nbsp;如果当前没有打开工程, 或当前工程关闭成功, 返回 True.<br><br>
<b>OpenProject</b><br>
&amp;nbsp;&amp;nbsp;如果指定名称的工程打开成功, 返回 True.
要创建新的工程和主窗体, 必须传入一个空字符串.<br><br>
<b>OpenProjectInfo</b><br>
&amp;nbsp;&amp;nbsp;如果指定的工程打开成功, 返回 True.
这个函数略过普通工程的载入特性(比如载入桌面设置文件, 显示源代码等),
而只简单地打开 .dpr 和 .opt 文件.<br><br>
<b>SaveProject</b><br>
&amp;nbsp;&amp;nbsp;如果当前工程未修改, 或当前没有打开工程, 或当前工程保存成功, 返回 True.<br><br>
<b>CloseFile</b><br>
&amp;nbsp;&amp;nbsp;如果指定的文件没有被打开, 或关闭成功, 返回 True.<br><br>
<b>OpenFile</b><br>
&amp;nbsp;&amp;nbsp;如果指定的文件已经被打开, 或打开成功, 返回 True.<br><br>
<b>ReloadFile</b><br>
&amp;nbsp;&amp;nbsp;如果指定的文件已经被打开, 而且再次成功地从磁盘载入, 返回 True. (注意, 这项操作不检查当前编辑器状态)<br><br>
<b>RefreshBuffers</b><br>
&amp;nbsp;&amp;nbsp;使得 IDE 检查所有打开的文件的日期/时间标记, 确定磁盘上的文件是否修改过,
如果是, 文件将被重新载入.<br><br>
<b>ModalDialogBox</b><br>
&amp;nbsp;&amp;nbsp;供非 VCL DLL 使用, 显示一个模态(modal)对话框.
注意, 使用 VCL 编写的 DLL 不需要调用这个方法, 而可以简单地使用窗体的 ShowModal 函数.<br><br>
<b>CreateModule</b><br>
&amp;nbsp;&amp;nbsp;从内存映象中创建新的模块, 包括源文件和(可选的)窗体文件.<br>
&amp;nbsp;&amp;nbsp;TCreateModuleFlags 包括:<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmAddToProject: 将新模块加入到当前工程中.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmShowSource: 在最上层的编辑器窗口中显示源文件.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmShowForm: 如果创建了窗体, 将窗体显示在源文件之上.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmUnNamed: 将模块标记为未命名, 用户第一次试图保存文件时将出现 SaveAs 对话框.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmNewUnit: 创建新的单元, 并加入到当前工程中. 注意: 其他所有参数将被忽略.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmNewForm: 创建新的窗体, 并加入到当前工程中. 注意: 其他所有参数将被忽略.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmMainForm: 如果模块包括窗体, 将窗体设置为当前工程的主窗体. 必须与 cmAddToProject 选项组合才有效.<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmMarkModified: 确保新模块标记为修改过.<br>

<br><big><big><i><b>信息:</b></i></big></big><br>
<b>GetParentHandle</b><br>
&amp;nbsp;&amp;nbsp;返回窗口句柄, 使用者创建窗体时将以这个句柄作为父窗口句柄.<br><br>
<b>GetProjectName</b><br>
&amp;nbsp;&amp;nbsp;返回当前工程的完整路径及名称, 如果没有打开工程, 返回空字符串.<br><br>
<b>GetUnitCount</b><br>
&amp;nbsp;&amp;nbsp;返回当前工程中包含的单元数量.<br><br>
<b>GetUnitName</b><br>
&amp;nbsp;&amp;nbsp;返回指定单元的完整路径及名称.<br><br>
<b>GetFormCount</b><br>
&amp;nbsp;&amp;nbsp;返回当前工程中包含的窗体数量.<br><br>
<b>GetFormName</b><br>
&amp;nbsp;&amp;nbsp;返回指定窗体的完整路径及名称.<br><br>
<b>GetCurrentFile</b><br>
&amp;nbsp;&amp;nbsp;返回当前文件的完整路径及名称, 当前文件可以是窗体或单元. 如果当前没有选择文件, 返回空字符串.<br><br>
<b>IsFileOpen</b><br>
&amp;nbsp;&amp;nbsp;如果指定的文件已打开, 返回 True.<br><br>
<b>GetNewModuleName</b><br>
&amp;nbsp;&amp;nbsp;自动生成有效的文件名及单元名标识符. 使用与 IDE 相同的机制.<br><br>
<b>GetModuleCount</b><br>
&amp;nbsp;&amp;nbsp;返回组件库中安装的模块数量.<br><br>
<b>GetModuleName</b><br>
&amp;nbsp;&amp;nbsp;返回指定模块的名称, 模块通过索引号指定.<br><br>
<br><big><big><i><b>组件库接口:</b></i></big></big><br>
<b>GetComponentCount</b><br>
&amp;nbsp;&amp;nbsp;返回确定的模块中安装的组件数量.<br>
<b>GetComponentName</b><br>
&amp;nbsp;&amp;nbsp;返回指定组件的名称, 组件通过模块索引号及组件在模块内的索引号指定.<br><br>

<br><big><big><i><b>意外处理:</b></i></big></big><br>
<b>RaiseException</b><br>
&amp;nbsp;&amp;nbsp;在 IDE 中产生一个意外, 这个意外的消息由传递给这个函数的字符串参数决定.
注意: 这将导致栈释放, 控制将<font color=red><b>不会</b></font>返回到这里.
库有责任确保在调用这个函数前正确地处理了意外情况.<br><br><br>
(与 Delphi 1.x 相比)在 Delphi 2.0x, 3 中 TIToolInterface 包括一些扩展的 Tools API,
不仅是 TIExpert 增加了新的方法, 更主要的是 TIToolServices.
下面这些扩展的方法是新增的, 而且只对32位版本的 Delphi 有效(与 Delphi 1.0 中相同的方法没有列出):
<br><br>
TIToolServices&amp;nbsp;=&amp;nbsp;class(TInterface) &amp;nbsp;<br>
public &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Action&amp;nbsp;interfaces&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;CreateModuleEx(const&amp;nbsp;ModuleName,&amp;nbsp;FormName,&amp;nbsp;AncestorClass,
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FileSystem:&amp;nbsp;string;&amp;nbsp;Source,&amp;nbsp;Form:&amp;nbsp;TIStream;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;CreateFlags:&amp;nbsp;TCreateModuleFlags):&amp;nbsp;TIModuleInterface;&amp;nbsp;virtual;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Project/UI&amp;nbsp;information&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;EnumProjectUnits(EnumProc:&amp;nbsp;TProjectEnumProc;&amp;nbsp;Param:&amp;nbsp;Pointer):&amp;nbsp;&amp;nbsp;<br>
Boolean;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Virtual&amp;nbsp;File&amp;nbsp;system&amp;nbsp;interfaces&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;RegisterFileSystem(AVirtualFileSystem:&amp;nbsp;TIVirtualFileSystem):&amp;nbsp;&amp;nbsp;<br>
Boolean;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;UnRegisterFileSystem(const&amp;nbsp;Ident:&amp;nbsp;string):&amp;nbsp;Boolean;&amp;nbsp;virtual;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetFileSystem(const&amp;nbsp;Ident:&amp;nbsp;string):&amp;nbsp;TIVirtualFileSystem;&amp;nbsp;virtual;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Editor&amp;nbsp;Interfaces&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetModuleInterface(const&amp;nbsp;FileName:&amp;nbsp;string):&amp;nbsp;TIModuleInterface;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetFormModuleInterface(const&amp;nbsp;FormName:&amp;nbsp;string):&amp;nbsp;TIModuleInterface;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Menu&amp;nbsp;Interfaces&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetMainMenu:&amp;nbsp;TIMainMenuIntf;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Notification&amp;nbsp;registration&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;AddNotifier(AddInNotifier:&amp;nbsp;TIAddInNotifier):&amp;nbsp;Boolean;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;RemoveNotifier(AddInNotifier:&amp;nbsp;TIAddInNotifier):&amp;nbsp;Boolean;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Pascal&amp;nbsp;string&amp;nbsp;handling&amp;nbsp;functions&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;NewPascalString(Str:&amp;nbsp;PChar):&amp;nbsp;Pointer;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;FreePascalString(var&amp;nbsp;Str:&amp;nbsp;Pointer);&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;ReferencePascalString(var&amp;nbsp;Str:&amp;nbsp;Pointer);&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;&amp;nbsp;<br>
abstract;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;AssignPascalString(var&amp;nbsp;Dest,&amp;nbsp;Src:&amp;nbsp;Pointer);&amp;nbsp;virtual;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;{&amp;nbsp;Configuration&amp;nbsp;Access&amp;nbsp;} &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetBaseRegistryKey:&amp;nbsp;string;&amp;nbsp;virtual;&amp;nbsp;stdcall;&amp;nbsp;abstract;
&amp;nbsp;<br>
end;
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>
对使用者有效的 ToolServices 函数如下(只对32位版本的 Delphi 有效):
</p>
<br><big><big><i><b>动作:</b></i></big></big><br>
<b>CreateModuleEx</b><br>
&amp;nbsp;&amp;nbsp;扩展形式的 CreateModule 方法. 将返回一个 TIModuleInterface 接口.
支持 CreateModule 中使用的所有 CreateModes, 但有一点不同:<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cmExisting: 从指定的文件系统中创建一个已存在的模块.<br>
增加了 AncestorClass 参数, 用于指定基类(必须是工程中已有的,
可以先使用 cmAddToProject 标志将模块加入到工程中).<br><br>
<br><big><big><i><b>信息:</b></i></big></big><br>
<b>EnumProjectUnits</b><br>
&amp;nbsp;&amp;nbsp;对过程中的所有单元调用 EnumProc.<br><br>
<br><big><big><i><b>编辑器:</b></i></big></big><br>
<b>GetModuleInterface</b><br>
&amp;nbsp;&amp;nbsp;返回一个关联到指定文件的模块接口.
这个函数对给定的模块返回相同的接口, 只有计数器作了修正,
用户根据自己的需要使用这个接口, 而且结束时必须调用 release.<br><br>
<b>GetFormModuleInterface</b><br>
&amp;nbsp;&amp;nbsp;返回一个关联到指定窗体的模块接口.<br><br>
<br><big><big><i><b>菜单:</b></i></big></big><br>
<b>GetMainMenu &amp;nbsp;</b><br>
&amp;nbsp;&amp;nbsp;返回 IDE 主菜单的接口. 详细信息参见 TIMainMenuIntf.<br><br>
<br><big><big><i><b>通知(Notification):</b></i></big></big><br>
<b>AddNotifier</b><br>
&amp;nbsp;&amp;nbsp;注册一个 TIAddInNotifier 派生类的实例.<br><br>
<b>RemoveNotifier</b><br>
&amp;nbsp;&amp;nbsp;删除一个已注册的 TIAddInNotifier 派生类的实例.<br><br>
<br><big><big><i><b>配置访问:</b></i></big></big><br>
<b>GetBaseRegistryKey</b><br>
&amp;nbsp;&amp;nbsp;返回 Delphi 基本注册信息主键的完整路径.
这个主键关联到 HKEY_CURRENT_USER.<br><br>
<br><big><big><i><b>虚拟文件系统:</b></i></big></big><br>
&amp;nbsp;&amp;nbsp;RegisterFileSystem 方法和 UnRegisterFileSystem 方法似乎是为将来的版本预留的,
以便实现与端口, 操作系统, 文件系统相关的特性.<br>
(注: 本文写作日期比较老, 大概是在 Delphi 3 时期, 新版本的 Delphi 似乎已经实现了虚拟文件系统)<br><br>
<br><big><big><i><b>Pascal 字符串处理:</b></i></big></big><br>
&amp;nbsp;&amp;nbsp;对于使用非 Pascal 语言(例如 C 或 C++)的程序员, 提供了 Pascal 字符串处理函数.
使用 Delphi 的程序员绝对不需要使用这些函数,
但为了完整起见, 我们还是来看看这些函数:<br><br>
<b>NewPascalString</b><br>
&amp;nbsp;&amp;nbsp;根据指定的PChar(在 C 中是 char*)内容分配并返回一个 Pascal 长字符串.
如果 PChar 中传入 nil 或空字符串, 则返回值将是 nil (等价于 Pascal 的空字符串).<br><br>
<b>FreePascalString</b><br>
&amp;nbsp;&amp;nbsp;通过减少引用计数来释放给定的 Pascal 字符串, 如果引用计数降为0, 释放实际的内存.<br><br>
<b>ReferencePascalString</b><br>
&amp;nbsp;&amp;nbsp;增加给定的 Pascal 字符串的引用记数.
调用这个函数可以人为地延长字符串的生存期.
必须相应地调用 FreePascalString, 以便实际地释放字符串所占用的内存.<br><br>
<b>AssignPascalString</b><br>
&amp;nbsp;&amp;nbsp;将 Pascal 字符串赋值给另一个字符串.
绝对不要直接在 Pascal 字符串之间进行赋值.
这样做会产生孤立内存并导致内存泄露.
目的字符串将引用源字符串,
因此目的字符串的引用记数将减少,
源字符串的引用记数将增加.<br><br>
 
<p align="center"><big><big><big>怎样编写DELPHI向导(五)</big></big></big></p>
<p>5. TFileOpenDialogExpert</p>
<p>通过 TIToolServices 接口我们的确获得了很多信息和能力.
下面我们尝试着做一些简单的事情.
让我能够把任意文件作为新工程打开的 API 似乎就是 OpenProject,
它的唯一参数就是一个完整的文件名.</p>
<p>TFileOpenExpert 的第一个版本的引擎如下:</p>
TFileOpenExpert<br>
&amp;nbsp;&amp;nbsp;GetStyle:&amp;nbsp;esStandard<br>
&amp;nbsp;&amp;nbsp;GetIDString:&amp;nbsp;DrBob.TFileOpenExpert.standard<br>
&amp;nbsp;&amp;nbsp;GetName:&amp;nbsp;FileOpen&amp;nbsp;Wizard<br>
&amp;nbsp;&amp;nbsp;GetAuthor&amp;nbsp;(win32):&amp;nbsp;Bob&amp;nbsp;Swart&amp;nbsp;(aka&amp;nbsp;Dr.Bob)<br>
&amp;nbsp;&amp;nbsp;GetMenuText:&amp;nbsp;&amp;amp;FileOpen&amp;nbsp;Wizard...<br>
&amp;nbsp;&amp;nbsp;GetState:&amp;nbsp;[esEnabled]<br>
&amp;nbsp;&amp;nbsp;GetGlyph:&amp;nbsp;0<br>
&amp;nbsp;&amp;nbsp;GetPage&amp;nbsp;(win32):<br>
&amp;nbsp;&amp;nbsp;GetComment:<br>
<br>
<p>因此, 我们在 Execute 方法中要作的就是如何得到完整的文件名, 然后调用 ToolServices.OpenProject.
最简单的方法大概就是使用 TOpenDialog, 因此 Execute 方法的源代码大致如下:</p>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;TFileOpenExpert.Execute;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;TOpenDialog.Create(nil)&amp;nbsp;do &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if&amp;nbsp;Execute&amp;nbsp;then
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ToolServices.OpenProject(FileName);
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Free &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
end &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{Execute};
&amp;nbsp;<br>
&amp;nbsp;<br>
<p>好, 差不多就是我们想要的了. 我们忘了初始化 TOpenDialog 的 Filter 属性.
另外, 我们打开新工程时, 没有关闭前一个工程中的文件,
因此在调用 OpenProject前还应该调用 SaveProject 和 CloseProject.</p>
<br>
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;TFileOpenExpert.Execute;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;with&amp;nbsp;TOpenDialog.Create(nil)&amp;nbsp;do &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Title&amp;nbsp;:=&amp;nbsp;GetName;&amp;nbsp;{&amp;nbsp;name&amp;nbsp;of&amp;nbsp;Wizard&amp;nbsp;as&amp;nbsp;OpenDialog&amp;nbsp;caption&amp;nbsp;}
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Filter&amp;nbsp;:=&amp;nbsp;'All&amp;nbsp;Files&amp;nbsp;(*.*)|*.*';
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Options&amp;nbsp;:=&amp;nbsp;Options&amp;nbsp;+&amp;nbsp;[ofShowHelp,&amp;nbsp;ofPathMustExist,&amp;nbsp;ofFileMustExist];
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HelpContext&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
if&amp;nbsp;Execute&amp;nbsp;then
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
begin
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ToolServices.SaveProject;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ToolServices.CloseProject;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ToolServices.OpenProject(FileName) &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
end;
&amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Free &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
end &amp;nbsp;<br>
&amp;nbsp;&amp;nbsp;
end&amp;nbsp;{Execute};
&amp;nbsp;<br>
</p>
 
哪为帮忙在这里随便写几句,
我好把它结束掉,
多谢~~
 
我来了
看看
 
是有点老了,等有空我翻译一些ota的
 
好啊,给你0分先
 
I LOVE YOU 李颖
 

Similar threads

后退
顶部