前言
2001-01-18·adding·yesky
在DOS时代,人们不会忘记,想要制作一个应用程序的安装往往是通过批处理文件来实现的,这种风格的安装程序常常令人们乐此不疲。直到UCDOS图形安装界面的出现,才让人感到一些新意,并为之一振。然而不久,具有易学易用的图形用户界面、多任务功能的Windows系统出现了,并大有取代DOS的趋势。直到Windows95的问世,才使得DOS真正变为过去,成为PC机上最流行的操作环境,并且随着Windows98与InternetExplorer集成的新特性的引入,越来越多的程序员已开始致力于Windows应用程序的研究与开发。
同样,安装程序的运行环境也由原来的DOS变成了现在的Windows系统。安装一个软件或应用程序已不再仅仅是将相关的文件复制到硬盘中,而是必须允许用户按自己的愿望选择安装类型和安装路径,并且在不需要的时候,还要能够将安装的相关内容全部删除掉。这种Windows下的安装程序给人们留下了很深的印象,人们在惊叹Office2000强大的安装功能和悦目的安装界面之后,已无法维持对DOS安装程序的留恋。
InstallShield恰恰是在这种操作系统不断发展的潮流中应运而生的,从InstallShield3.0到5.5,从普通的安装程序制作到最新的Windows安装界面,InstallShield公司已开发出基本各种操作平台和软件开发环境的InstallShield产品。InstallShieldfor Microsoft Visual C++6(简称InstallShield VC版)和InstallShield Express CustomEdition for C++ Builder或Delphi(简称InstallShield Express C++ Builder或Delphi版)就是其中用户较为熟悉的产品。
由于InstallShield功能强大、灵活性好、完全可扩展以及具有强有力的网络支持,在各种安装程序开发工具中脱颖而出,成为目前最为流行的制作安装程序的工具软件。而且,它所内建的脚本语言InstallScript使得用户可以像其他高级语言那样灵活地构造出自己的安装脚本程序来。正是因为这一点,InstallShield已经成为目前制作安装程序的工业标准。用户所熟悉的VisualStudio 98、BorlandC++ Builder(Delphi)以及目前绝大多数的软件安装程序均是用InstallShield来制作的。
由于InstallShield5.5还支持VisualBasic 6.0,故本教程以InstallShield5.5专业版为主,并从应用出发,深入详实地讨论制作一般应用类和数据库类安装程序的方法、技巧以及InstallScript语言基础,且在InstallShield用户界面函数的基础上,挖掘其运用能力,最大地发挥InstallShield的定制和扩展潜能,构造出颇具创意、功能完善的安装界面来。
本教程主要讲述InstallShield开发环境、InstallScript脚本语言基础、基本安装程序的建立、安装界面的设计以及深入安装程序制作等共五章内容。各章内容并不停留在初学者的水平上,而且在制作安装程序的每个方面,都给出了更高、更深层次的方法,例如安装对话框的定制、使用自己的DLL库、操作注册表、安装界面的汉化、使用多媒体、反安装以及安装程序的调试等。
为了帮助读者充分掌握InstallShield特性,本书给出大量有用的实例,这些实例均以[Ex_xxxx]命名,并在Windows98、InstallShield5.5专业版本调试通过。
由于在软件开发环境和操作系统未来发展的几年里,Windows98/2000以及VC++、C++ Builder、VB等还仍将是主流。在这种契机下,适时地将InstallShield5.5的使用方法和技巧奉献给大家,必将对广大的程序员、软件开发者和爱好者有所帮助。
由于时间仓促,加之作者水平有限,不当之处在所难免,恳请读者批评指正。
感谢天极网及赵家雄、方舟先生,没有他们此教程不可能在网上出版。感谢一直关心和支持此项工作的家人和朋友们,尤其是我的妻子。
集成开发环境概述
2001-01-18· adding ·yesky
在Windows95/98/NT操作系统中正确安装了InstallShield5.5专业版后,就可以单击任务栏的"开始",选择"程序"中的"InstallShield5.5 Professional Edition",再选择该程序文件夹下的"InstallShield 5.5 ProfessionalEdition"就能运行InstallShield。第一次运行时,弹出如图1.1所示的界面。
但当利用ProjectWizard(项目向导)或其他工具创建一个安装项目后,就会出现InstallShield5.5的完整界面,如图1.2所示。
它是由标题栏、菜单栏、工具栏、项目工作区窗口、文档窗口、输出窗口以及状态栏等组成的。
标题栏是用来显示出当前窗口中的文件名,而且一般还有[最小化]、[最大化]或[还原]以及[关闭]按钮,单击[关闭]按钮将退出集成开发环境。
菜单栏包含了集成开发环境中几乎所有的命令,它为用户提供了文档操作、安装脚本程序的编译、调试、窗口操作等一系列的功能。由于工具栏比菜单操作更为便捷,故常常将一些常用菜单命令也同时安排在工具栏上。
项目工作区窗口包含用户安装项目的一些信息,包括文件组、组件、脚本文件、资源等。在项目工作区窗口中的目录项或图标处单击鼠标右键,有时还会弹出相应的快捷菜单,它包含当前状态下的一些常用操作。
文档窗口位于集成开发环境中的右边,脚本文件、资源文件以及安装程序所需要的各种资源等都可以通过该窗口显示出来。
输出窗口出现在集成开发环境窗口的底部,它包含了Build和Compile两个页面,分别用来显示建立和编译过程中的相关信息。
状态栏位于集成开发环境的最底部,它用来显示当前操作状态、说明、文本光标所在的行列号等信息。
菜单栏和工具
2001-01-17· adding·yesky
1.2.1菜单栏
在集成开发环境界面中,用户可以看到在它的上方排列着一系列的菜单,而每一个菜单下都有各自的菜单命令。在进一步与集成开发环境打交道之前,先了解各项菜单命令的基本功能是很有必要的,因为大部分的操作都是通过菜单来完成的。
InstallShield 5.5的菜单栏中包含了File(文件)、Edit(编辑)、View(查看)、Insert(插入)、Project(项目)、Build(编译)、Tools(工具)、Windows(窗口)以及Help(帮助)等菜单。其中File、Edit、View、Windows和Help均与一般Windows应用程序的菜单用法相同。这里仅对Insert、Project、Build和Tools菜单作简单说明。
Insert菜单
Insert菜单中的命令主要用于项目及资源的创建和添加,它有三个菜单项:File into Script Files...、File into Setup Files...和Links into File Groups...,分别表示将某个文件插入脚本文件和安装文件中以及链接到文件组中。
一般情况,这三个菜单项是被禁用的。当切换到项目工作区窗口的"Scripts"页面并选定其中的脚本文件目录项时,菜单项"File into Scripts Files"被激活;当切换到项目工作区窗口的"Setup Files"页面并选定其中的目录项时,菜单项"Files into Setup Files"被激活;而当切换到项目工作区窗口的"File Groups"页面并选中其中的"Links"目录项时,菜单项"Links into File Groups"被激活。
Project菜单
Project菜单中的命令主要用于项目的创建和相关内容的设置,它有三个菜单项:Project Wizard…、Visual Basic Project Wizard…和Setting…,分别用来创建一般安装项目、VB应用程序安装项目以及项目相关内容的设置。
Build菜单
Build菜单中的命令主要用来进行安装程序的编译、连接、调试、运行等操作,它包括这样的菜单命令:Compile(编译)、Run Setup(运行)、Debug Setup(调试)、Media(媒介)、Settings...( 设置调试和编译时的参数)。
Tools菜单
Tools菜单中的命令主要是一些用于运行或定制开发环境中的实用工具,如图1.3所示。
值得一提的是,随着集成开发环境当前状态的改变,有些菜单中的菜单命令项还会随之变化。例如,当文档窗口没有任何脚本程序时,许多菜单项都是灰色的,用户不能使用它们。此外,InstallShiled 5.5与其他Windows应用程序一样,其菜单系统一般都遵循下列一些相同的规则:
(1) 打开InstallShiled 5.5的"File"菜单,会看到"Open"菜单项文本后有"…",若选择该菜单命令,则弹出通用文件"打开"对话框。因此,菜单文本后有"…"就表示其执行结果是将弹出相应的对话框。
(2) 在"File"菜单文本中,其中"F"字母带下划线。它表示该菜单项的助记符是"F",当按住"Alt"键不放,再敲击该字母时,对应的菜单项就会被选中。
(3) 在"Open"菜单文本后有"Ctrl+O"字样,任何时候,先按下"Ctrl"健不放,然后再按"O"键就执行"Open"菜单项命令,弹出通用文件"打开"对话框。这表明"Ctrl+O"和该菜单项命令是一致的,"Ctrl+O"称为该菜单项的快捷键。
1.2.2 工具栏
尽管菜单命令可以完成各种操作,其相应的快捷键也可提高操作的效率。但是,菜单命令的操作相对繁琐,快捷键又需要用户加以记忆,所以,有时候用起来还略嫌不便。而工具栏是一种图形化的操作界面,具有直观和快捷的特点,熟练掌握工具栏的使用后,工作效率将大有提高。
工具栏是一系列工具按钮的组合。当鼠标指针停留在工具栏按钮的上面时,按钮凸起,主窗口底端的状态栏上显示出该按钮的一些提示信息,并且如果指针停留时间长一些,就会出现一个小的弹出式的"工具提示"窗口,显示出按钮的名称。工具栏上的按钮通常和一些菜单命令相对应,提供了一种执行经常使用的命令的快捷方法。
同菜单中的菜单命令项相似,当菜单命令项禁止使用时,相应的工具按钮也是灰色的,用户不能使用它们。
InstallShield 5.5的工具栏如图1.4所示。
1.3.1 Scripts页面
项目工作区窗口的Scripts页面用来管理安装程序的脚本文件,在该页面中各项脚本文件均以树状列表的型式显示出来的。每个目录项前都有一个图标,且顶层目录项前还有一个套在方框中的符号"+"。双击顶层目录项或单击最前面的"+",则直接打开并显示该目录项的所有子项,此时顶层目录项前的"+"变成"-"号;再双击顶层目录项或单击最前面的"-",则该项目的所有子项被收缩,只显示顶层目录项内容,此时顶层项目前的"-"又变成了原来的"+"号。
展开顶层目录项的所有子项,双击以.rul为扩展名的脚本文件项,则在开发环境的右边的文档窗口中显示出该脚本文件的内容。为了增强安装程序代码的可读性,脚本文件的源代码内容往往是以不同颜色来显示的,各种颜色所代表的含义如下所示:
白底黑字 一般文本
黑底白字 被选定的文本
青色底黑色字 文本的行标记
白底红字 InstallShield的函数
白底蓝字 InstallScript脚本语言的关键字
白色底品红色字 常数
白色底紫红色字 用""符号括起来的文本内容
白底绿字 注释
1.3.2Components页面
项目工作区窗口的Components页面用来管理安装程序的各项组件。缺省时,一个安装项目通常有程序文件(Program Files)、示例文件(Example Files)、帮助文件(Help Files)以及共享的DLL文件(Shared DLLs)共四个组件。双击某个组件目录项,则在主界面的右边窗口中显示出该组件相关属性的完整列表,这些属性都可以方便地进行相应的修改。
1.3.3 SetupTypes页面
项目工作区窗口的Setup Types页面用来管理提供给用户的安装类型。缺省时,一个安装项目通常有Typical(典型)、 Compact(紧凑)和Custom(定制)共三种安装类型。双击某种安装类型,则在主界面的右边窗口中显示出该安装类型相关的组件。
在组件中,凡是文件组前面有一个带钩号(√)的图标,表示该文件组已被选入相应的安装类型中。反复双击文件组前面的图标可在"选入"和"不选"之间进行切换。
1.3.4 SetupFiles页面
项目工作区窗口的Setup Files页面用来管理在安装过程中所需要的安装文件,它通常有含有下面一些内容。
(1) Splash Screen(启动画面)
InstallShield用Setup.bmp作为安装程序的启动画面。若在不同的语系(中文、English)中放置各自的位图文件,则安装程序将根据安装环境的不同语系选用相应的Setup.bmp;若将该文件放置在Language Independent(与语系无关)目录项中,则不管操作系统是何种语系,都将以此位图文件作为程序安装的启动画面。
(2) Language Independent(与语系无关)
它允许用户为各种操作系统或专门为Windows 95/98/NT操作系统指定相应的安装文件,这样不管怎样的语系,安装程序都会根据相应的操作系统来拣选相应的文件。(3) (3)其他语系相关的文件
它允许用户为各种操作系统或专门为Windows 95/98/NT操作系统指定相应的安装文件,这样安装程序会根据相应的语系和语系下的操作系统来拣选相应的文件。
(4) Advanced Files(高级文件)
在用具体的媒介发布时,允许用户在相应的媒介中放置一些非压缩文件。
1.3.5 FileGroups页面
项目工作区窗口的File Groups页面用来管理安装项目所需要的文件组。缺省时,安装程序项目通常有Example Files(示例文件组)、Help Files(帮助文件组)、
Program DLLs(应用程序所需的DLL文件组)、Program Executable Files(应用程序文件组)以及Shared DLLs(共享DLL文件组)共五个文件组。
双击某个文件组,则在主界面的右边窗口中显示出该文件组的相关属性,用户可以方便地进行修改。
1.3.6 Resources页面
项目工作区窗口的Resources页面用来管理安装项目所需要的安装资源。缺省时,一个安装项目通常有String Table(字符串表)、Registry Entries(注册项)和Shell Objects(外壳对象)共三种资源,其中Shell Objects资源是在Windows 95/98和Windows NT 4.0及其以后操作系统中创建被安装应用程序的程序文件夹(Folder命令)、桌面图标或相应的快捷方式(Shortcut命令)。
1.3.7 Media页面
项目工作区窗口的Media页面用来管理程序发布时的媒介。在该页面中包含Media Build Wizard(媒介创建向导)、缺省的媒介以及用户新创建的媒介等项,单击"Media Build Wizard"将开始媒介创建向导,用来创建新的媒介。
需要说明的是:在各个页面中,右击鼠标时都会弹出相应的快捷菜单,它包含当前状态下的一些常用操作。
集成开发环境的初步实践
2001-01-18· adding·yesky
前面介绍了关于集成开发环境的一些基本情况,这里以空类型的安装项目为例,进一步说明集成开发环境的使用过程。
1.4.1 创建一个空的安装项目
在InstallShield 5.5中,利用Project Wizard(安装项目向导)和安装项目模板可以创建Windows应用程序、数据库应用程序以及其他类型程序的安装项目。这里,我们首先对空类型的安装项目作简单说明,其他安装项目类型将在以后的章节中陆续介绍。
一个空类型的安装项目包含了一般安装项目的基本框架,只是安装脚本文件中没有相应的安装程序代码,因而不执行任何操作。创建一个空类型的安装项目的最大好处是可以帮助用户熟悉和掌握InstallScript语言的用法,并由此编制出简繁随意的安装程序来。
在InstallShield 5.5中,想要创建一个空类型的安装项目,只需选择"File"菜单->"New"菜单命令,在"New"对话框中选定"Blank Setup",并单击[确定]按钮即可,如图1.5所示。
此时,InstallShield 5.5自动为该安装项目命名为"Blank Setup",并定位到项目工作区窗口的Scripts页面,而且还在集成开发环境的右边窗口中打开相应的脚本文件。
1.4.2 添加代码
在空类型安装项目的脚本文件中,一开始是没有相应的安装程序内容的,它需要用户添加一些代码,例如:
...
program // 每个安装脚本程序都是以program开始
SprintfBox(INFORMATION,"问候","%s", "您好!" ); // 消息对话框
endprogram // 每个安装脚本程序都是以endprogram结束
1.4.3 编译并运行
打开Build菜单,选择Compile菜单项或按快捷键Ctrl+F7,系统开始对"Blank Setup"进行编译,同时在输出窗口中在线地显示出编译过程的情况,当出现
Done - 0 error(s), 0warning(s)
字样时,表示"Blank Setup"安装程序可以被运行了。
在"Build"菜单中选取"Run Setup"菜单命令或按快捷键Ctrl+F5,就可以运行"Blank Setup"安装项目。
运行刚开始,出现"Setup"对话框,用来显示准备安装向导的进展情况,如图1.6。
然后才执行前面添加的程序代码,其结果如图1.7所示。
本章着重介绍了InstallShield5.5的集成开发环境,并以空类型的安装项目为例简单地说明了安装脚本程序的添加、编译、运行的过程。下一章将讨论InstallScript脚本语言的基础内容。
第 2 章 InstallScript脚本语言基础
2001-01-19· adding·yesky
InstallScript是专门用来编写InstallShield安装程序的脚本语言。由于InstallScript和C语言极为相似,因而使得Visual C++用户编写安装脚本程序颇为得心应手。即使对于没有任何语言基础的用户来说,编写InstallScript程序也不会觉得无从下手,因为InstallScript程序结构是非常简单的。并且,InstallScript为用户提供了超过250个的内部函数,从而使得用户不需要太多的代码就能编写出具有专业水准的安装程序来。
2.1 InstallScript程序结构
同其他程序设计语言一样,InstallScript脚本语言也有自己的程序结构。
2.1.1 几个InstallScript程序
下面先来看看几个比较简单的InstallScript程序。
[例Ex_Hello] 一个简单的InstallScript程序,用来弹出"问候"对话框。
STRING szTitle;
program
szTitle = "问候";
SetDialogTitle(DLG_MSG_INFORMATION, szTitle);
MessageBox("您好!", INFORMATION );
endprogram
程序中,program...endprogram构成主程序体,每一个InstallScript程序中都必须包含一个且只有一个这样的主程序体。在主程序体外,只能是变量定义、用户函数定义以及预处理指令等,而程序体内可以包括若干条语句,每一条语句都由分号";"结束。本例中,SetDialogTitle和MessageBox都是InstallScript的内部函数,它们分别用来设置对话框的标题和显示指定的信息文本,INFORMATION是一个系统预定义的常量,szTitle变量是在程序体外定义的字符串变量。
[例Ex_Func] 自已定义一个函数,用来显示消息对话框。
STRING szTitle; // 定义一个字符串变量
prototype MyMessage(STRING,STRING); // 自定义函数的声明
program
szTitle = "问候";
MyMessage(szTitle, "您好!");
endprogram
function MyMessage(szTitle,szMessage) /* MyMessage函数体 */
begin
SetDialogTitle(DLG_MSG_INFORMATION, szTitle);
MessageBox(szMessage,INFORMATION );
end;
尽管本例的结果和Ex_Hello示例相同,但它使用了自定义函数MyMessage。InstallScript语言规定,一个自定义函数名必须在program关键字前面声明,而函数体代码的实现代码必须在endprogram后进行,且每个自定义的函数体都必须以begin开始end结束(注意end后要有分号";")。程序中的"/*...*/"之间的内容或"//"开始一直到行尾的内容是用来注释的,它的目的只是为了提高程序的可读性,对编译和运行并不起作用。正是因为这一点,注释的内容可以用汉字来表示,也可以用英文来说明,只要便于理解就行。
[例Ex_Include] 使用包含文件。
#include"Sddialog.h";
STRING szTitle, szMsg,svDir;
program
szTitle ="SdAskDestPath Example";
svDir ="C:\\EXAMPLE\\TARGET";
szMsg = "";
// 获取用户指定的安装路径
if(SdAskDestPath(szTitle, szMsg, svDir, 0) = NEXT) then
TARGETDIR = svDir;
endif;
// 显示用户指定的安装路径
SprintfBox(INFORMATION,"SdAskDestPath", "Successful.\n\nThe Target " +
"directory is:" + TARGETDIR);
endprogram
#include"Sddialog.rul"
该程序是使用Sd(Script Dialog,脚本对话框)对话框函数的一个示例。InstallScript语言规定,在调用Sd对话框函数时,需要在program前加上#include "Sddialog.h"语句,而在endprogram后加#include "Sddialog.rul"。与C语言相似,#include "Sddialog.h"和#include "Sddialog.rul"是InstallScript的编译指令,称为预处理指令。InstallScript编译系统会根据预处理指令#include中的文件名,把该文件的内容包含进来。也就是说,实际程序的代码长度是在原来长度的基础上增加了Sddialog.h和Sddialog.rul文件的长度。程序中,SprintfBox参数内容中的"\n"是换行符,即在"Successful."文本后回车换行。
2.1.2InstallScript程序的基本组成
从上面的几个示例可以看出,一个InstallScript程序往往由预处理命令、函数、语句、变量以及注释等几个基本部分组成的。
(1) 预处理命令
在InstallScript程序的一开始经常出现含有以"#"开头的命令,它们是预处理命令。InstallScript提供了三类预处理命令:宏定义命令、文件包含命令和条件编译命令。
(2) 函数
一个InstallScript程序是由若干个函数组成的。这些函数中,有的是InstallScript系统中所提供的内部函数,有的是用户根据自己需要自己编制设计的函数(如例Ex_Func中的MyMessage)。
(3) 语句
语句是组成程序的基本单元,它可以是用来判断的条件语句,也可以是用来反复运行的循环语句等。这些语句是组成InstallScript程序中的最重要部分之一。
(4) 变量
大多数程序离不开变量。InstallScript变量的类型比较简单,主要有数值型(NUMBER)、字符串型(STRING)以及链表型(LIST)等,例如例Ex_Hello中的szTitle是一个STRING型变量。
(5) 注释
程序的目的不仅在于实现某种功能、解决某个问题,而且还在于数据结构和算法的交流。因此在程序中添加必要的注释是非常重要的,它能提高程序的可读性,帮助用户对程序的理解。
需要说明的是,InstallScript不支持控制台的输入和输出,数据的输入和输出是通过对话框进行的。
2.1.3InstallScript程序的书写风格
尽管InstallScript语言比C或C++语言容易理解,但对于初学者来说,一开始就养成良好的编程习惯仍然是非常重要和必要的。
1. 标识符命名
标识符是用来标识变量名、函数名、结构名、文件名等的有效字符序列。标识符命名的好坏直接影响程序的可读性,例如a1b1、c1d虽然是合法的标识符,但却是不好的标识符,因为它不能让人理解它们所代表的含义。下面几个原则是命名时所必须注意的:
(1) 合法性
InstallScript规定标识符由大小写字母、数字字符(0―9)和下划线组成,且第一个字符必须为字母或下划线。任何标识符中都不能有空格、标点符号及其他字符,例如下面的标识符是不合法的:
93Salary,Youhe.Ding,$178,#5f68,r
注意,InstallScript中标识符的大小写是有区别的。例如,data、Data、DaTa、DATA等都是不同的标识符。
用户定义的标识符不能和系统的关键字同名。以下是43个InstallScript关键字:
abort begin BOOL BYREF
case CHAR default downto
else end elseif endfor
endif endprogram endswitch endwhile
exit for function GDI
goto HWND if INT
KERNEL LIST LONG NUMBER
POINTER program prototype repeat
return SHORT step STRING
switch then to typedef
until USER while
需要注意的是,用户定义的标识符还不能和InstallShield的函数名、系统变量名以及预定义的常量名相同。
(2) 有效性
虽然,标识符的长度(组成标识符的字符个数)是任意的,但最好不能超过32个,因为InstallShield的编译系统只能识别前32个字符,也就是说前32个字符相同的两个不同标识符被有的系统认为是同一个标识符。
(3) 易读性
在定义标识符时,若能做到"见名知意"就可以达到易读性的目的。为了达到这个目的,许多Visual Basic、Visual C++及Delphi等程序员广泛使用匈牙利的命名规则来定义标识符,InstallScript也使用这个<
命名规则。
匈牙利的命名规则是将标识符的类型(小写)来作为标识符的前缀。例如前面的szTitle表示一个字符串变量,其中的sz表示STRING变量类型。表2.1列出了常用变量的前缀。除此之外,对于函数名的命名往往使用多个单词来组成,每个单词的第一字母都是大写,例如前面的SdAskDestPath函数名。
2.缩进和注释
缩进是指程序在书写时不要将程序的每一行都由第一列开始,而且在适当的地方加进一些空行或空格。它同注释一样,也是为了提高程序的可读性。
注释的重要性已在前面论及过,这里不再重复。但要注意的是:
(1) 注释应在编程的过程中同时进行,不要指望程序开发完成后再补写注释。那样只会多花好几倍的时间,更为严重的是,时间长了以后甚至会读不懂自己写的程序。 必要的注释内容应包含:脚本程序的总体注释(文件名、作用、创建时间、版本、作者及引用的手册、运行环境等)、函数注释(目的、算法、使用的参数和返回值的含义、对环境的一些假设等)及其他的少量注释。千万不要陈述那些一目了然的内容,否则会使注释的效果适得其反』些空行或空格。它同注释一样,也是为了提高程序的可读性。
注释的重要性已在前面论及过,这里不再重复。
2.2 数据类型
程序可以看成是由数据结构和算法组成的。数据结构体现对数据的描述,而算法反映了对数据的操作及处理。任何一门计算机语言都必须包括数据类型、运算符与表达式等内容来定义和实现程序中的数据结构和算法。
2.2.1 基本数据类型
InstallScript的数据类型比其他任何高级语言的数据类型要简单易用,它只有基本类型和结构类型两类。这里先讨论InstallScript的基本数据类型。
基本数据类型是InstallScript的内部数据类型,包括CHAR(字符型)、NUMBER(数值整型)等,表2.2列出各种基本数据的类型。
需要说明的是:在InstallScript的数据类型中,除了BOOL、HWND及LIST类型不能使用小写外,其余的数据类型还有其小写形式,例如int、number、string等,用来提供一种方便。但是,InstallScript没有无符号数值类型以及浮点数值类型。
2.2.2 常量与变量
根据程序中数据的可变性,数据可以分为常量和变量两大类。
1. 常量
在程序运行过程中,其值不能被改变的量称为常量。常量可分为不同的类型,如1、20、0、-6为整型常量,‘a’、‘b’为字符常量。常量一般从其字面形式即可判别。
InstallScript的常量有整型常量、字符常量和字符串常量等类型。这些常量的含义和C语言基本一致,故这里不再重复。
需要说明的是,在InstallScript中还可以用一个标识符表示一个常量。
[例Ex_Define] 用#define定义符号常量。
#define TITLE "问候"
program
SprintfBox(INFORMATION,TITLE,"%s","您好!");
endprogram
程序中用#define命令行定义TITLE,使其代表字符串常量"问候",此后凡是在程序中出现的TITLE都代表"问候"。
这种代替常量本身的标识符称为符号常量。在程序中使用符号常量不仅可以提高程序的可读性(标识符总比常量本身更具意义),而且修改也极为方便。
2. 变量
变量是指在程序执行中其值可以改变的量。变量的作用是存储程序中需要处理的数据,它可以放在程序中的任何位置上。但无论如何,在使用一个变量前必须先定义这个变量。
变量是用下面的格式语句进行定义的:
类型 变量名表;
例如:
NUMBER nNum1;
NUMBER nNum2;
NUMBER nNum3;
BOOL bValidEntry;
其中,nNum1、nNum2、nNum3被定义成整型变量,而bValidEntry被定义成布尔型变量。有时,还可以将同类型的变量定义在一行语句中,不过变量名要用逗号(,)分隔。例如上面的变量可这样定义:
NUMBER nNum1, nNum2, nNum3;
BOOL bValidEntry;
在定义字符串常量时,可以指定字符串的长度,例如:
STRING szUserName[128]; // 指定字符串的长度为128个字符
若不指定其长度,则InstallScript自动指定。16位操作系统中,字符串的长度被指定为512个字符,而32位操作系统中,字符串的长度被指定为1024个字符。
在定义变量时,需要注意:
(1) 不能在主程序体(program...endprogram之间)或函数体内部(begin...end之间)定义变量,变量必须定义在程序体外或函数名与begin关键字之间。例如:
function SdAskDestPath(szTitle, szMsg,svDir, nStyle)
STRING szDlg, svDirLoc, szTemp;
INT nId, nTemp;
HWND hwndDlg;
BOOL bDone;
begin
...
end;
(2) 在同一个主程序或同一个函数体中不能有同时出现两个相同的变量名。
(3) 不能在变量定义的同时,给变量赋初值。
2.2.3 InstallScript运算符简介
和其他的程序设计语言一样,InstallScript记述运算的符号称为运算符,运算符的运算对象称为操作数。一个操作数可以是变量、常量或是具体的数值等。对一个操作数运算的运算符称为单目运算符,如-a;对二个操作数运算的运算符称为双目运算符,如3+5等。
InstallScript的运算符分为以下几类:
算术运算符 ( +, -, *, /)
关系运算符 ( <, >, =, <=, >=, != )
逻辑运算符 ( &&, ||, ! )
位运算符 ( &, |, ~, ^, <<, >>)
赋值运算符 ( = )
指针运算符 ( *, & )
分量运算符 ( ., -> )
下标运算符 ( [ ] )
字符串运算符 ( ^, +, % )
其它 ( 如BYREF运算符 )
2.2.4 算术运算符
算术运算符包括常用的加减乘除四则运算符以及单目正负运算符,如下所示:
+ (正号运算符,如+4等)
- (负号运算符,如-4等)
* (乘法运算符,如6*8等)
/ (除法运算符,如6/8等)
+ (加法运算符,如6+8等)
- (减法运算符,如6-8等)
InstallScript中算术运算符和数学运算的概念及运算方法是一致的,但要注意以下几点:
(1) 除法运算
两个整数相除,结果为整数,如7/5的结果为1,它是将小数部分去掉,而不是四舍五入。但InstallScript不支持浮点运算。
(2) 优先级和结合性
在一个包含多种算术运算的混合运算中,先乘除后加减的运算规则是由运算符的优先级来保证的。InstallScript将表达式求值中多种运算之间的先后关系(即运算符之间的优先关系)用运算符的优先级表示。在算术运算符中,单目运算符的优先级最高,其次是乘、除,最后是加减。
优先级相同的运算符,则按它们的结合性进行处理。所谓运算符的结合性是指运算符和操作数的结合方式,它有"从左至右"和"从右至左"两种。"从左至右的结合"又称"左结合",是指运算符左边的操作数先与运算符相结合,再与运算符右边的操作数进行运算,如3*5/4的次序是先乘后除;而自右至左的"右结合"的次序刚好相反,它是将运算符右边的操作数先与运算符相结合,如-i+6相当于(-i)+ 6。
在算术运算符中,除单目运算符外,其余运算符的结合性都是从左至右的。
(3) 关于书写格式
在使用运算符进行数值运算时,若书写时没有在双目运算符两边加上空格,则有时编译系统会做出与自己想象中不同的理解。例如:
-5*-6-7
和
-5 * -6 - -7 // 注意空格
结果是不一样,前者发生编译错误,而后果的结果是37。
为了避免上述情况的发生,在书写时,有时应有意识地加上一些括号。这样不仅增强程序的可读性,而且,尤其当对优先关系犹豫时,加上括号是保证正确结果的最好方法。
2.2.5 赋值运算符和赋值表达式
在InstallScript脚本语言中,赋值符"="是一个双目运算符,结合性从右至左,其作用是将赋值符右边操作数的值赋给左边的操作数。每一个合法的表达式在求值后都有一个确定的值和类型。赋值表达式的值是赋值符右边操作数的值,赋值表达式的类型是赋值符右边操作数的类型。例如下面语句:
STRING szName;
LONG nValue;
BOOL bDone;
HWND hInstance;
INT iStyle;
LIST LISTINFO;
program
szName = "InstallShield";
nValue = 15;
bDone = FALSE;
hInstance = 0;
iStyle =DLG_MSG_STANDARD|DLG_CENTERED;
LISTINFO = ListCreate(STRINGLIST);
...
但是,InstallScript不支持多重赋值运算,例如a = b = c 相当于C++的a = b ==c。也就是说,若 b 不等于c,表达式为a=0,若b和c相等,则表达式为a=1。
InstallScript往往利用逻辑运算后的结果对程序进行判断、选取等控制。
2.3 逻辑运算和判断选取控制
2.3.1 关系运算符
关系运算是逻辑运算中比较简单的一种。所谓"关系运算"实际上是比较两个操作数是否符合给定的条件。若符合条件,则关系表达式的值为"真",否则为"假"。在InstallScript编译系统中,往往将"真"表示为TRUE,将"假"表示为FALSE。而任何不为0的数被认为是"真",0被认为是"假"。
由于关系运算需要两个操作数,所以关系运算符都是双目运算符。InstallScript提供了下列6种关系运算符:
<(小于),<=(小于等于),>(大于),>=(大于等于),= (相等于),!=(不等于)
其中,前4种的优先级相同且高于后面的两种,但关系运算符的优先级低于算术运算符。
需要说明的是:
(1)InstallScript赋值运算符和等于的关系运算符使用同一个"="符号。
(2)InstallScript不支持赋值和关系运算同在一个表达式中的情形。例如,下面的语句是不允许的:
if ((listID= ListCreate (NUMBERLIST)) = LIST_NULL)
then
. . .
endif;
2.3.2 逻辑运算符
逻辑运算符是用于将多个关系表达式或逻辑量("真"或"假")组成一个逻辑表达式。InstallScript提供了下列3种逻辑运算符:
! 逻辑非(单目)
&& 逻辑与(双目)
|| 逻辑或(双目)
"逻辑非"是指将"真"变"假","假"变"真"。
"逻辑与"是指当两个操作数都是"真"时,结果才为"真",否则为"假"。
"逻辑或"是指当两个操作数中有一个是"真"时,结果就为"真",而只有当它们都为"假"时,结果才为"假"。
"逻辑非"、"逻辑与"和"逻辑或"的优先级依次从高到低,且"逻辑非"的优先级还比关系运算符高,而"逻辑与"和"逻辑或"的优先级却比关系运算符低。
和C不一样,InstallScript对逻辑表达式的值非常敏感,例如下面代码:
if (iVar =10) && (MyFunction( ) = 0)
then
MessageBox("Thatis so true.", INFORMATION);
endif;
只有当&&运算符左边的结果为TRUE时,右边的函数MyFunction才会被执行。为了不引起误解,最好将上述代码改写成:
if (iVar =10) then
if(MyFunction( ) = 0) then
MessageBox("Thatis so true.", INFORMATION);
endif;
endif;
2.3.3 if语句
if语句是用来判定所给定的条件是否满足,并根据判定的结果("真"或"假")决定执行给出的两种操作之一。
InstallScript提供了下列5种形式的if语句。
(1) if-then结构
if-then结构具有下列形式:
if (条件表达式) then
语句
endif;
当"条件表达式"表达为"真"时,then后面的语句才会被执行。一个"条件表达式"可以是一个布尔或整型常量、变量、产生布尔或整型结果的表达式以及能返回整型结果的函数。
例如:
if(szStringA = "exit") then
AskYesNo( "Are you sure you want to exit?" , NO );
endif;
当字符串szStringA和"exit"相等时,函数AskYesNo才会被执行,否则跳过if-then结构,执行后面的语句。
条件表达式两边的圆括号"()"是可选的,但最好能使用,因为它能提高程序代码的可读性。(2) if-then-else结构
if-then-else结构具有下列形式:
if (条件表达式) then
语句1
else
语句2
endif;
当"条件表达式"表达为"真"时,执行then后面的语句1,而当"条件表达式"表达为"假"时,执行语句2。例如:
ifszStringA = "exit" then
AskYesNo("Are you sure you want to exit?" , NO );
//szStringA等于"exit"时
else
MessageBox("Please wait... ", INFORMATION ); // szStringA不等于"exit"时
endif;
(3) if-then-else的嵌套结构
在if-then-else语句中以包含一个或多个if-then-else语句称为if-then-else语句的嵌套。其一般形式如下:
if (条件表达式1) then
if (条件表达式2) then
语句1 //当条件表达式2为TRUE时执行
else
语句2 //当条件表达式2为FALSE时执行
endif;
else
if (条件表达式3) then
语句3 //当条件表达式3为TRUE时执行
else
语句4 //当条件表达式3为FALSE时执行
endif;
endif;
例如:
ifszStringA = "exit" then
AskYesNo("Are you sure you want to exit?" , NO );
else
ifszStringA = "continue" then
MessageBox("Please wait...", INFORMATION );
else
UserErrorHandler;
endif;
endif;
当字符串szStringA和"exit"相等时,执行函数AskYesNo;当szStringA和"continue"相等时,执行MessageBox,而当szStringA等于其他值时,用户自定义的UserErrorHandler函数被执行。
(4) elseif结构
elseif结构具有下列形式:
if (条件表达式1) then
语句1
elseif (条件表达式2) then
语句2
elseif (条件表达式3) then
语句3
...
endif;
例如:
ifszStringA = "exit" then
AskYesNo("Are you sure you want to exit?" , NO );
elseifszStringA = "continue" then
MessageBox("Please wait...", INFORMATION );
elseifszStringA = "reboot" then
gotoStartHere;
endif;
...
StartHere:
...
代码中,StartHere是一个语句标号。当字符串szStringA和"exit"相等时,执行函数AskYesNo;若不相时等,则将szStringA和"continue"比较,相等时执行函数MessageBox;若不相等,再将szStringA和"reboot"比较,...。
(5) if 和goto结构
if和goto的结构具有下列形式:
if (条件表达式) goto 标号;
当条件表达式为"真"时,将流程转到"标号"所在的位置。这种形式最简单,例如:
Name:
AskText("Companyname:", "", szSrc);
if (szSrc= "") goto Name;
一旦szSrc为空字符串时,就不停地要求用户输入相关内容。
2.3.4 switch...endswitch语句
当程序有多个条件判断时,若使用if语句则可能使嵌套太多,降低了程序的可读性。开关语句switch能很好地解决这个问题,它具有下列形式:
switch ( 表达式 )
case 常量1 :语句1
case 常量2 :语句2
...
case 常量n :语句n
default :语句n+1
endswitch;
当表达式的值与case中某个值相等时,就执行该case中":"号后面的所有语句。若case中所有的值都不等于表达式的值,则执行default:后面的语句,若default不存在,则跳出switch结构。
这里的表达式可以是一个常量、变量、算术表达式、逻辑表达式或一个有返回值的函数,但必须用圆括号"()"括起来。case后面只能是一个常数或常量名,不能为变量名、有返回值的函数名、字符串表涉及的字符串名以及其他类型的表达式等。
例如:
STRINGszMsg, svResult;
NUMBERnvResult;
program
GetSystemInfo(VIDEO,nvResult, svResult); // 获得系统显卡类型
switch(nvResult)
caseIS_UNKNOWN: szMsg = "用户显卡类型未知";
caseIS_EGA : szMsg = "EGA显卡";
caseIS_VGA : szMsg = "VGA显卡";
caseIS_SVGA : szMsg = "Super VGA (800 x 600) 显卡";
caseIS_XVGA : szMsg = "XVGA (1024 x 768) 显卡";
caseIS_UVGA : szMsg = "分辨率大于1024 x 768的显卡";
default: szMsg = "错误";
endswitch;
MessageBox(szMsg,INFORMATION);
endprogram
每次只有一个case语句块被执行,执行后,将跳出switch结构,执行endswitch后面的语句,这一点与C语言不同,InstallScrip的case语句后不需要break。
2.4 循环语句
在InstallScript语言中,可以用以下几种形式的语句来实现循环:
(1) 用goto语句和if语句构成循环
(2) 用while..endwhile语句
(3) 用repeat..until语句
(4) 用for..endfor语句
2.4.1 用goto语句和if语句构成循环
goto语句为无条件转向语句,它的一般形式为:
goto 语句标号;
语句标号用标识符表示,它的命名规则与变量名相同,不能用整数来作为标号。结构化程序设计方法主张限制使用goto语句,因为滥用goto语句将使程序流程无规律、可读性差。但也不是绝对禁止使用goto语句。一般来说,可以有两种用途:一是从循环体中跳到循环体外,另一是与if语句一起构成循环结构。
例如:
Name:
AskText("Companyname:", "", szSrc);
if (szSrc ="") then
MessageBox("Pleaseenter the company name.", SEVERE);
goto Name;
endif;
2.4.2 while..endwhile语句
while..endwhile循环语句具有下列形式:
while (表达式)
语句
endwhile;
“语句”是此循环的循环体,它可以是一条语句,也可以是多条的复合语句。当"表达式"为"真"时便开始执行while循环体中的语句,然后反复执行,每次执行都会判断"表达式"是否为"真",若为"假",则终止循环。
[例Ex_While] 一个简单的while..endwhile循环程序。
NUMBERnCount;
program
nCount =1;
while(nCount < 5)
MessageBox("This is still true.", INFORMATION);
nCount =nCount + 1;
endwhile;
endprogram
由于nCount的初始值为1,因此while的表达式为"真",循环体第一次被执行,同时nCount被增加1,当循环4次后,nCount被增加到5,此时while的表达式为"假",结束循环,执行endwhile后面的语句。
需要说明的是,while..endwhile循环可以使用嵌套,但每一个while循环体都必须以endwhile来结束。在while循环体中不能定义语句"标号"。
2.4.3 repeat..until语句
repeat..until循环语句具有下列形式:
repeat
语句
until (表达式) ;
"语句"是此循环的循环体,它可以是一条语句,也可以是多条的复合语句。当语句执行到until时,将判断"表达式"是否为"真",若是,则继续执行循环体,直到下一次表达式等于"假"为止。
[例Ex_Repeat]repeat ..until循环程序。
NUMBERnCount;
program
nCount =1;
repeat
MessageBox("Countis less than 5", INFORMATION);
nCount =nCount + 1;
until(nCount = 5);
endprogram
同while一样,在repeat循环体中也不能定义语句"标号"。
2.4.4 for..endfor语句
for..endfor循环语句具有下列形式:
for X=A toB step C
语句
endfor;
其中,X为循环控制变量(或称循环变量),可以用任一简单变量来表示;A为循环变量初值;B为循环变量终值;C为循环变量的增量或步长。若省略step关键字,则增量自动为1。关键字to也可用downto代替,表示从数值从高到低自动减去C的量。
[例Ex_For]for..endfor循环程序。
NUMBERiCount;
program
foriCount = 1 to 5
MessageBox("You will see this 5 times", INFORMATION);
endfor;
endprogram
[例Ex_DownFor] 使用downto的for..endfor循环程序。
NUMBER j;
program
for j =20 downto 10 step 5
MessageBox("You will see this 3 times", INFORMATION);
endfor;
endprogram
同repeat一样,在for循环体中也不能定义语句"标号"。
2.4.5 abort和exit
abort(异常中断)和exit(退出)是InstallScript的两个关键字。在安装程序执行过程中,当用户按下Esc键、F3键或单击安装对话框中的[Cancel]按钮时,系统将自动执行abort,其目的是将已安装的内容从计算机系统中清除掉。任何时候,只要安装程序遇到abort,都会进行上述的处理。而exit只是中断安装程序的执行,因此若用户在未安装完之前需要程序中断,则应在主程序体中使用abort来代替exit。但也应注意,虽然exit还可代替程序中的endprogram,与program一起构成一个主程序体,但最好不要这样。??palign="right">
2.5 函 数
在结构化程序设计中,通常需要若干个模块实现较复杂的功能,而每一个模块自成结构,用来解决一些子问题。这种模块化的结构设计思想能很好地发挥"团队"力量,在代码修改和重用上,极为方便和快捷。函数正是结构化设计程序的基本结构。
2.5.1 概述
InstallScript允许用户在安装程序中使用下列三种类型的函数:
(1) InstallShield内部函数
InstallShield中定义了250多个的内部函数,包括字符串处理、文件、路径以及文件夹等操作的函数。除了Sd对话框函数外,其他大多数内部函数可以直接在程序中进行调用。
(2) 用户自定义的函数
自定义的函数是用户自己构造的函数,它必须在主程序体program关键字前声明,而在endprogram后进行定义,才能在程序中进行调用。
(3) DLL函数
Windows动态链接库(DynamicLinking Library,简称DLL)提供了一些特定结构的函数,能被应用程序在运行过程中装入和连接,且多个程序可以共享同一个动态链接库,从而可以大大节省内存和磁盘空间。从编程角度来说,动态链接库可以提高程序模块的灵活性,因为它本身是可以单独设计、编译和调试的。同大多数编程语言一样,在InstallShield5.5中也可方便调用DLL函数。
2.5.2 自定义函数的声明和定义
在InstallScript脚本语言中,使用用户自定义函数必须先进行函数的声明,然后进行函数的定义。
(1) 自定义函数的声明
自定义的函数必须在主程序体program关键字前按下列形式进行声明:
prototype 函数名(形参类型1,形参类型2,...);
其中,prototype是InstallScript的关键字,它通知编译器该行语句是用来声明一个自定义函数。"形参类型"是指InstallScript的基本数据类型,如INT、STRING或SHORT等。例如下面的函数声明都是合法的:
prototypeFunctionName (INT, STRING, SHORT); // 声明有三个形参的函数
prototypeCopyBitmapExample (); // 声明一个没有形参的函数
prototypeFileTransfer (LONG, LONG, LONG, STRING, STRING);// 声明有五个形参的函数
函数名是一个有效的InstallScript标识符(注意命名规则),函数名后面必须跟一对圆括号"()",以区别于变量名及其他用户定义的标识名。函数的形式参数写在括号内,参数表中参数个数可以是0,表示没有参数,但圆括号不能省略,也可以是一个或多个参数,但多个参数间要用逗号分隔。
(2) 函数的定义
函数声明后,必须在主程序体endprogram后按照下列的形式进行相应的函数定义:
function 函数名(形参1,形参2,...)
定义函数内部使用的变量;
begin
语句
end;
函数的函数体由begin和end之间的若干条语句组成,用于实现这个函数执行的动作。"函数名"必须和声明时的函数相同,"形参"应与声明时的形参类型一一对应,但"形参名"可以任意的有效InstallScript标识符。如果需要在函数中使用其他变量,则这些变量应在begin前进行定义。
[例Ex_MyFunc]使用自定义函数SetupScreen。
prototypeSetupScreen(NUMBER); // 声明一个函数,只有一个形参
program
SetupScreen(WHITE);// 自定义函数在程序体中的调用
endprogram
function SetupScreen (nColor) // 函数的定义,注意nColor与NUMBER是一一对应的
numbernDx, nDy; // 函数内部变量的定义
begin
GetExtents(nDx, nDy );
Enable(FULLWINDOWMODE);
Enable(INDVFILESTATUS);
Enable(BITMAP256COLORS);
Enable(DIALOGCACHE);
SetTitle("Installing " , 24, nColor);
SetColor(BACKGROUND, BK_BLUE);
SetColor(STATUSBAR, BLUE);
SetTitle("Setup", 0, BACKGROUNDCAPTION);
Enable(BACKGROUND);
Delay(1);
end;
和C语言一样,不允许在一个函数体中再定义函数。
(3) 函数的调用
函数调用的一般形式为: 函数名(实际参数表 );
所谓"实际参数"(简称"实参"),它与"形参"相对应,是实际调用函数时所给定的常量、变量或表达式,且必须有确定的值。需要注意的是:实参与形参的个数应相等,类型应一致,且按顺序对应,一一传递数据。
InstallScript中,调用一个函数的方式可以有很多,例如:
RectangleArea(nLong, nWide);
// 作为一个语句,不使用返回值,只要求函数完成一定的操作
nArea =RectangleArea (nLong, nWide);
// 将函数的返回值赋予一个变量
nTotal=RectangleArea (nLong1, nWide1) + RectangleArea (nLong2, nWide2);
// 将函数的返回值参与运算
2.5.3 BYREF参数和函数的返回值
在InstallScript的大多数函数中,函数的参数传递方式是"按值传递"的。所谓"按值传递",是指当一个函数被调用时,系统根据实参和形参的对应关系将实际参数的值一一传递给形参,供函数执行时使用。函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也不会受到影响。
当然,由于某种原因,用户有时想要让形参的改变影响实参,这里就需要使用BYREF(引用)关键字。所谓"引用",简单地说,它实际上是给一个已知变量起个别名,对引用的操作也就是对被它引用的变量的操作。一个函数能使用引用传递的方式是在函数声明时将形参类型前加上引用关键字"BYREF"。例如:
prototypeStrInvert(BYREF STRING );
若形参列表中不止一个形参定义成引用形式,则必须在每个引用形参类型前加上引用关键字"BYREF"。例如:
prototypeStrChangeChar( BYREF STRING, CHAR, BYREF BOOL);
// 注意,第二个形参没有被变成引用形式。
下面来看看函数参数的引用传递的示例。
[例Ex_ByRef] 函数参数的引用传递。
prototypeSwapString( BYREF STRING, BYREF STRING );
STRINGmyStr1,myStr2;
program
myStr1= "这是第一个字符串";
myStr2= "这是第二个字符串";
MessageBox(myStr1,INFORMATION);// 结果显示"这是第一个字符串"
SwapString(myStr1,myStr2);
MessageBox(myStr1,INFORMATION);// 结果显示"这是第二个字符串"
endprogram
functionSwapString(svString1, svString2)
STRINGsTemp;
begin
sTemp =svString1;
svString1= svString2;
svString2= sTemp;
end;
实际上,如果用户需要函数改变的数值个数只有一个的话,那么使用函数的返回值就显得非常随意。例如:
functionRectangleArea (nLength, nWidth)
INTnVal;
begin
nVal =nLength * nWidth;
returnnVal;
end;
其中,关键字return负责将后面的值作为函数的返回值,并将流程返回到调用此函数的位置处。由于return的后面可以是常量、变量或任何合法的表达式,因此函数RectangleArea可以改成下列形式:
functionRectangleArea (nLength, nWidth)
begin
returnnLength * nWidth;
end;
需要注意的是,一旦执行return语句后,在函数体内return后面的语句不再被执行。
2.5.4 局部变量和全局变量
InstallScript中每一个变量必须先定义后使用,若变量是在函数定义时函数名和begin之间定义的变量,则此变量就是一个局部变量,它只能在函数体内使用,而在函数体外则不能使用它。若变量是在主程序体program前定义,则该变量就是一个全部变量,它能被后面的所有函数或语句引用。
在一个程序中,不能有两个同名的全局变量,但局部变量在其作用范围外可以同名,甚至可以和全局变量同名。
[例Ex_Variable]函数的局部变量。
STRINGszVal; // 定义的全局变量
prototypeAFunction();
program
szVal ="YES"; // 给全局变量赋值,结果为"YES"
AFunction();
MessageBox(szVal,INFORMATION); // szVal结果仍为"YES"
endprogram
functionAFunction()
STRINGszVal; // 函数内部的局部变量,和全局变量同名
begin
szVal ="NO"; // 给局部变量赋值,结果为"NO"
end;
在InstallScript中,函数的形参变量被认为是局部变量。
2.5.5 使用DLL函数
出于对InstallShield函数功能的扩展,InstallShield专业版还允许用户使用外部DLL中的函数,其使用步骤如下:
(1) 首先使用下列形式在主程序体program前声明所要使用的DLL函数:
prototype.<函数名>( 形参类型列表 );
(2) 然后,使用UseDLL函数将DLL文件调入内存;
(3) 接着,用下列形式调用已声明过的DLL函数;
函数名 ( 实参 );
(4) 最后,使用UnUseDLL将DLL文件从内存中释放出来。
[例Ex_DLL] 使用DLL函数。
#define
DLL_FILE"C:\\EXAMPLE\\DLLS\\MSVC\\MSC\\EXAMPLE\\WINDEBUG\\MYDLL.DLL"
// 声明在MYDLL.DLL文件中的MydllReturn函数
prototype MYDLL.MydllReturn( INT, POINTER );
STRING szDLL, svString;
INT nValue;
POINTER psvString;
NUMBER nResult;
BOOL bDone;
program
szDLL =DLL_FILE;
/*--------------------------------------------------------------------------*\
* 将MYDLL.DLL文件调入内存。
\*--------------------------------------------------------------------------*/
nResult =UseDLL (szDLL);
if (nResult= 0) then
MessageBox("UseDLL successful \n\n.DLL file loaded.", INFORMATION);
else
MessageBox("UseDLL failed.\n\nCouldn’t load .DLL file.", INFORMATION);
abort;
endif;
bDone =FALSE;
while (bDone!= TRUE)
Disable(BACKBUTTON);
AskText("Enteran example string.", "Example string.", svString);
psvString= &svString;
nValue =StrLength(svString);
// 调用DLL函数
MydllReturn(nValue,psvString);
SprintfBox(INFORMATION,"UseDLL", "MydllReturn() changed the string " +"to:%s",
svString);
// 由用户控制while循环的终止
if(AskYesNo("Do another example?", YES) = NO) then
bDone =TRUE;
endif;
endwhile;
/*--------------------------------------------------------------------------*\
* 将MYDLL.DLL文件从内存中释放出来。
\*--------------------------------------------------------------------------*/
if(UnUseDLL (szDLL) < 0) then
MessageBox("UnUseDLLfailed.\n\nDLL still in memory.", SEVERE);
else
MessageBox("UnUseDLLsuccessful.\n\n.DLL file removed from memory.",
INFORMATION);
endif;
endprogram
2.6 字符串操作
同C语言一样,InstallScript也有许多字符串操作的运算符及其内部函数。
2.6.1 字符和字符串
虽然InstallScript支持数组类型,但它只支持一维数组。且这里的字符数组和字符串的概念很不一样。例如:
CHARstr[10];
program
str="ABCDE";// 产生编译错误
endprogram
但是,STRING类型的字符串概念与C语言一样。它是一个以'\0'为终止符的一维字符数组,使用数组下标可以获得相应的字符。例如:
[例Ex_String] 使用字符串。
prototypeBlankLeadingZeros(BYREF STRING);
STRINGszString;
program
szString= "00001234";
BlankLeadingZeros(szString);
MessageBox(szString,INFORMATION);
endprogram
functionBlankLeadingZeros(szString) // 将字符串的前导字符'0'变为空格。
INT iVal,iLength;
begin
iVal =0; // 字符数组的下标从0开始
iLength= StrLength (szString);
while(szString[iVal] = "0") && (iVal <= iLength)
szString[iVal]= " ";
iVal =iVal + 1;
endwhile;
end;
结果是将"00001234"字符串变为"1234"。
2.6.2 字符串的运算符
在InstallScript脚本程序中,用户打交道最多的是字符串的操作。为此,InstallScript提供了下列的字符串运算符:
^ (在一个路径或文件名后添加另一个路径)
+ (在一个字符串后添加另一个字符串)
% (在一个字符串中查找一个子串)
例如:
szStringVar= "C:\\MYPATH\\" ^ "YOURPATH\\FILENAME";
的结果为
"C:\MYPATH\YOURPATH\FILENAME"
但是,如果用户忘记在C:\\MYPATH后加上反斜杠,即:
szStringVar= "C:\\MYPATH" ^ "YOURPATH\\FILENAME";
其结果仍然是上述结果。因为InstallScript的"^"运算符自动添加相应的反斜杠。
用字符串的"+"可以将上述表达式改为下列形式:
szStringVar= "C:\\MYPATH\\" + "YOURPATH\\FILENAME";
但是,在使用字符串运算符中,不能在运算符的两边使用圆括号"()"。例如,下面的表达式是错误的:
szPath =szTestPath ^ (AUTOFILE + ".BAT");
而应该用下列形式:
szFile =AUTOFILE + ".BAT";
szPath =szTestPath ^ szFile;
需要特别注意的是,字符串运算符"%"是在一个字符串中查找一个子串,而不是C语言的求余运算符。例如:
szStringVarA= "This is a sample string.";
if(szStringVarA % "sample") then
MessageBox("Operationcomplete",INFORMATION);
endif;
其结果是MessageBox被执行。若在查找时不要求大小写敏感,则上述代码可改为:
szStringVarA= "This is a sample string.";
if(szStringVarA % "SAMPLE") then
MessageBox("Operationcomplete", INFORMATION);
endif;
需要说明的是,字符串运算符%与内部函数StrFind相似,但StrFind还返回被查找的字符串首字符在字符串中的位置。
2.6.3 字符串和数值转换
使用InstallShield的内部函数可以很容易地实现字符串和数值之间的转换。
1. StrToNum函数
StrToNum函数是将字符串转换成数值。函数原型如下:
StrToNum(nvVar, szString);
其中,nvVar是转换后返回的NUMBER数值,而szString用来指定源字符串。当转换成功后,函数返回0,否则返回负值。
需要说明的是,在将字符串转换成数值过程中,可能有下列几种情况:
(1) 若字符串中的字符都是由"0"~"9"组成的,则将其转换成相应的数值。
(2) 若字符串前面的一个或多个字符由"0"~"9"组成,则只转换其前面的字符。例如"-123ABC456"被转换成-123。
(3) 若字符串第一个字符不是"0"~"9"或不是正负号,则不能转换。
(4) 若字符串第一个字符是正负号,而第二个字符不是"0"~"9",则不能转换。
2. NumToStr函数
与StrToNum相对应的NumToStr函数是将数值转换成字符串,其函数原型如下:
NumToStr(svString, nValue);
其中,svString是转换后返回的字符串,而nValue用来指定要转换的NUMBER数值。
[例Ex_NumToStr]将数值转换成字符串。
#defineDISK_DRIVE "C:\\"
STRINGszDrive, svString;
NUMBERnSpace, nResult;
program
szDrive= DISK_DRIVE;
nSpace= GetDiskSpace(szDrive);
nResult= NumToStr(svString, nSpace);
if(nResult < 0) then
MessageBox("NumToStrfailed.", SEVERE);
abort;
endif;
SprintfBox(INFORMATION,"NumToStr", "Disk Space: %s", svString);
endprogram
3. Sprintf函数
Sprintf函数是将字符、字符串、数值按一定的格式转换成另外一个字符串,它和MFC的CString类中的Format函数极为相似。Sprintf函数原型如下:
Sprintf(svResult, szFormat [,arg] [,...]);
其中,svResult是返回的字符串,szFormat用来指定格式控制的字符串,arg是变量或常量列表,它的个数不能超过10个。函数成功调用后,返回得到的字符串长度。
需要说明的是,szFormat字符串所包含的格式字符必须用百分号"%"来引导,由于它的格式与Format函数或C的printf等函数的含义相同,故这里不再重复。例如:
Sprintf (svResult , "%s:%d*%d" ,"屏幕分辨率为", 640, 480);
则svResult的值为:“屏幕分辨率为:640*480”。
2.6.4 字符串操作函数
和C语言一样,InstallShield也提供了许多字符串函数,如表2.3所示。
2.7 结构体类型和指针
至此,我们所使用的数据类型都是基本的类型,如INT、NUMBER、STRING等。但InstallScript还允许用户按一定的规则进行数据结构体类型的构造。同时提供指针的概念,方便用户对变量的地址进行操作。
2.7.1 用typedef定义一个结构体
一个结构体是由多种类型的数据组成的整体。组成结构的各个分量称为结构体的数据成员(简称为成员)。结构体是InstallScript提供的构造复杂数据类型的唯一手段。
1. 定义结构体
结构体定义的格式为:
typedef结构体名
begin
成员定义1;
成员定义2;
...
成员定义n;
end;
结构体定义是以关键字typedef开始的,结构体名应是一个有效合法的标识符。在结构体中的每个成员都必须通过"成员定义"来确定成员名及其类型。例如:
typedefEMPLOYEE
begin
STRINGszName[50]; // 姓名
STRINGszDepartment[50]; // 部门
NUMBERnExtension; // 电话分机号码
end;
其中,EMPLOYEE是自己定义的结构体名,该结构有3个成员变量。一旦结构体类型定义后,就可以定义其结构体变量。例如:
EMPLOYEEstructEmployee;
使用结构体类型时要注意:
(1) 不能用赋值运算符将一个结构内容赋予另一个结构,如newstruct= struct1;
(2) 成员变量类型若是STRING,则必须指定其大小;
(3) 不能在函数体内部定义一个结构体类型;
(4) 成员变量类型或结构体本身不能使用BYREF关键字,数据的传递用指针来进行。2. 结构体变量的引用
当一个结构体变量定义之后,就可引用这个变量。使用时,遵循下列规则:
(1) 只能引用结构体变量中的成员变量,并使用下列格式:
结构体变量名.成员变量名
例如:
structEmployee.nExtension= 3057;
"."是成员运算符,它的优先级是最高的,因而可以把structEmployee.nExtension作为一个整体来看待,它可以像普通变量那样进行赋值或各种运算。
(2) 若成员本身又是一个结构体变量,引用时需要多个成员运算符一级一级地找到最低一级的成员。例如:
typedefPOINT
begin
SHORTnX;
SHORTnY;
end;
typedefRECT
begin
POINTptUpperLeft;
POINTptLowerRight;
end;
RECT rc;
则有:
rc.ptUpperLeft.nX = 0;
2.7.2 指针
如果在程序中定义了一个变量,在编译时系统就会给这个变量分配内存单元,并根据程序中定义的变量类型,分配一定长度的内存空间,每个内存单元中存放着变量的值。为了便于内存单元的存取,系统为每一个内存单元分配一个地址。这个"地址"称为"指针"。
1. 定义和引用指针变量
指针变量(pointer)是存放内存地址的变量,一般情况下该地址是另一个变量存储在内存中的首地址,这时又称该指针变量"指向"这个变量。例如:
INT i;
POINTER p;
...
i = 5;
p = &i;
其中,i是一个值为5的整型变量,p是一个指针变量,&i是取变量i在内存中的地址;于是p的数值就等于变量i在内存中的地址值,因此p是一个指向变量i的指针。
需要注意的是:一旦一个变量定义后,该变量在内存中的地址也就确定下来,不管以后对该变量如何赋值,在程序运行期间,其内存地址总是固定不变的。
指针变量和所有变量一样,遵循先定义后使用的原则。InstallScript中定义一个指针变量是在变量名前加上关键字POINTER,若是结构体类型,则按下列格式:
结构体类型名POINTER 指针变量名1,[指针变量名2,...];
例如:
EMPLOYEEPOINTER pPointerName;
这时,结构体成员变量的引用就可以像下列形式:
pPointerName->nExtension= 3057;
程序中,"->"称为指向运算符,它的左边必须是一个指针变量,它等效于指针变量所指向的结构体类型变量。
在定义一个指针后,系统也会给指针分配一个内存单元,但分配的空间大小都是相同的,因为指针变量的数值是某个变量的地址,而地址值的长度是一样的。
InstallScript中有两个专门用于指针的运算符:
&(取地址运算符)、*(取值运算符)
运算符"&"只能对变量操作,作用是取该变量的地址;运算符"*"用于指针类型的变量操作,作用是取该指针所指内存单元中存储的内容。例如:
EMPLOYEEMyStructure;
POINTERpNum;
STRINGsvString;
...
pPointerName= &MyStructure; // 将结构体变量地址赋予结构体指针
pNum =&nvNumber; // 将NUMBER变量地址赋予指针变量
SprintfBox( INFORMATION , "", "%d" ,*pNum );
2. 函数的指针传递
指针也可作为函数的形参类型,这样的形参改变后将影响实参的值。
[例Ex_Pointer] 函数的指针传递。
typedefRECT // 定义一个结构体
begin
SHORT sX;
SHORT sY;
end;
RECTRectangle; // 定义一个结构体变量
RECTPOINTER pRect; // 定义一个结构体指针变量
prototypeSizeRectangle(RECT POINTER); // 将函数的形参定义成指针
program
pRect =&Rectangle;
SizeRectangle(pRect);// 结果Rectangle的sX和sY分别为10和5
. . .
endprogram
functionSizeRectangle(pRectangle)
begin
pRectangle->sX= 10;
pRectangle->sY= 5;
end;
2.8 链 表
众所周知,在使用数组存放数据前,必须事先定义好数组的长度。而且,相邻的数组元素的位置和距离都是固定的,也就是说任何一个数组元素的地址都可以用一个简单的公式计算出来,因此这种结构可以有效地对数组元素进行随机访问。但数组元素的插入和删除会引起大量数据的移动,从而使简单的数据处理变得非常复杂、低效。为了能有效地解决这些问题,一种称为"链表"的结构类型得到了广泛的应用。
2.8.1 概述
链表是一种动态数据结构,它的特点是用一组任意的存储单元(可以是连续的,也可以是不连续的)存放数据元素。链表中每一个元素称为"结点",每一个结点都是由数据域和指针域组成的,每个结点中的指针域指向下一个结点。
实际上,链表中的每个结点可以有若干个数据和若干个指针。结点中只有一个指针的链表称之为单链表,是最简单的链表结构。
但在InstallScript中,使用的是和C语言相似的单链表结构,并将指针域的操作变成InstallScript内部的工作方式,这使得用户只需通过相应的函数就可以简单地向链表添加字符串或整型数据。这些函数如表2.4所示。
从表2.4中可以看出,InstallScript的单链表结构分为两种类型:一类是由字符串组成的链表;另一类是由整型数据组成的链表。InstallScript规定:在同一个链表中,结点的数据域要么由字符串组成,要么由整型数据组成,而不能同时存在这两种数据类型。
2.8.2 建立链表
在InstallScript中,使用ListCreate函数就可以建立一个单链表。这一点要比C语言的链表操作简单许多。例如下面的示例。
[例Ex_CreateList]创建链表。
LISTlistID; // 定义一个链表变量
NUMBERnItem, nvItem;
program
listID =ListCreate(NUMBERLIST); // 创建链表
// 检查链表是否被成功创建。
if(listID = LIST_NULL) then
MessageBox("不能创建链表。",SEVERE);
abort;
endif;
// 向链表添加数据
nItem =1078;
ListAddItem(listID,nItem, AFTER);
nItem =304;
ListAddItem(listID,nItem, AFTER);
// 返回链表当前结点的数据,结果为304
ListCurrentItem(listID,nvItem);
SprintfBox(INFORMATION,"ListCreate", "Current item in list: %d", nvItem);
// 返回链表中第一个结点的数据,结果为1078。
ListGetFirstItem(listID,nvItem);
SprintfBox(INFORMATION,"ListCreate", "First item in list: %d", nvItem);
ListDestroy(listID);// 删除链表并将链表从内存中释放出来。
endprogram
需要注意的是,当链表使用完之后,必须调用ListDestroy来删除链表,以释放被链表所占用的内存空间。
2.8.3 链表元素的基本操作
InstallScript中的ListAddItem、ListDeleteItem、ListFindItem及ListSetCurrentItem或ListAddString、ListDeleteString、ListFindString及ListSetCurrentString函数分别对链表中的字符串或整型数据的结点进行添加、删除、查找及修改等操作。
[例Ex_AddAndSet]向链表添加结点并进行修改。
#include"Sddialog.h"
STRINGszTitle, szMsg;
LISTlistID;
NUMBERnItem;
program
listID =ListCreate(NUMBERLIST);
if(listID = LIST_NULL) then
MessageBox("Unableto create list.", SEVERE);
abort;
endif;
// 添加结点数据
nItem =1078;
ListAddItem(listID,nItem, AFTER);
nItem =1304;
ListAddItem(listID,nItem, AFTER);
szTitle= "ListSetCurrentItem Example";
szMsg ="Elements in listID:";
// 显示链表内容
SdShowInfoList(szTitle,szMsg, listID);
nItem =305;
/*--------------------------------------------------------------------------*\
* 将当前结点的数据由1304更改成305。
\*--------------------------------------------------------------------------*/
if(ListSetCurrentItem(listID, nItem) < 0) then
MessageBox("ListSetCurrentItemfailed.", SEVERE);
endif;
// 显示修改后的链表内容
SdShowInfoList(szTitle,szMsg, listID);
// 删除链表
ListDestroy(listID);
endprogram
#defineSD_SINGLE_DIALOGS 1
#defineSD_SHOWINFOLIST 1
#include"Sddialog.rul"
当然,用户还可通过ListGetFirstItem和ListGetNextItem函数来遍历链表的结点内容。
[例Ex_SearchAll]遍历链表的结点内容。
STRINGszTitle, szMsg;
LISTlistID;
NUMBERnItem, nvItem, nResult;
program
// 创建一个整型数据链表并添加一些结点数据
listID =ListCreate(NUMBERLIST);
if(listID = LIST_NULL) then
MessageBox("Unableto create list.", SEVERE);
abort;
endif;
// 添加结点数据
nItem =1078;
ListAddItem(listID,nItem, AFTER);
nItem =304;
ListAddItem(listID,nItem, AFTER);
// 以下是链表的遍历过程
nResult =ListGetFirstItem(listID, nvItem);
while(nResult != END_OF_LIST)
szTitle= "ListGetFirstItem & ListGetNextItem";
// 显示nvItem.
SprintfBox(INFORMATION,szTitle, "%i", nvItem);
nResult= ListGetNextItem(listID, nvItem);
endwhile;
// 删除链表
ListDestroy(listID);
endprogram
2.9 编译预处理
InstallScript程序的源代码中可包含各种编译指令,这些指令称为预处理命令。虽然它们实际上不是InstallScript语言的一部分,但却扩展了InstallScript程序设计的环境。
InstallScript提供的预处理命令主要有宏定义命令、文件包含命令和条件编译命令。这些命令在程序中都是以"#"来引导,每一条预处理命令必须单独占用一行。由于它不是InstallScript的语句,因此一般在结尾没有分号";"。
2.9.1 宏定义
在以前的程序中,曾用#define定义这样的一个符号常量:
#defineTITLE "问候"
其中,#define是宏定义命令,它的作用是将字符串"问候"用TITLE来代替;TITLE称为宏名。再如:
#defineMAX_SIZE 145
这样,将数值145用宏MAX_SIZE来代替。
需要注意的是:
(1) #define、MAX_SIZE和145之间一定要有空格,且一般将宏名定义成大写,以与普通标识符相区别。
(2) 宏被定义后,一般不能再重新定义,而只有当使用下列命令才可以:
#undef 宏名
(3) 一个定义过的宏名可以用来定义其它新的宏,但要注意其中的括号,例如:
#defineWIDTH 80
#defineLENGTH ( WIDTH + 10 )
宏LENGTH等价于:
#defineLENGTH ( 80 + 10 )
但其中的括号不能省略,因为当
var =LENGTH * 20;
若宏LENGTH定义中有括号,则预处理后变成:
var = (80 + 10 ) * 20;
若宏LENGTH定义中没有括号,则预处理后变成:
var = 80+ 10 * 20;
显然,两者的结果是不一样的。
(4)InstallScript的宏定义不能带参数,仅限于使用简单的宏定义。
2.9.2 "文件包含"处理
所谓"文件包含"是指将另一个源文件的内容合并到源程序中。InstallScript语言提供了#include命令用来实现文件包含的操作,它的格式如下:
#include"文件名"
例如:
// 将系统缺省路径中的文件包含进来
#include"SUPPORT.RUL"
// 包含一个含有变量或自定义函数声明的文件
#include"DECLARE.RUL"
// 从LIBRARY文件夹中包含一个文件
#include "..\LIBRARY\WINSUB.H"
#include"..\LIBRARY\SYSCHK.H"
// 从DIALOGS文件夹中包含一个文件
#include"..\DIALOGS\WELCOME\WELCOME.H"
#include"..\DIALOGS\REGINS\REGINS.H"
#include"..\DIALOGS\ICONS\ICONS.H"
"文件包含"命令是很有用的,它可以节省程序设计人员的重复劳动。但在使用#include命令需要注意:
(1) 一条#include命令只能包含一个文件,若想包含多个文件须用多条文件包含命令。
(2) 包含的文件所指明的路径全名(含文件名)不能越过260个字符。
(3) 当在文件中使用路径时,应该用单反斜杠"\"代替双反斜杠"\\"。
(4) 若文件中不指明具体的路径,则编译器将在安装程序项目文件夹中或InstallShield的include文件夹中查找。
(5) 不能将C语言的.H文件包含进来,因为编译器不能识别C语言结构。
2.9.3 条件编译
一般情况下,脚本源程序中所有的语句都参加编译,但有时也希望根据一定的条件去编译脚本源文件的不同部分,这就是"条件编译"。条件编译使得同一脚本源程序在不同的编译条件下得到不同的目标代码。
InstallScript提供的条件编译命令有几种常用的形式,现分别介绍如下:
(1) 第一种形式
#ifdef 标识符1
程序段1
[#ifndef 标识符1
程序段2]
#endif
其中,#ifdef、#ifndef和#endif都是关键字,"程序段"是由若干条预处理命令或语句组成的。这种形式的含义是:如果标识符已被#define命令定义过,则编译"程序段1",如果标识符未被#define命令定义过,则编译"程序段2"。
(2) 第二种形式
#ifdef 标识符
程序段1
[#else
程序段2]
#endif
这种形式是第一种形式的替代,它的含义是:如果标识符已被#define命令定义过,则编译"程序段1",否则编译"程序段2"。
(3) 第三种形式
#ifndef 标识符
程序段1
[#else
程序段2]
#endif
这与前一种形式的区别仅在于,如果标识符没有被#define命令定义过,则编译"程序段1",否则就编译"程序段2"。
(4) 第四种形式
#if 表达式1
程序段1
[#elif 表达式2
程序段2
...]
[#else
程序段n]
#endif
其中,#if 、#elif、#else和#endif是关键字。它的含义是,如果"表达式1"为"真"就编译"程序段1",否则如果"表达式2"为"真"就编译"程序段2",...,如果各表达式都不为"真"就编译"程序段n"。
使用InstallScript预处理命令需要注意:
(1) 预处理命令只能放在主程序体外部。
(2) 在#ifdef等预处理命令的同一行上不能添加注释。
(3) 在#ifdef等预处理命令中不能使用像if、while及switch等流控制语句。
(4) 在#ifdef或#ifndef 语句中只能测试整型常量。
(5) 用户还可以#error预处理命令来定义自己的错误信息。例如:
#definePRODUCTID 1
#if(PRODUCTID = 1)
#definePRODUCTNAME "Lite"
#elif(PRODUCTID = 2)
#definePRODUCTNAME "Professional"
#endif
#ifndefPRODUCTNAME
#errorPRODUCTID out of range.
#endif
若PRODUCTNAME没有用#define定义过,则用户定义的错误消息"3out of range."被显示(若PRODUCTID为3)。
2.10 文件及文件夹操作
InstallShield提供了许多函数用来对文件进行基本操作以及对文件夹进行创建、删除和查找等操作。
2.10.1 文件基本操作
文件基本操作包括复制、删除、查找、重新命名以及获取或设置文件的属性等。
(1) 文件的复制
InstallShield提供的CopyFile与XCopyFile函数用来复制文件的,它们的原型如下:
CopyFile(szSrcFile, szTargetFile);
XCopyFile(szSrcFile, szTargetFile, nOp);
这两个函数都是用来将文件从源文件夹复制到目标文件夹中。虽然,CopyFile函数不像XCopyFile可以复制源文件夹下所有的子文件夹中的文件,但它可以将复制到目标文件夹中的文件重新命名。显然,XCopyFile函数对成批复制文件非常有效,并可根据由nOp指定的方式来操作。nOp可以是下列的预定义值:
COMP_NORMAL 正常方式,复制时覆盖相同的文件
COMP_UPDATE_SAME 它和COMP_UPDATE_DATE或COMP_UPDATE_VERSION组合
COMP_UPDATE_DATE 只有当源文件的日期和时间比相同的目标文件新时才会覆盖
COMP_UPDATE_VERSION 只有当源文件的版本比相同的目标文件新时才会覆盖
SELFREGISTER 复制文件时还进行自我注册操作
SHAREDFILE 把复制的所有文件当作是共享的
LOCKEDFILE 记录锁定的.dll和.exe文件以便Windows重启后更新
EXCLUDE_SUBDIR 复制时不含有子文件夹
INCLUDE_SUBDIR 连同子文件夹中的文件一起复制
当然,这两个函数都有可能返回下列的值:
0 成功复制
COPY_ERR_CREATEDIR目标文件夹不能创建
COPY_ERR_MEMORY不能为复制文件进程分配必要的内存
COPY_ERR_NODISKSPACE目标磁盘中没有足够的可用空间
COPY_ERR_OPENINPUT找不到源文件夹
COPY_ERR_OPENOUTPUT不能复制函数中指定的文件
COPY_ERR_TARGETREADONLY目标文件夹写保护
-51 自我注册文件没有注册成功(只用于XCopyFile函数)
其他负数 产生未知的错误
需要说明的是,InstallShield使用系统变量SRCDIR和TARGETDIR表示源文件夹和目标文件夹的路径。由于安装程序中其他函数也会使用这些变量,因此在调用CopyFile与XCopyFile函数前,必须先用VarSave函数将SRCDIR和TARGETDIR的当前值保存,然后设置相应的路径,最后用VarRestore函数恢复SRCDIR和TARGETDIR的原来值。
[例Ex_CopyFile]文件复制示例。
#defineSOURCE_DIR "C:\\Windows"
#defineTARGET_DIR "D:\\Temp"
NUMBERnResult;
program
VarSave(SRCTARGETDIR); // 将缺省的源文件夹和目标文件夹路径保存
SRCDIR =SOURCE_DIR; // 设定源文件夹路径
TARGETDIR= TARGET_DIR; // 设定目标文件夹路径
// 复制文件,它等效于XCopyFile("*.TXT","", COMP_NORMAL)
nResult =CopyFile("*.TXT", "*.*");
if (nResult < 0) then
MessageBox("不能复制文件!",SEVERE);
else
MessageBox("文件复制完毕。",INFORMATION);
endif;
VarRestore(SRCTARGETDIR); // 恢复缺省的源文件夹和目标文件夹路径
endprogram
(2) 文件的删除与重新命名
InstallShield提供的DeleteFile与RenameFile函数分别用来文件的删除与重新命名,它们的原型如下:
DeleteFile(szFile);
RenameFile(szFileOld, szFileNew);
需要说明的是:DeleteFile函数不能删除系统文件、只读文件、隐含文件以及网络上没有删除权限的文件。并且该函数使用TARGETDIR作为其工作路径。而RenameFile函数是将由SRCDIR指定的源文件夹下的文件重新命名并移至由TARGETDIR指定的目标文件夹中。
[例Ex_Rename] 文件重新命名示例。
#defineTARGET_DIR "D:\\Temp"
program
VarSave(SRCTARGETDIR); // 将缺省的源文件夹和目标文件夹路径保存
SRCDIR =TARGET_DIR; // 设定源文件夹路径
TARGETDIR= TARGET_DIR; // 设定目标文件夹路径
// 将My.TXT文件重新命名为MyNew.TXT
if (RenameFile("My.TXT", "MyNew.TXT") < 0 ) then
MessageBox("文件不能重新命名!",SEVERE);
else
MessageBox("文件已重新命名。",INFORMATION);
endif;
VarRestore(SRCTARGETDIR); // 恢复缺省的源文件夹和目标文件夹路径
(3) 文件的查找
InstallShield提供两个函数用来查找文件,它们是:
FindFile(szPath, szFileName, svResult);
FindAllFiles(szDir, szFileName, svResult, nOp);
其中,szDir和szPath用来指定要查找的路径,szFileName表示要查找的文件名,它可以使用通配符,svResult用来返回查找到的第一个文件。对于FindAllFiles函数来说,还可使用nOp指定查找的方式,当nOp为CONTINUE时表示从上一次查找停止的位置处开始查找,当nOp为RESET时表示在szDir中从头开始查找。
[例Ex_FindFiles]查找C:\Windows下的所有.INI文件。
#defineTARGET_DIR "C:\\Windows"
NUMBERnResult;
STRINGsvFileName;
program
nResult =FindAllFiles(TARGET_DIR, "*.ini", svFileName, RESET);
while(nResult = 0)
MessageBox(svFileName,INFORMATION);
nResult= FindAllFiles(TARGET_DIR, "*.ini", svFileName, CONTINUE);
endwhile;
endprogram
endprogram
(4) 文件属性的获取和设置
InstallShield提供的SetFileInfo与GetFileInfo函数分别用来设置与获取文件的属性。SetFileInfo函数的原型如下:
SetFileInfo(szPathFile, nType, nAttribute, szValue);
该函数是用来设置由szPathFile指定文件的由szValue指定的时间、日期或用来更改文件的属性。想要文件的时间和日期同时被改变,用户必须两次调用该函数,但若改变文件的其他多个属性,则只要在nAttribute中使用"|"组合进行一次调用就可实现。其中nType用来指定要更改的文件特征,它可以是下列值之一:
FILE_ATTRIBUTE表示一个或多个属性将被更改
FILE_DATE 表示文件的日期将被更改
FILE_TIME 表示文件的时间将被更改
若当nType为FILE_ATTRIBUTE时指定的文件属性(nType为其它值时,该参数为0),则szValue为"",而nAttribute可以是下列值之一或"|"组合:
FILE_ATTR_ARCHIVED设置"存档"属性
FILE_ATTR_HIDDEN设置"隐含"属性
FILE_ATTR_READONLY设置"只读"属性
FILE_ATTR_SYSTEM设置"系统"属性
FILE_ATTR_NORMAL当此值单独指定时,清除所有的文件属性,
另一个函数GetFileInfo是用来获取一个已存在文件szPathName的属性、时间、日期和大小。它的原型如下:
GetFileInfo(szPathName, nType, nvResult, svResult);
其中,nType用来指定获取文件属性的特征,它可以是下列值之一:
FILE_ATTRIBUTE获取文件属性,结果在nvResult中
FILE_DATE 获取文件日期,格式为YYYY\MM\DD,结果在svResult中
FILE_SIZE 获取文件大小,结果在nvResult中
FILE_TIME 获取文件时间,格式为HH:MM:SS,结果在svResult中
需要说明的是,用GetFileInfo获取文件属性时最好先将nType指定为FILE_ATTRIBUTE,若返回的nvResult值等于FILE_ATTR_NORMAL,则没有任何属性;但若返回的nvResult不等于FILE_ATTR_NORMAL,则需要与系统预定义的文件属性值进行"与"(&)操作以确定文件的具体属性,例如下面的代码片断:
if(nvResult = FILE_ATTR_NORMAL) then
// 正常文件
else
if (FILE_ATTR_HIDDEN& nvResult) then
// 该文件有"隐含"属性
endif;
if(FILE_ATTR_READONLY & nvResult) then
// 该文件有"只读"属性
endif;
endif;
其中,返回的nvResult值可能是:
FILE_ATTR_ARCHIVED存档文件
FILE_ATTR_DIRECTORY目录文件
FILE_ATTR_HIDDEN隐含文件
FILE_ATTR_READONLY只读文件
FILE_ATTR_SYSTEM系统文件
FILE_ATTR_NORMAL正常文件
endprogram
2.10.2 文件夹与路径操作
用于文件夹与路径操作的InstallShield函数有很多,表2.5列出所有的相关函数。
需要说明的是:
1. 关于DeleteDir函数
DeleteDir函数能够删除由szDir指定的文件夹或文件夹中的所有内容,具体的删除操作还取决于nFlag的值。若nFlag为ALLCONTENTS时,则删除该文件夹所有的内容;若nFlag为ONLYDIR时,则仅当文件夹中的文件为空时才会删除该文件夹。需要注意的是:
(1)DeleteDir函数不会将删除的文件夹放入Windows系统的"回收站",因而一旦文件夹删除后不能再恢复。
(2) 该函数不能删除当前文件夹以及网络系统中没有删除权限的文件。
(3) 当指定的文件夹下有"只读"、"隐含"或"系统"文件时,该函数不会删除该文件夹。
(4) szDir指定的文件夹路径中的"\"应是"\\",例如:
DeleteDir("D:\\Temp",ALLCONTENTS);
2. 关于FindAllDirs
FindAllDirs函数用来查找szDir指定的文件夹或该文件夹下的所有子文件夹,并将查找的结果保存在字符串链表listDirs中。函数中的nOp用来指定是(为INCLUDE_SUBDIR)否(为EXCLUDE_SUBDIR)查找所有子文件夹。
[例Ex_FindFolders]查找C盘下的所有子文件夹。
LISTlistDirs;
program
listDirs= ListCreate (STRINGLIST);
FindAllDirs("C:\\", INCLUDE_SUBDIR, listDirs);
ListDestroy( listDirs );
endprogram
需要说明的是,FindAllDirs函数支持Windows95/98的长文件夹名。
3. 关于GetValidDrivesList
GetValidDrivesList函数用来获取系统中有效的驱动器列表,返回的结果取决于下面的nDriveType值:
FIXED_DRIVE查找硬盘驱动器
REMOTE_DRIVE查找网络驱动器
REMOVEABLE_DRIVE查找软盘驱动器
CDROM_DRIVE查找CD-ROM
例如,下面的代码将查找所有的本地驱动器,并将结果存放在字符串列表中:
listDirs =ListCreate (STRINGLIST);
GetValidDrivesList( listDirs , REMOVEABLE_DRIVE , -1 );
GetValidDrivesList( listDirs , FIXED_DRIVE , 10000 );
GetValidDrivesList( listDirs , CDROM_DRIVE , -1 );
ListDestroy( listDirs );
代码中,GetValidDrivesList函数最后一个参数用来指定要查找的驱动器所含有的最少的磁盘空间,若此参数小于0,则查找时不会检测磁盘空间,从而大大加快查找速度,这对查找软驱和CD-ROM特别有用。
2.11 常用对话框操作(上)
作为与用户交互的重要手段,对话框是InstallShield安装程序中最重要也是最主要的用户界面。在安程序程序运行过程中,对话框通过各种控件(如按钮、编辑框、列表框、组合框等)来捕捉用户的输入信息或数据。
基于对话框的这种重要性,InstallShield为用户提供了大量的对话框函数,这其中包括内建对话框和Sd对话框函数。当然,用户也可以在安装程序代码中定义自己的对话框(在4.4节中,将讨论如何定制对话框)。
2.11.1 内建对话框和Sd对话框
InstallShield在系统内部定义了一些对话框,这些对话框称之为内建对话框,其相应的对话框函数可以在所有版本中使用。但为了提高对话框的功能和应用能力,作为补充和拓展,InstallShield还提供了一些高效、适应能力强的脚本对话框(ScriptDialog),由于它们是用InstallScript脚本语言代码来写的,因此又称之为Sd对话框。
1. 内建对话框
InstallShield的内建对话框函数中,除了AskYesNo、MessageBox、SprintfBox等少量对话框是调用WindowsAPI函数外,其余的均是InstallShield自己构造的。表2.6列出了InstallShield全部的内建对话框函数。
例如下面的代码,其结果如图2.1所示。
program
Welcome ("欢迎", 0 );
endprogram
2. Sd对话框
InstallSheld提供了大量的脚本对话框供用户使用,脚本对话框是按InstallScript特定的机制来创建的,并提供对话框的脚本语言代码供用户揣摩。为了与内建对话框函数相区别,脚本对话框的函数名都是以Sd为开头。表2.7列出了InstallShield全部的Sd对话框函数,
但使用脚本对话框时一定要注意:
(1) 与内建对话框函数相比,调用Sd对话框时还需要在安装脚本程序中添加另外两条语句,如下所示:
#include"sddialog.h" // 添加Sd对话框的头文件
program
SdWelcome( "欢迎", "" ); // 调用Sd对话框
endprogram
#include"sddialog.rul" // 添加Sd对话框的脚本文件
其结果如图2.2所示。
(2) 若调用Sd对话框函数时,其字符串实参为NULL字符串("")时,Sd对话框将该参数使用缺省的字符串文本。这一点,也适用于InstallShield的内建对话框函数。
(3) 用户可以通过调用DialogSetInfo改变某些对话框中的控件。
(4) 在Sd对话框函数中,用户可以将%P插入到字符串中,用于放置产品名称。缺省时,产品名称%P表示空字符串,但用户可以使用SdProductName函数来设定其具体的值。
(5) 为了提高系统对Setup.rul的编译速度以及减小编译文件Setup.ins的字节数,在需要包含Sd对话框脚本文件前,先对SD_SINGLE_DIALOGS进行宏定义,然后再对具体的对话框标识(参见表2.7)进行定义。例如若调用SdShowInfoList、SdLicense对话框时,则可有如下定义:
...
endprogram
#defineSD_SINGLE_DIALOGS 1
#defineSD_SHOWINFOLIST 1
#defineSD_LICENSE 1
#include"Sddialog.rul"
(6) 在所有InstallShield对话框中,若对话框含有[Next]、[Back]以及[Cancel]按钮。则单击[Next]、[Back]按钮,对话框函数相应地返回NEXT、BACK之值,而单击[Cancel]按钮,则将弹出"ExitSetup"对话框,用于确认是否真的退出安装。
2.11.2 信息显示对话框
对话框函数MessageBox、SprintfBox、SdLicense、SdShowInfoList、SdShowMsg和SdStartCopy分别用来显示用户资料、安装进程、错误代码等信息。
1. MessageBox和SprintfBox
MessageBox和SprintfBox都是调用Windows的API函数的消息对话框,且SprintfBox还能使用如Sprintf函数的格式控制符。它们的原型如下:
MessageBox(szMsg, nType);
SprintfBox(nType, szTitle, szFormat [,arg] [,...]);
其中,nType用来指定在对话框中显示的图标类型,其预定义值的含义如图2.3所示。
参数szMsg指定要显示的消息内容,如果消息太长,则可在消息文本中添加"\n"转义符来使其换行,szTitle指定对话框的标题。
[例Ex_MessageBox]使用MessageBox。
STRINGszTitle;
STRINGszMyComp;
NUMBERnvDx,nvDy;
program
szTitle ="我的电脑";
SetDialogTitle(DLG_MSG_INFORMATION, szTitle); // 设置对话框的标题为"我的电脑"
GetExtents(nvDx, nvDy );
Sprintf(szMyComp,"%s:%dx %d","屏幕分辨率为",nvDx,nvDy);
MessageBox(szMyComp,INFORMATION );
endprogram
[例Ex_SprintfBox]使用SprintfBox。
NUMBERnvDx,nvDy;
program
GetExtents(nvDx, nvDy );
SprintfBox( INFORMATION , "我的电脑", "%s:%d x %d" , "屏幕分辨率为",nvDx,nvDy);
endprogram
这两个示例的结果都是一样的,如图2.4所示。显然,SprintfBox要比MessageBox功能强大得多。
需要说明的是:缺省时,这两个对话框函数显示的对话框中总有一个[确定]按钮。为了能发挥WindowsAPI的MessageBox的功能,用户可以在上例的基础上作如一些修改。
[例Ex_SprintfBoxEx]扩展使用SprintfBox或MessageBox。
#defineMB_OK 0x0000 // 对话框中含有[确定]按钮
#defineMB_OKCANCEL 0x0001 // 对话框中含有[确定]、[取消]按钮
#defineMB_ABORTRETRYIGNORE 0x0002 // 对话框中含有[终止]、[重试]、[忽略]按钮
#defineMB_YESNOCANCEL 0x0003 // 对话框中含有[是]、[否]、[取消]按钮
#defineMB_YESNO 0x0004 // 对话框中含有[是]、[否]按钮
#defineMB_RETRYCANCEL 0x0005 // 对话框中含有[重试]、[取消]按钮
#defineMB_ICONHAND 0x0010 // 对话框中含有X形图标
#defineMB_ICONQUESTION 0x0020 // 对话框中含有?形图标
#defineMB_ICONEXCLAMATION 0x0030 // 对话框中含有!形图标
#defineMB_ICONASTERISK 0x0040 // 对话框中含有i形图标
NUMBERnvDx,nvDy;
program
GetExtents(nvDx, nvDy );
SprintfBox (MB_YESNO|MB_ICONQUESTION ,"我的电脑" ,"%s:%d x %d" , "屏幕分辨率为",nvDx,nvDy);
endprogram
结果在对话框中显示出[是]和[否]按钮,且图标变成了带问号的图标,如图2.5所示,其中MB_OK等符号常量的值必须按上述代码中的值进行定义。
同样,若将MessageBox函数中的nType设置成MB_YESNO|MB_ICONQUESTION,也会有类似的结果。
2. SdShowInfoList和SdStartCopy函数
SdShowInfoList和SdStartCopy是用来显示多条信息的对话框。它们的原型如下:
SdShowInfoList(szTitle, szMsg, listID);
SdStartCopy(szTitle, szMsg, listData);
其中,szTitle为对话框的标题,szMsg为对话框中最前面显示的消息。ListID和ListData是LIST数据类型的链表变量。
[例Ex_ShowInfo]使用SdShowInfoList和SdStartCopy。
#include"Sddialog.h"
STRINGszTitle, szMsg;
STRINGsvReturn, szInfo;
NUMBERnvReturn;
LISTlistInfo;
program
listInfo =ListCreate(STRINGLIST); // 创建链表
// 检测系统是否有CD-ROM
GetSystemInfo(CDROM, nvReturn, svReturn);
if(nvReturn = TRUE) then
szInfo ="您的计算机中有一个CD-ROM 驱动器。";
else
szInfo ="您的计算机中没有CD-ROM 驱动器。";
endif;
// 将上述信息插入链表中
ListAddString(listInfo,szInfo, AFTER);
// 检测当前系统时间
GetSystemInfo(TIME, nvReturn, svReturn);
Sprintf(szInfo,"现在的时间是:%s.", svReturn);
// 将上述结果插入链表中
ListAddString(listInfo,szInfo, AFTER);
// 检测系统基本内存大小
GetSystemInfo(BASEMEMORY, nvReturn, svReturn);
Sprintf(szInfo,"您的计算机的基本内存大小为:%ldk ", nvReturn);
ListAddString(listInfo,szInfo, AFTER);
szTitle ="SdShowInfoList示例";
szMsg ="下面的信息和您的计算机有关:";
SdShowInfoList(szTitle, szMsg, listInfo);
szTitle ="SdStartCopy示例";
SdStartCopy(szTitle,szMsg, listInfo);
endprogram
#defineSD_SINGLE_DIALOGS 1
#defineSD_SHOWINFOLIST 1
#defineSD_STARTCOPY 1
#include"Sddialog.rul"
结果如图2.6、2.7所示。
第 3 章 基本安装程序的建立
2001-01-23· adding·yesky
上一章介绍了InstallScript脚本语言的一些基础内容,其目的是帮助用户能够编制出具有较高水平的安装程序。当然,建立一个安装程序无需用户从头开始,因为installshild的Project Wizard能快速有效地生成安装项目所需的程序框架。需要用户所做的,就是在该框架的基础上添加或修改一些内容以完善安装程序功能。
3.1 创建安装项目
在installshild 5.5中,Project Wizard用来制作一般应用程序的安装项目,Visual Basic Project Wizard则还专门为VB6.0应用程序进行定制。本节着重讨论Project Wizard的使用方法。
3.1.1 使用Project Wizard
运行installshild 5.5后,双击Project窗口中的ProjectWizard就可开始安装项目向导。
(1) 首先,出现如图3.1所示的"Welcome"对话框,要求用户输入应用程序名称、公司名称、选择应用程序所使用的开发环境、应用程序的类型、版本号以及应用程序的可执行文件名,单击Browse按钮("..."符号的按钮)可将磁盘中已有的应用程序的可执行文件名调入。单击[帮助]按钮,弹出该对话框的帮助说明。
当然,用户不一定现在就在"Welcome"对话框中输入相应的内容,因为在installshild的项目工作区窗口中也可以进行上述内容的修改和添加。
(2) 保留缺省值,单击[下一步]按钮,出现如图3.2所示的"Choose Dialogs"对话框。该对话框用来让用户从列表中选定安装过程中所出现的对话框。在对话框列表项前面的方框中有钩号(√)的表示被选中,单击小方框可以在选中和未选中之间进行切换。每次选定对话框列表项时,"Choose Dialogs"对话框的左下角将会显示相应的对话框模型,单击[Preview]按钮还可按正常比例显示该模型。
(3) 保留缺省值,单击[下一步]按钮,出现如图3.3所示的"Choose Target Platforms"对话框。该对话框用来让用户选择一个或多个操作系统类型,以决定可以在哪些操作系统中进行安装。
(4) 保留缺省值,单击[下一步]按钮,出现如图3.4所示的"Specify Languages"对话框。该对话框用来让用户选择一个或多个语系,以决定创建的安装项目可以支持哪些语系。需要说明的是,installshild 5.5英文专业版只支持English语系的安装项目。
(5) 保留缺省值,单击[下一步]按钮,出现如图3.5所示的"Specify Setup Types"对话框。该对话框用来让用户选择一个或多个应用程序的安装类型,以决定程序安装时供用户选择的安装类型。
需要说明的是,多个安装类型列表项的选定操作是通过鼠标来进行的。当用户按住Shift键不放,再单击鼠标可选定多个连续的列表项,若单击鼠标前按住的键是Ctrl,则可选定多个不连续的列表项。这种操作方式在Windows应用程序中几乎是一致的。
(6) 保留缺省值,单击[下一步]按钮,出现如图3.6所示的"Specify Components"对话框。该对话框用来让用户添加或删除安装项目中的组件,单击[Add]按钮将在Components列表中添加一个组件,单击[Delete]删除选定的组件。
(7) 保留缺省值,单击[下一步]按钮,出现如图3.7所示的"Specify File Groups"对话框。该对话框用来让用户添加或删除安装项目中的文件组,单击[Add]按钮将在File Groups列表框中添加一个文件组,单击[Delete]删除选定的文件组。
(8) 保留缺省值,单击[下一步]按钮,出现如图3.8所示的"Summary"对话框。该对话框显示用户向导中选定的信息摘要,若用户对其中某项设置不满意,可单击[上一步]按钮进行重新选择。任何时候,单击[取消]按钮都会终止创建安装项目。
(9)单击[完成]按钮,installshield开始创建。稍等片刻,一个名为"Your Application Name"的安装项目的框架就创建好了,同时该项目的所有内容都被放在缺省的C:\My Installations\ Your Application Name文件夹中。当然,用户不必当心创建的安装项目名是否和以前创建的安装项目名重名,因为installshild会自动在重名的项目名后面依次加上"-1"、"-2"...。
3.1.2修改安装项目属性
想要改变上述安装项目的缺省属性,可选择"Project"菜单下的"Settings..."命令。弹出相应的"Project Settings"对话框,如图3.9所示。
对话框中含有"General"(一般信息)、"Information"(项目信息)、"Owner"(制造商信息)、"Instructions"(说明)、"Language"(语系)、"Operating Systems"(操作系统)等页面。
其中,"Information"页面可供用户进行开发环境、应用程序的类型以及应用程序适用的行业的重新选择。而"Owner"页面用来指定产品名称、作者、开发商、Email地址、主页、公司名称、版权说明以及版本等信息。
这里,我们着重讨论"Language"和"Operating Systems"两个页面。任何时候,选择这两个标签总可以进行语系和操作平台的添加。
添加语系的操作步骤如下:
(1) 将"Project Settings"对话框切换到"Language"页面(参见图3.9);
(2) 单击[Add...]按钮可向语系列表中增加新的语系,如图3.10所示;
(3) 取消"Show only available languages"选中标记,则语系列表中显示出所有的语系;
(4) 选定"Chinese (PRC)",单击[OK]按钮,将给此安装项目添加一个新的语系"Chinese (PRC)"。
添加操作平台的操作步骤如下:
(1) 将"Project Settings"对话框切换到"Operating Systems"页面;
(2) 单击[Add...]按钮可向操作系统列表中增加新的操作系统,如图3.11所示;
(3) 取消"Show only available platforms"选中标记,操作系统列表中显示出其他一些操作系统;
(4) 选定某操作系统列表项,单击[OK]按钮,将给此安装项目添加一个新的操作平台。3.2理解程序框架
前面创建的安装脚本程序Setup.rul是用来进行安装初始化、显示安装对话框、安装所有的数据以及创建程序菜单项和桌面图标等操作的。
3.2.1 安装初始化
下面先来看看安装脚本程序Setup.rul的部分源代码:
#include"sdlang.h" // 预定义语言标识的头文件
#include"sddialog.h" // Sd对话框的头文件
#defineUNINST_LOGFILE_NAME "Uninst.isu"
// 以下是安装过程所需要的自定义函数声明
prototypeShowDialogs();
prototype...
...
// 以下是全局变量的定义
BOOLbWinNT, bIsShellExplorer, bInstallAborted, bIs32BitSetup;
STRINGsvDir;
STRINGsvName, svCompany, svSerial;
STRINGsvDefGroup;
STRINGszAppPath;
STRINGsvSetupType;
program
Disable(BACKGROUND ); // 安装界面不使用背景色
// 安装初始化
CheckRequirements();
SetupInstall();
SetupScreen();
// 显示安装过程的对话框
if(ShowDialogs()<0) goto end_install;
// 安装所有的文件
if(ProcessBeforeDataMove()<0) goto end_install;
if(MoveFileData()<0) goto end_install;
if(ProcessAfterDataMove()<0) goto end_install;
// 安装注册
if(SetupRegistry()<0) goto end_install;
// 安装程序菜单项和桌面图标
if(SetupFolders()<0) goto end_install;
end_install:
CleanUpInstall();
// 若一个不可恢复的错误产生后,则清除已安装的部分内容
if(bInstallAborted) then
abort;
endif;
endprogram
// 以下是自定义函数的代码
// 略
#include"sddialog.rul" // Sd对话框所必须的包含文件
从上述代码过程可以看出,在程序框架中进行安装初始化的代码语句为:
CheckRequirements();
SetupInstall();
SetupScreen();
它们都是自定义函数的调用,其相应的函数代码如下:
functionCheckRequirements() // 检测安装所需要的环境
NUMBERnvDx, nvDy, nvResult;
STRINGsvResult;
begin
bIsShellExplorer= FALSE;
bIsWindowsNT4= FALSE;
bIsWindowsNT351= FALSE;
bIsWindows95= FALSE;
bIsWindows98= FALSE;
// 测量屏幕分辨率,最小要求为640x 480
GetExtents(nvDx, nvDy );
if (nvDy< 480) then
MessageBox(@ERROR_VGARESOLUTION, WARNING );
abort;
endif;
// 设置"安装"操作模式
bIs32BitSetup= TRUE;
GetSystemInfo(ISTYPE, nvResult, svResult ); // 获得操作系统的类型信息
if(nvResult = 16) then
bIs32BitSetup= FALSE;// 行16位安装程序
return0;
endif;
// 检测目标操作系统
GetSystemInfo(OS, nvResult, svResult );
if(nvResult = IS_WINDOWSNT) then
// 判定操作系统是WindowsNT 4.0还是WindowsNT 3.51,
if(GetSystemInfo( WINMAJOR, nvResult, svResult ) = 0) then
if(nvResult >= 4) then
bIsShellExplorer= TRUE;
bIsWindowsNT4= TRUE;
else
bIsWindowsNT351= TRUE;
endif;
endif;
elseif(nvResult = IS_WINDOWS9X) then
bIsShellExplorer= TRUE;
// 判定操作系统是Windows95还是Windows 98
GetSystemInfo(WINMINOR, nvResult, svResult);
if(nvResult < 10) then
bIsWindows95= TRUE;
else
bIsWindows98= TRUE;
endif;
endif;
end;
functionSetupInstall() // 设置安装时所需要的参数
begin
Enable(CORECOMPONENTHANDLING ); // 可以处理核心组件
bInstallAborted= FALSE;
if(bIs32BitSetup) then // 若是32位安装,将使用长路径名
svDir =PROGRAMFILES ^ @COMPANY_NAME ^ @PRODUCT_NAME;
else
svDir =PROGRAMFILES ^ @COMPANY_NAME16 ^ @PRODUCT_NAME16;
endif;
TARGETDIR= svDir; // 设置目标文件路径
SdProductName(@PRODUCT_NAME ); // 设置Sd对话框中产品的名称
Enable(DIALOGCACHE ); // 将对话框使用高速缓冲机制,避免闪烁
return 0;
end;
functionSetupScreen() // 设置安装主界面的外观
begin
Enable(FULLWINDOWMODE ); // 安装主界面全屏显示
SetTitle(@TITLE_MAIN, 24, WHITE ); // 主标题的颜色为白色、字体大小为24
SetTitle(@TITLE_CAPTIONBAR, 0, BACKGROUNDCAPTION ); // 设置标题栏的标题
Enable(BACKGROUND ); // 可以使用背景颜色
Delay( 1); // 延时1秒
end;
代码中,凡是在标识符前有"@"符号的表示取安装项目中字符串资源中的相关内容。例如@TITLE_MAIN表示取字符串资源中的TITLE_MAIN字段内容。
3.2.2 显示安装过程对话框
显示安装过程对话框的函数是自定义函数ShowDialogs,其代码如下:
functionShowDialogs()
NUMBERnResult;
begin
Dlg_Start:// 开始的语句标号
Dlg_SdWelcome:
nResult =DialogShowSdWelcome(); // 显示欢迎对话框
if(nResult = BACK) goto Dlg_Start; // 按[Back]按钮,转到一开始
Dlg_SdLicense:
nResult= DialogShowSdLicense(); // 显示许可协议对话框
if(nResult = BACK) goto Dlg_SdWelcome; // 按[Back]按钮,转到标号Dlg_SdWelcome
Dlg_SdRegisterUserEx:
nResult =DialogShowSdRegisterUserEx(); // 显示用户注册信息对话框
if(nResult = BACK) goto Dlg_SdLicense;
Dlg_SdAskDestPath:
nResult =DialogShowSdAskDestPath(); // 显示选择目的位置对话框
if(nResult = BACK) goto Dlg_SdRegisterUserEx;
Dlg_SdSetupType:
nResult =DialogShowSdSetupType(); // 显示安装类型对话框
if(nResult = BACK) goto Dlg_SdAskDestPath;
Dlg_SdComponentDialog2:
if((nResult = BACK) && (svSetupType != "Custom") &&(svSetupType != "")) then
gotoDlg_SdSetupType;
endif;
nResult =DialogShowSdComponentDialog2();// 显示选择组件对话框
if(nResult = BACK) goto Dlg_SdSetupType;
Dlg_SdSelectFolder:
nResult =DialogShowSdSelectFolder(); // 显示选择程序菜单项对话框
if(nResult = BACK) goto Dlg_SdComponentDialog2;
return 0;
end;
当然,上述的DialogShowSdSelectFolder等显示对话框的函数也都是自定义函数,用户可自行查看其代码。
3.2.3 安装文件数据
安装文件数据是安装程序所完成的最主要的任务,它不仅将应用程序所需要的全部文件正确地安装到用户指定的目的文件夹中,而且还要为以后反安装时注册一些内容。Setup.rul程序中的自定义函数
ProcessBeforeDataMove、MoveFileData和ProcessAfterDataMove就是实现上述过程,其代码如下:
functionProcessBeforeDataMove() // 在真正数据安装前所做的必须准备
STRINGsvLogFile;
NUMBERnResult;
begin
InstallationInfo(@COMPANY_NAME, @PRODUCT_NAME, @PRODUCT_VERSION,
@PRODUCT_KEY );
// 注册安装信息
svLogFile =UNINST_LOGFILE_NAME; // 反安装注册文件
nResult =DeinstallStart( svDir, svLogFile, @UNINST_KEY, 0 );// 开始注册反安装信息
if (nResult< 0) then
MessageBox(@ERROR_UNINSTSETUP, WARNING );
endif;
szAppPath =TARGETDIR; // 用户指定的安装路径保存在TARGETDIR变量中
if((bIs32BitSetup) && (bIsShellExplorer)) then // 32位安装时
// 以下是反安装信息的注册
RegDBSetItem( REGDB_APPPATH, szAppPath );
RegDBSetItem(REGDB_APPPATH_DEFAULT, szAppPath ^ @PRODUCT_KEY );
RegDBSetItem( REGDB_UNINSTALL_NAME, @UNINST_DISPLAY_NAME );
endif;
return 0;
end;
functionMoveFileData() // 安装数据
NUMBERnResult, nDisk;
begin
nDisk =1;
SetStatusWindow(0, "" ); // 设置安装时的状态窗口参数
Disable(DIALOGCACHE );
Enable(STATUS ); // 显示进展指示器
StatusUpdate(ON, 100 ); // 跟踪显示安装的进程
nResult =ComponentMoveData( MEDIA, nDisk, 0 ); // 安装数据
HandleMoveDataError(nResult ); // 处理安装时产生的错误
Disable(STATUS ); // 关闭进展指示器
returnnResult;
end;
functionProcessAfterDataMove()
STRINGszReferenceFile, szMsg;
begin
// 在反安装之前,DeinstallSetReference用来检测相应的文件,
// 若该文件正在使用,反安装将不会进行。
szReferenceFile= svDir ^ @PRODUCT_KEY;
DeinstallSetReference(szReferenceFile );
return 0;
end;
3.2.4 创建程序菜单项和桌面图标
Setup.rul代码中的自定义函数SetupFolders负责创建程序菜单项和桌面图标,其代码为:
functionSetupFolders()
NUMBERnResult;
begin
nResult =CreateShellObjects( "" ); // 创建Shell对象
returnnResult;
end;
由于安装项目Resources页面的"ShellObjects"目录项中还没有程序菜单项和图标相关的内容,因而上述代码实际上并没有真的起作用。想要创建程序菜单项和图标,除了在ShellObjects目录项中添加相关内容外,还可使用CreateProgramFolder和AddFolderIcon等函数。如下面的代码过程:
functionSetupFolders()
NUMBERnResult;
STRINGsvPath;
begin
svPath =TARGETDIR ^ "MySDI.exe"; // 应用程序的路径全名
LongPathToQuote( svPath , TRUE ); // 使用长路径名
// 创建程序菜单
AddFolderIcon( "" , "我的单文档应用程序" , svPath , "" ,"" , 0 , "" , REPLACE );
// 创建桌面图标
AddFolderIcon( FOLDER_DESKTOP , "我的单文档应用程序" , svPath ,
"", "" , 0 , "" , REPLACE );
file://nResult= CreateShellObjects( "" ); // 创建Shell对象
return 0;file://nResult;
end;
同样,若只在"开始"->"程序"中创建一个程序文件夹,内有"我的单文档应用程序"和"ReadMe"程序项,则有下列代码:
function SetupFolders()
NUMBERnResult;
STRINGsvPath;
begin
//创建程序文件夹
CreateProgramFolder( SHELL_OBJECT_FOLDER );
svPath =TARGETDIR ^ "MySDI.exe"; // 应用程序的路径全名
LongPathToQuote( svPath , TRUE ); // 使用长路径名
// 在程序文件夹下创建程序菜单项
AddFolderIcon( SHELL_OBJECT_FOLDER , "我的单文档应用程序" , svPath ,
"", "" , 0 , "" , REPLACE );
svPath ="C:\\Windows\\NotePad.exe" + TARGETDIR ^ "ReadMe.txt";
LongPathToQuote( svPath , TRUE ); // 将路径名两边插入引号
AddFolderIcon( SHELL_OBJECT_FOLDER , "ReadMe" , svPath ,
"", "" , 0 , "" , REPLACE );
file://nResult= CreateShellObjects( "" );
return 0;file://nResult;
end;
3.3 添加和修改
上述程序框架在编译运行后,不会有任何文件数据被复制,因为该安装项目还只是一个空的框架。所以,它还需要用户通过InstallShield的开发环境对相关文件、文件组、组件、程序菜单项和图标进行添加或修改等操作,并且还需在理解程序框架的基础上,添加一定的代码来完善安装程序的功能,如使序列号有效等。
为叙述方便起见,这里以前面用Project Wizard创建的"Your ApplicationName"安装项目为例。
3.3.1 文件、文件组和组件的修改
在InstallShield中,一个组件包含若干个文件组,一个文件组包含若干个文件。并且,用户可以通过InstallShield的开发环境中的相关属性使它们互相关联起来,如图3.12所示。
根据图3.12所示的关联属性,我们可以作下列一些修改。
1. 删除不要的组件
打开"YourApplication Name"安装项目,将项目工作区窗口切换到Components页面,选定组件项"ExampleFiles",右击鼠标,从弹出相应的快捷菜单中选择"Delete"菜单命令,删除该组件。按类似的操作,删除"HelpFiles"组件。这样,安装项目中只剩下"ProgramFiles"和"SharedDLLs"组件。
2. 删除不要的文件组
将项目工作区窗口切换到FileGroups页面,选定文件组项"ExampleFiles",右击鼠标,从弹出相应的快捷菜单中选择"Delete"菜单命令,删除该文件组。按类似的操作,删除"HelpFiles"和"ProgramDLLs"文件组。这样,安装项目中只剩下"ProgramExecutable Files"和"SharedDLLs"文件组。
3. 向文件组中添加文件
将项目工作区窗口切换到FileGroups页面,展开所有的文件组项。选定"ProgramExecutable Files"的"Links"项,右击鼠标,从弹出相应的快捷菜单中选择"InsertFiles"菜单命令。这里以VisualC++创建的单文档应用程序的MySDI.exe为例,将MySDI.exe(Release版本)文件调入。还有,需要在"SharedDLLs"文件组中将Windows\System文件夹下的mfc42.dll和msvcrt.dll调入。
4. 向组件中添加文件组
将项目工作区窗口切换到Components页面,选定组件项"ProgramFiles",双击右边窗口中的"IncludeFile Groups"字段,弹出如图3.13所示的属性对话框。
在该对话框中单击[Add]按钮,又弹出一个对话框,从该对话框的文件组列表中选定"ProgramExecutable Files",单击[OK]按钮。然后再单击属性对话框的[确定]按钮,文件组"ProgramExecutable Files"就和组件"ProgramFiles"关联起来。类似的,将"SharedDLLs"文件组与"SharedDLLs"组件相关联。
需要说明的是,组件中的字段"Overwrite"属性起着非常关键的作用,因为它决定了在文件复制时的覆盖特征。缺省时是"ALWAYSOVERWRITE",它的意思是:总是将源文件覆盖机器中已有的文件。这样就有可能将一些根本不能工作的老版本文件覆盖机器中已有新版本文件。为此,我们需要将组件的"Overwrite"值进行更改,尤其是"SharedDLLs"组件。
双击"SharedDLLs"组件的"Overwrite"字段,弹出如图3.14的属性对话框。在该对话框的组合框中选择要覆盖的特性类型,通常我们选择如图3.14所示的类型,并进行如图3.14所示的设置。这样,只有源文件比用户机器中的相同文件具有新的时间和高的版本时才覆盖原文件。
3.3.2 添加Shell对象
为了能通过自定义函数SetupFolders中的CreateShellObjects函数创建程序菜单项或桌面图标,我们需要在工作区窗口Resources页面的ShellObjects目录项中添加相关内容。
需要说明的是:在Windows系统中,Shell通常指资源管理器和程序管理器的外壳。展开Shellobjects下的所有目录项,当用户右击某个目录项时,还将弹出相应的快捷菜单。通过它们用户可以在资源管理器外壳(用于Windows95/98和WindowsNT 4.0及其以后操作系统中)下创建程序文件夹(Folder命令)或快捷方式(Shortcut命令),在程序管理器外壳(用于Windows 3.1和Windows NT3.51操作系统中)下创建程序组(Group命令)或图标(Icon命令)。
1. 只在"程序"菜单中添加"我的单文档应用程序"菜单项
其步骤如下:
(1) 在InstallShield集成开发环境中,将工作区窗口切换到Resources页面,并展开ShellObjects目录项中所有的子项,如图3.15所示。
(2) 选定"StartMenu"下的"Programs"子项,右击鼠标,从弹出的快捷菜单中选择"New"->"Shortcut"(快捷方式)菜单命令,此时会在"Programs"目录项下添加一个名为"NewShortcut-1"。
(3) 选定刚才的"NewShortcut-1",右击鼠标,从弹出的快捷菜单中选择"Rename",将"NewShortcut-1"改为"App"。单击"App",将在右边窗口中显示其属性内容,如图3.16所示。
(4) 双击右边窗口中的字段名,如"ShortcutText",则弹出如图3.17所示的属性对话框。单击[>>]按钮将从字符串资源中选择一个字符串作为快捷方式的名称。
(5) 在这个对话框中,用户可以更改所有"Shortcut"属性,其含义和结果如表3.1所示。
3.4 选择媒介发布
当安装项目的所有的内容被编译后,若没有任何错误,我们就可以通过MediaBuild Wizard创建适当的媒介来发布安装程序。
3.4.1 使用Media Build向导
一般来说,对于大型应用程序往往选择CD_ROM媒介来发布,而对于小型应用程序则往往选择3.5英寸软盘(1.44MB)来发布。创建媒介的过程如下:
(1) 用下面的三种方式之一启动MediaBuild Wizard:
选择"Build"菜单"->"MediaBuild Wizard"命令;
单击InstallShield开发环境工具栏上的"MediaBuild"工具按钮。
将InstallShield项目工作区窗口切换到"Media"页面,单击"MediaBuild Wizard"项,或右击鼠标,从快捷菜单中选择"MediaBuild Wizard..."命令。
(2) MediaBuild Wizard启动后,出现"MediaName"对话框。用户在"MediaName"编辑框中可指定一个新的媒介名称。
(3) 保留缺省值,单击[下一步]按钮,出现"DiskType"对话框。在磁盘类型列表中,用户可以选择不同的媒介类型。其中,"singledisk image"用于将文件打包在同一张磁盘中,可进行二次压缩。
(4) 保留缺省值,单击[下一步]按钮,出现"BuildType"对话框。选中"FullBuild"项将全部创建所需要的文件数据,其中包括压缩应用程序的所有文件,创建CAB文件及Setup.exe文件等。选中"QuickBuild"项,将测试和检查安装程序是否按预期的方式进行。单击[Advanced...]按钮,则弹出相应的高级属性对话框,允许用户设置口令、文件的时间/日期、媒介创建的目标位置等属性。
(5) 保留缺省值,单击[下一步]按钮,出现"TagFile"对话框。它用来输入公司名称及其他与应用程序相关的信息,这些信息将保存在Data.tag文件中。
(6) 保留缺省值,单击[下一步]按钮,出现"Platforms"(操作平台)对话框。
(7) 保留缺省值,单击[下一步]按钮,出现"Summary"(摘要)对话框。这里列出前面用户指定的选项,若用户不满意还可单击[上一步]按钮重新进行选择。
(8) 单击[完成]按钮,InstallShield将根据用户的选择创建相应的媒介。这时用户还可看到一个"BuildingMedia"对话框。一旦媒介创建完毕,用户可按[Finish]按钮结束MediaBuild Wizard。
3.4.2 发送到实际的媒介中
当一个媒介创建完成,并且安装项目被正确编译后,就可将其发送到实际的媒介中。这里以刚才创建的"NewMedia"为例,说明发送的过程。
(1) 将InstallShield项目工作区窗口切换到"Media"页面,将会看到刚才的"NewMedia",选定此项并右击鼠标,从弹出的快捷菜单中选择"SendMedia To ..."命令。
(2) 弹出"SelectType"对话框。它用来指定将媒介文件复制到硬盘还是软盘中。
(3) 选中"Copyeach ’disk’ in the media to a removable disk"(复制到软盘)项,单击[下一步]按钮,弹出"Select RemovableDrive"对话框。若有一个以上的软驱,用户可从组合框进行选择。
(4) 单击[下一步]按钮,弹出"Status"(状态信息)对话框。单击[Start]按钮,系统将根据需要提示用户插入一张格式化过的空白软盘,并开始复制相关文件数据。
(5) 一旦文件数据复制完成后,出现"Status"对话框。单击[Close]按钮关闭对话框,完成媒介发送过程。
若用户觉得上述过程比较麻烦,可直接将C:\MyInstallations\Your Application Name\Media\New Media\Disk Images\disk1文件夹中的内容复制到软盘中。需要注意的是,若创建的媒介数据不止一张软盘时,系统会将数据依次存入disk1、disk2、disk3...等文件夹中。
本章从应用角度对基本安装程序的建立过程作深入细致的讨论,使用户不需要太多的脚本程序编写就可对一般应用程序进行包装发布。但是,若仅仅掌握上述技巧则远远不够,因为一个出色的安装软件还应有其独到之处,如果没有创意,那只能是一种重复劳动。因此,从下一章开始起,我们将就安装界面的定制话题作进一步探讨。
第 4 章 安装界面的设计
2001-01-24·adding·yesky
前面讨论的对话框在安装程序中起着非常重要的作用,它们不仅可以获得用户选定的安装路径、需要安装的组件及程序菜单项,而且还可以用于密码和序列号的检测等。但这些对话框是为最后的文件数据安装作准备的,因此从另一个角度来说,用户的最终评价除了取决于对话框的界面效果外,在很大程度上还取决于最后的安装主界面的好坏。当然,为了使安装界面具有一定的"个性",用户还需要在InstallScript语言的基础上,挖掘其运用能力,最大地发挥InstallShield的潜能。
4.1 概 述
与一般Windows应用程序界面相比,安装程序的界面(尤其是安装主界面)要简洁得多。正是因为这个原因,我们在设计安装界面时,尤其要考虑美学方面的要求。
4.1.1 主界面元素
InstallShield5.5提供的图形界面元素包括:弹出窗口、消息文本、对话框、图标、位图、声音以及影像等。同样,组成安装主界面的元素一般也不会超出这些类型。图4.1是一个常见的安装主界面:
它含有这样的一些元素:
(1) 主标题
在安装主界面中,主标题往往是安装的应用程序或软件的名称。一般情况下,主标题的字体是最大的。
(2) 背景
安装主界面的背景往往决定了界面视觉效果的基调,它可以是用户指定的渐变颜色或是纯色。当然也可以用一张图片作为其背景。
(3) 广告牌
InstallShield允许用户在文件复制过程中发布广告牌。所谓广告牌,是指这样的一些位图或元文件图像,它们是用来显示一切用于沟通、广告、培训、激发兴趣以及引起注意的文字或图片。
(4) 进展指示器
进展指示器,顾名思义,它是用来显示文件安装的进度。它有三种类型,一种是没有[取消]按钮的旧式指示器;另一种是只有[取消]按钮,但没有边框和标题栏的指示器;还有一种是带有[取消]按钮的进展对话框。图4.1的进展指示器是最后一种的进展对话框。
(5) 信息指示器
信息指示器用来反映安装过程中三个方面的信息,一是文件已复制到目的位置的百分比,另一是每张安装盘的进展情况,最后是目的驱动器中所含有的可用空间大小。如图4.2所示,当目的驱动器中可用的空间大小低于总容量的5%,最右下角的"Low"将变成红色。
4.1.2 主界面操作函数
InstallShield为用户提供了一些函数用来设置安装主界面的特性以及将界面元素在主界面窗口中的放置位置。表4.1列出这些函数的形式及其功能说:
其中Enable函数是最经常使用的,它是用来激活并显示某个界面元素。其原型如下:
Enable(nConstant);
其中,nConstant表示要激活的界面元素,它可以是下列值之一:
BACKBUTTON 表示[上一步](Back)按钮,缺省时该按钮是被激活。
BACKGROUND 当安装处在窗口模式下时,显示安装界面的背景窗口。
BITMAP256COLORS激活位图的256色调色板
DEFWINDOWMODE设置安装界面的背景窗口是一个常规的、可调整大小及带标题栏的窗口。当BACKGROUND被Enable后,设置的窗口立即有效。
FEEDBACK_FULL表示信息指示器。
FULLWINDOWMODE将安装界面的背景窗口最大化。
HOURGLASS 将鼠标指针变成"沙漏型"的等待光标。
INDVFILESTATUS在进展指示器中显示被传送的文件全名。
NEXTBUTTON 表示[下一步](Next)按钮,缺省时该按钮是被激活。
STATUS 激活标准进展指示器,信息指示器(若没有被禁用)也会被激活。
STATUSDLG 激活对话框形式的进展指示器,信息指示器(若没有被禁用)也会被激活。
STATUSOLD 激活旧式的、不带[取消]按钮的进展指示器,信息指示器(若没有被禁用)也会被激活。
例如:若要指定安装主界面的背景是一个最大化的窗口,则有下列代码:
Enable (BACKGROUND );
Enable (DEFWINDOWMODE );
需要说明的是,在与Enable相对的Disable函数中,形参nConstant的取值和Enable函数中的nConstant是基本相同的。
4.1.3 界面设计的常用原则
界面设计中常遵循的原则有:对比原则、协调原则、平衡原则、乐趣原则等。运用这些原则可以加强界面的气氛、增加吸引力、突出重心、提高美感。其中,乐趣原则的重要性非同小可。所谓"乐趣"原则是指对用户的愉悦心情的考虑,通俗来说就是提供以用户为中心,提高其舒适感。为了遵循这个原则,用户需要在比例、强调、凝聚、扩散以及形态等多个方面加以考虑。
1. 比例
黄金分割点(0.618),也称黄金比例,是界面设计中非常有效的一种方法。在设计物体的长度、宽度、高度及其型式和位置时,如果能参照黄金比例来处理,就能产生特有的稳定和美感。
2. 强调
在单一风格的界面中,加入适当的变化,就会产生强调的效果。强调可打破界面的单调感,使界面变得有朝气,例如,界面皆为文字编排,看起来索然无味,如果加上插图或照片,就如一颗石子丢进平静的水面,产生一波一波的涟漪。
3. 凝聚与扩散
人们的注意力总会特别集中到事物的中心部分,这就构成了视觉的凝聚。一般而言,凝聚型看似温柔,也是许多人所喜欢采用的方式,但容易流于平凡。离心型的布局,可以称为扩散型是具有现代感的编排型式。
4. 形态的意象
由于计算机屏幕的限制,一般的编排形式总是以四边形为标准形,其他各种形式都属于它的变形。四角皆成直角,给人以很规律、表情少的感觉,其他的变形则呈现出形形色色的感觉,譬如成为锐角的三角形有锐利、鲜明感,近于圆的形状有温和柔弱之感。相同的曲线也有不同的表情,例如用仪器画出来的圆,有硬质感,而徒手画出来的圆就有柔和的圆形曲线之美。
5. 变化率
在界面设计中,必须根据内容来决定标题的大小。标题和正文大小的比率就称为变化率。变化率越大,界面越活泼,变化率越小,界面格调越高。依照这种尺度来衡量,就很容易判断界面的效果。
6. 规律感
具有共同印象的形状反复排列时,就会产生规律感。不一定要用同一形状的东西,只要具有强烈印象就可以了。三四次的出现就能产生轻的规律感。有时候只反复使用两次特定的形状,也会产生规律感。规律感在设计一个软件时,可以使用户很快地熟悉系统,掌握操作方法。这一点,相信用户从微软的Windows软件中可以得到启发。
7. 导向
依眼睛所视或物体所指的方向,使界面产生一种引导路线,称为导向。设计者在设计界面时,常利用导向使整体画面更引人注目。一般来说,用户的眼光会不知不觉地锁定在移动的物体上,即使物体是在屏幕的角落,画面的移动都会让目光跟它移动的方向。了解了这一点,设计者就可以有意识地将用户的目光导向到希望用户注意的信息对象上。
8. 空白区
速度很快的说话方式适合体育新闻的播报,但不适合做典礼的节目主持人,原因是每一句话当中的空白量太少。界面设计的空白量问题也很重要,无论排版的平衡感有多好,读者一看界面的空白量就已给它打好分数了。所以,千万不要在一个界面上放置太多的信息对象,以至界面拥挤不堪。没有空白区,就没有界面的美。空白的多寡对界面的印象有决定性的影响。空白部分加多,会使格调提高并且稳定界面;空白较少,会使人产生活泼的感觉。设计信息量很丰富的杂块界面时,用较多的空白显然就不适合。
4.2 应用多媒体
为了不使安装主界面过于单调,许多优秀软件(如Windows 98、VisualStudio 98等)的安装界面中还用广告牌的形式来发布相关信息,让用户更多地了解自己的产品;甚至还播放背景音乐或影像来消除用户在安装过程中长时间等待的不满情绪。这种以多媒体的形式来丰富安装主界面的特色,是InstallShield5.5中的显著特点。
4.2.1 字体
字体是文字显示的外观形式,它包括了文字的字样、风格和尺寸等多方面的属性。适当地选用不同的字体,可以大大地丰富文字的外在表现力。例如,把文字中某些重要的字句用较粗的字体显示,能够体现出突出、强调的意图。
字体的字样是字符书写和显示时表现出的特定模式,例如,对于汉字,通常有宋体、楷体、仿宋、黑体、隶书以及幼圆等多种字样。字体风格主要表现为字体的粗细和是否倾斜等特性。字体的尺寸是用来指定字符所占区域的大小,通常用字符高度来描述。字体尺寸可以取毫米或英寸作为单位,但为了直观起见,也常常采用一种称为"点"的单位,一点约折合为1/72英寸。对于汉字,还常用"号"数来表示字体尺寸,初号字最大,以下依次为小初、一号、小一、二号、小二??,如此类推,字号越大,字体尺寸越小。
在InstallShield中,字体的应用范围非常有限,用户只能通过SetFont和SetTitle设定安装主界面中主标题的字体类型和大小。例如:
SetFont ( FONT_TITLE ,STYLE_BOLD|STYLE_ITALIC|STYLE_SHADOW , "华文新魏" );
SetTitle ("InstallShield汉化补丁", 28 , WHITE);
// 设定主标题的内容为"InstallShield汉化补丁"、大小为28点、颜色为白色
其中SetFont是用来设置要显示字符串的文本字体,它的原型如下:
SetFont(nItemID, nFontStyle, szFontName);
参数nItemID用来指定要设置字体的项目,目前只能为FONT_TITLE,它表示主标题。nFontStyle用来指定字体的风格,它可以是下列的值之一:
STYLE_NORMAL正常字体风格,它不能与其他值进行"|"组合
STYLE_BOLD 粗体
STYLE_ITALIC斜体
STYLE_SHADOW文字带阴影
STYLE_UNDERLINE文字带下划线
szFontName用来指定字体的字样名。若指定的字样名没有找到,则使用缺省的"Arial"字样。当函数返回0时表示字体设置成功,否则字体设置失败。
需要说明的是,在安装Word2000后,Windows可使用的字体类型增加了很多,尤其是中文字体。但是,用户最好能使用基本的中文字体,如宋体、楷体、黑体以及仿宋体,以适应不同的安装环境。
4.2.2 颜色
Windows提供了一种"设备无关"的颜色接口,使得应用程序只需提供"绝对的"颜色值,系统就会将该代码以合适的颜色或颜色组合映射到计算机的显示器上。同样,也可以在InstallShield安装脚本程序中使用RGB函数来指定某一个颜色值:
NUMBERnColor;
...
nColor =RGB(128, 0, 255);
其中,RGB函数用来创建一个用于SetColor和SetTitle函数中的颜色值。它的原型如下:
RGB(constRed, constGreen, constBlue);
参数constRed、constGreen和constBlue用来指定RGB中红色、绿色和蓝色分量值,取值范围都是为0-255,函数成功调用后返回相应的颜色值。
但是,这一颜色值在系统不同的颜色模式下,其实际的颜色会有所不同。例如,在256色颜色模式下,由于实际显示的颜色不会超过256色,因此系统会用最接近的颜色和用户指定的颜色相匹配,从而造成了颜色的失真现象。为了有效地解决这一问题,下面的建议值得参考:
(1) 尽量使用Windows的标准色。例如对于256色模式,有下列20种标准色:
RGB( 0, 0,0) 黑色
RGB( 0, 0,255) 蓝色
RGB( 0,255, 0) 绿色
RGB( 0,255, 255) 青色
RGB( 255,0, 0) 红色
RGB( 255,0, 255) 品红色
RGB( 255,255, 0) 黄色
RGB( 255,255, 255) 白色
RGB( 0, 0,128) 暗蓝色
RGB( 0,128, 0) 暗绿色
RGB( 0,128, 128) 暗青色
RGB( 128,0, 0) 暗红色
RGB( 128,0, 128) 暗紫色
RGB( 128,128, 0) 橄榄色
RGB( 128,128, 128) 暗灰色
RGB( 192,192, 192) 亮灰色
RGB( 192,220, 192) 淡绿色
RGB( 166,202, 240) 天蓝色
RGB( 255,251, 240) 乳白色
RGB( 160,160, 164) 中灰色
(2) 尽量使用纯色,尤其是用于安装主界面的背景颜色。这些纯色是InstallShield中预先定义的一些值,并可从SetColor函数得到这些纯色的应用:
SetColor(nObject, nColor);
该函数用来为指定的对象设定颜色。其中nObject用来指定要设定颜色的对象,它只能是下列值之一:
BACKGROUND 表示安装主界面的背景
STATUSBAR 表示进展指示器中的进展条
参数nColor用来指定要设定的颜色。它除了可以是用RGB定义的颜色外,还可使用下面的颜色:
BK_BLUE 渐变的蓝背景色
BK_GREEN 渐变的绿背景色
BK_MAGENTA 渐变的紫背景色
BK_RED 渐变的红背景色
BK_YELLOW 渐变的黄背景色
BK_SOLIDBLUE用于背景的纯蓝
BK_SOLIDGREEN用于背景的纯绿
BK_SOLIDMAGENTA用于背景的纯紫
BK_SOLIDRED用于背景的纯红
BK_SOLIDYELLOW用于背景的纯黄
BK_SMOOTH 与RGB定义的颜色进行"|"组合,用于产生渐变的背景色。
GREEN 产生绿色的进展条
RED 产生红色的进展条
BLUE 产生蓝色的进展条
MAGENTA 产生紫色的进展条
YELLOW 产生黄色的进展条
(3) 如果安装界面一定要使用256色以上的颜色模式,那么可通过GetSystemInfo(COLORS, 0, "")获得当前系统使用的颜色数来确定是否继续安装。
4.2.3 位图
InstallShield5.5支持的图像格式文件有两种类型。一种是BMP,它是一些和显示像素相对应的位阵列;另一种是WMF,它是一种标准型的图元文件,也是一种设备无关的图像文件,它将图像以图形对象(线、圆弧、多边形)而不是用像素的形式来存储的。
在InstallShield5.5中,位图不仅可以作为广告牌,而且可以作为组件项前面的图标以及对话框左边的位图标签。
1. 组件项前面的图标
下面的过程将使一个位图成为组件项前面的图标:
(1) 用图像编辑软件创建一个位图,如图4.3所示。
该位图实际上是由多个连续的16x 16的图像组成的,其背景色一定要设置成紫色(RGB值为255,0,255)。
(2) 将该位图保存在View.bmp文件中。
(3) 启动InstallShield5.5,用ProjectWizard创建一个安装项目。
(4) 切换到项目工作区窗口的"SetupFiles"页面,选定"LanguageIndependent\Windows 95/98 & NT 3.51/4.0"项。
(5) 在右边的属性窗口中,右击鼠标,从弹出的快捷菜单中选择"InsertFiles..."命令。
(6) 通过弹出的对话框将刚才保存的View.bmp文件调入。
(7) 将项目工作区窗口切换到Media页面。单击MediaBuild Wizard项,创建新的媒介。
(8) 编译并运行。在"SelectType"对话框中选择"Custom"安装类型,按[Next>]按钮弹出如图4.4所示的"SelectComponents"对话框界面。
需要说明的是,组件图标可应用于ComponentDialog、SdComponentDialog、SdComponentDialog2、SdComponentDialogAdv和SdComponentMult对话框中。
2. 一般位图的显示
当然,若用户想要将位图显示在屏幕的任何位置,则可使用PlaceBitmap函数,其原型如下:
PlaceBitmap(szName, nID_BITMAP, nDx, nDy, nDrawOp);
该函数是将一张图像插入到安装界面中。这个图像来自于由szName指定的BMP文件、WMF文件或DLL文件。若szName指定的文件是DLL,则还需要用nID_BITMAP指定相应的位图ID号。参数nDx和nDy用来指定与安装界面窗口边框的水平和垂直偏移量,参数nDrawOp用来表示以下的操作方式:
BITMAPICON 表示位图有透明部分。用户可以将此方式与其他操作进行"|"组合,但除TILED、FULLSCREEN和FULLSCREENSIZE外。当szName指定一个图元文件或是一个24位位图,则BITMAPICON不起作用。
TILED 平铺位图
FULLSCREENSIZE将图像放大至整个安装窗口
CENTERED 居中位图
LOWER_LEFT 将位图放置在窗口的左下角
LOWER_RIGHT将位图放置在窗口的右下角
UPPER_LEFT 将位图放置在窗口的左上角
UPPER_RIGHT将位图放置在窗口的右上角
REMOVE 清除以前放置在窗口中的图像
需要说明的是:
(1) 应明确图像文件路径的影响。用于显示在安装界面的图像文件的路径,用户可以在上述函数的szName中指定,例如D盘中存在MyImage.bmp文件,则szName应为"D:\\MyImage.bmp"。虽然此时运行一般不会有问题,但将安装程序发布后问题就来了,因为用户的机器上不会有MyImage.bmp文件。为此我们需要将要使用的所有文件(包括图像文件)添加在InstallShield集成开发环境的"SetupFiles"页面中,此时szName应为:
szName =SUPPORTDIR ^ "MyImage.bmp";
(2) szName中也可使用分号";",用来设置相应的透明色。例如:
szName =SUPPORTDIR ^ "TransImage.bmp;255, 128, 64";
其中,255, 128,64分别表示RGB颜色中的红、绿、蓝颜色分量值,用来指定这种颜色是透明的。
(3) 若图像保存在DLL文件中时,用户不但用szName指定DLL文件全名,而且还要在nID_BITMAP指定相应的位图ID号,这里的ID号是DLL中已定义的。例如,若创建的DLL文件是MyImage.DLL,文件中包含一个位图(ID号为1000),当该文件调入安装项目后,则有下列代码:
PlaceBitmap( SUPPORTDIR ^"MyImage.Dll" , 1000 , 0, 0, CENTERED );
图像保存在DLL文件的方法有很多,例如用户可以用VisualC++ 6.0修改_IsRes.DLL或利用InstallShield专业版提供的定制对话框的项目来构造编译。但不管是怎样的方法,其最后的DLL文件名一定不能是_IsRes.DLL或_IsUser.DLL,否则相应的图像不会显示。
(4) 当在PlaceBitmap函数中使用REMOVE操作方式之前,可以用nID_BITMAP指定一个位图ID号,这样就不需要再指定相应的图像文件名。例如:
PlaceBitmap( "D:\\CIBA2Ks.bmp" , 10 , 0, 0, CENTERED );
elay(1);
PlaceBitmap( "" , 10 , 0, 0, REMOVE );
(5) 为了使显示的图像更具特色,用户可以在PlaceBitmap函数调用前,用SetDisplayEffect函数设置图像显示效果,它的原型如下:
SetDisplayEffect(nEffect);
其中,nEffect可以下列值之一(但这些效果对PlaceBitmap操作方式BITMAPICON、BITMAPFULLSCREEN和BITMAPTILE不起作用):
EFF_FADE 淡入淡出效果
EFF_REVEAL 中心展开效果
EFF_HORZREVEAL水平展开效果
EFF_HORZSTRIPE水平条纹显示效果
EFF_VERTSTRIPE垂直条纹显示效果
EFF_BOXSTRIPE盒式条纹显示效果
EFF_NONE 取消任何效果
3. 对话框的位图标签
更改对话框的位图标签有两种方法,一是使用VisualC++修改_IsRes.Dll中的对话框资源,另一是使用DialogSetInfo函数。由于第一种方法在本章的最后一节中还将具体介绍,故这里仅讨论第二种方法。
函数DialogSetInfo是用来更改一些Sd对话框中的指定的元素,例如对话框中的位图标签、复选框的风格、硬盘空间大小的单位等。该函数往往应用于SdComponentDialogAdv、SdComponentDialog2和SdComponentMult对话框函数中。它的原型如下:
DialogSetInfo(nInfoType, szInfoString, nParameter);
其中参数nInfoType用来指定要更改的元素,它可以是下列值之一:
DLG_INFO_USEDECIMAL显示的内存大小使用十进制
DLG_INFO_KUNITS空间大小的单位使用KB
DLG_INFO_ALTIMAGE更改对话框中的位图标签
DLG_INFO_CHECKSELECTION更改复选框的风格
参数szInfoString用来当nInfoType为DLG_INFO_ALTIMAGE时指定的位图文件名,该位图的大小最好为120x 260像素,否则超出该范围的位图被裁剪,小于该范围的位图被缺省的背景色(RGB(0,128,028))填充。
参数nParameter用来当nInfoType为DLG_INFO_CHECKSELECTION时,指定下列的值:
CHECKBOXWindows 3.1的复选框
CHECKBOX95Windows 95的复选框
CHECKLINE 选中项
CHECKMARK 选中标记
若当nInfoType为DLG_INFO_ALTIMAGE时,则该参数可以是:
-1 将位图填入_isres.dll相关的资源中
TRUEszInfoString必须指定显示的位图
若当nInfoType为DLG_INFO_KUNITS或DLG_INFO_USEDECIMAL时,则该参数可以是:
TRUE 表示nInfoType设置有效
FALSE 表示nInfoType设置无效,使用缺省的风格
例如,下面的过程将使所有的对话框的位图标签改为类似如图4.5所示的外观:
(1) 用图像编辑软件创建一个大小为120x 260的位图。将该位图保存在Bmp.bmp文件(也可是其他文件名)中。
(2) 启动InstallShield5.5,用ProjectWizard创建一个安装项目。
(3) 切换到项目工作区窗口的"SetupFiles"页面,选定"LanguageIndependent\Windows 95/98 & NT 3.51/4.0"项。
(4) 在右边的属性窗口中,右击鼠标,从弹出的快捷菜单中选择"InsertFiles..."命令。
(5) 通过弹出的对话框将刚才保存的Bmp.bmp文件调入。
(6) 打开Setup.rul文件,在主程序体的最前面添上下列语句:
DialogSetInfo( DLG_INFO_ALTIMAGE , SUPPORTDIR ^"Bmp.bmp" , TRUE );
(7) 将项目工作区窗口切换到Media页面。单击MediaBuild Wizard项,创建新的媒介。
(8) 编译并运行。
4.2.4 声音和影像
为了丰富产品展示的表现力,提高安装界面的专业水准,InstallShield还提供了PlayMMedia函数来播放MIDI、WAVE声音和AVI影像,其函数原型如下:
PlayMMedia(nType, szFileName, nOperation, nReserved);
其中,nType表示播放的媒体类型,它可以是MMEDIA_WAVE(MIDI音乐)、MMEDIA_MIDI(WAVE音乐)和MMEDIA_AVI(AVI影像);szFileName指定要播放的声音或影像文件全名,若媒体文件调入安装项目后,则可使用系统变量SUPPORTDIR来指明相应的路径;nReserved目前保留,只能为0;nOperation表示媒体播放的方式,它可以是下列值:
MMEDIA_PLAYSYNCH同步播放。它意味着只有当媒体播放完毕后,才执行下一步操作。
MMEDIA_PLAYASYNCH异步播放。它意味着媒体是在后台播放的,但为了确保媒体播放结束,还必须指定MMEDIA_STOP操作。
MMEDIA_PLAYCONTINUOUS循环播放。它只能和MMEDIA_PLAYASYNCH进行"|"组合。
MMEDIA_STOP停止播放。
显然,若要在安装进行过程中进行媒体的后台连续播放,则可有下列代码:
PlayMMedia ( MMEDIA_WAVE , "C:\\Windows\\Media\\TheMicrosoft Sound.wav" ,
MMEDIA_PLAYASYNCH|MMEDIA_PLAYCONTINUOUS, 0 );
...
PlayMMedia ( MMEDIA_WAVE , "C:\\Windows\\Media\\TheMicrosoft Sound.wav" ,
MMEDIA_STOP, 0 );
4.3 界面的效果设计
通过上面的介绍,相信用户对安装界面的设计有一定的了解,这里再对一些常用的界面效果的设计方法和技巧作进一步的讨论。
4.3.1 设置主界面的背景效果
安装主界面的背景可以有三种效果:一般背景色、渐变背景色以及位图背景。
1. 背景色
在设置安装主界面的背景色之前首先要调用Enable函数显示安装界面的背景,然后调用SetColor函数设置相应的背景色,若在该函数中指定BK_SMOOTH特性时,则产生垂直的颜色渐变效果,其中SetColor指定的颜色是界面最上边的颜色,而最下面的颜色是黑色RGB(0,0, 0)。例如:
program
Enable (BACKGROUND );
Enable (FULLWINDOWMODE );
SetColor (BACKGROUND , BK_RED|BK_SMOOTH );
Delay( 3);
endprogram
其结果如图4.6所示。需要说明的是,若不指定任何背景色,则安装界面使用缺省的深青色RGB(0, 128, 128)。
2. 位图背景
如果想要用位图作为安装界面的背景,用户首先要创建一个BMP或WMF图片,然后调用PlaceBitmap函数将图片显示在安装界面上。但为了图片能覆盖整个背景,用户还必须在该函数中指定FULLSCREENSIZE、FULLSCREEN(若图片大小超过背景)或TILED特性。例如下面的代码:
program
Enable (BACKGROUND );
Enable (FULLWINDOWMODE );
PlaceBitmap( "C:\\Windows\\安装程序.bmp", 0 , 0 , 0 , FULLSCREENSIZE );
Delay( 3);
endprogram
其结果如图4.7所示。
4.3.2 使用进展指示器
在说明进展指示器的使用方法之前,我们先来看看ProjectWizard产生的一段代码:
functionMoveFileData()
NUMBERnResult, nDisk;
begin
nDisk =1;
SetStatusWindow( 0, "" );
Disable(DIALOGCACHE );
Enable(STATUS );
StatusUpdate( ON, 100 );
nResult =ComponentMoveData( MEDIA, nDisk, 0 );
HandleMoveDataError(nResult );
Disable(STATUS );
returnnResult;
end;
显然,上述代码中的SetStatusWindow、Enable以及StatusUpdate函数与进展指示器密切相关。其中,Enable用于激活和显示不同类型的进展指示器,相关的参数值可以是STATUSDLG(标准类型的进展对话框)、STATUS(只有[取消]按钮的进展条)、STATUSOLD(没有[取消]按钮的进展条)以及INDIVFILESTATUS(在进展指示器中显示被传送的文件全名);而SetStatusWindow和StatusUpdate分别用于设置进展指示器的相关信息及确定是否跟踪文件复制进程,它们的原型如下:
SetStatusWindow(nPercent, szString);
该函数是为进展指示器指定开始或当前的百分比以及在进展条上方显示的当前文本信息。参数nPercent指定进展指示器的百分比大小(从0到100)。若不改变当前的百分比,则将此参数设定为-1。参数szString指定在进展条上方显示的当前文本信息。若指定组件的"StatusText"属性后,则当调用ComponentMoveData函数时,这个信息内容还会自动被更改,
StatusUpdate(bLink, nFinalPercent);
该函数使用或禁止跟踪文件传送进程。一旦bLink设为ON,当文件传送时,进展条自动显示出相应的百分比,直到nFinalPercent设定的最后百分比值为止。参数bLink用来指定是使用(ON)或禁止(OFF)跟踪文件复制进程。nFinalPercent用来指定跟踪文件复制进程后要达到的最终百分比。若设定的最终百分比比当前的值要小,则进展条不会被更新。
需要说明的是:
(1)StatusUpdate函数只对文件传送函数CopyFile、XCopyFile以及ComponentMoveData有效。
(2) 用户可以用SetStatusWindow函数来代替StatusUpdate进行文件传送进程的人工跟踪,例如下面的代码:
// 假设安装项目中只有一个名为"Component"的组件,该组件下包含一个文件组"FileGroup"
NUMBERnTotalSize, nFileSize, nPercent;
NUMBERnFileResult, nvResult;
LISTlistFile;
STRINGsvFile, svStatus, svResult;
program
nPercent =0;
Enable (BACKGROUND );
Enable (FULLWINDOWMODE );
PlaceWindow( BILLBOARD , 0 , 0 , CENTERED );
Enable(STATUSDLG );
Enable( INDVFILESTATUS);
PlaceWindow( FEEDBACK , 50 , 50 , LOWER_LEFT );
PlaceWindow( STATUSDLG , 50 , 50 , LOWER_RIGHT );
SetStatusWindow( nPercent , "准备复制文件...");
VarSave(SRCTARGETDIR);
TARGETDIR= "D:\\Temp";
// 获取所有组件中的文件字节总数
nTotalSize= ComponentTotalSize ( MEDIA , "" , TRUE , TRUE );
listFile =ListCreate( STRINGLIST );
// 获取与"Component"组件相联的文件组中的所有文件
ComponentFileEnum( MEDIA , "Component" , "File Group\\*.*" , listFile ,INCLUDE_SUBDIR );
// 获取"Component"组件的状态文本信息
ComponentGetData( MEDIA , "Component" , COMPONENT_FIELD_STATUS , nvResult , svStatus);
nFileResult= ListGetFirstString( listFile, svFile );
while (nFileResult != END_OF_LIST )
// 获取每个文件的字节大小
ComponentFileInfo( MEDIA , "Component" , svFile ,COMPONENT_INFO_ORIGSIZE , nFileSize , svResult);
// 计算当前的百分比
nPercent= nPercent + 100 * nFileSize / nTotalSize;
// 设置进展提示器的相关信息
SetStatusWindow( nPercent , svStatus );
nFileResult= ListGetNextString( listFile, svFile );
endwhile;
ListDestroy(listFile );
VarRestore(SRCTARGETDIR);
SetStatusWindow( 100 , " 文件复制完毕...");
Delay ( 3);
endprogram
如果用户执意人工处理组件的相关数据,虽然不失为一种方法,但总没有函数ComponentMoveData来得简单,且该函数是唯一能自动更新信息批示器的函数。
(3) 另外,用户还可使用SetDialogTitle和SetColor函数来改变进展对话框的标题和进展条的颜色。例如:
Enable(STATUSDLG );
SetDialogTitle( DLG_STATUS , "复制文件");
SetColor (STATUSBAR , BK_GREEN );
需要说明的是,在调用Enable(STATUSDLG)前,使用Disable(FEEDBACK_FULL)函数可以使信息指示器隐藏。