上一页 | 目录 | 下一页

2.3 脚本结构

一个 NSIS 脚本应该包括安装程序属性和区段、函数。你也可以使用编译器命令在编译的时候进行指定。所必需的是 OutFile 指令(该命令告诉 NSIS 安装程序输出路径) 和一个区段。

2.3.1 安装程序属性

安装程序属性确定你的安装程序的性能、外观和习惯。由这些属性你可以更改安装的时候显示的文本、安装类型的数量等。这些命令大多数在运行时仅被设定并且不能更改。

其他基本的指令为 NameInstallDir

欲了解更多安装程序属性信息,请查看 安装程序属性

2.3.2 页面

一个非静默安装程序需要向导页面来指导用户运行安装程序。你可以通过 Page 命令(或更多高级设置如 PageEx)。一个典型的设置像这样:

Page license
Page components
Page directory
Page instfiles
UninstPage uninstConfirm
UninstPage instfiles

对于安装程序,典型的页面设置应该显示许可协议页面,允许选择要安装的组件,允许选择要安装的目录,最后安装选择的组件。对于卸载程序,应该显示卸载确认页面,然后执行卸载。

2.3.3 区段

在一个普通的安装包里用户需要安装许多东西。例如在 NSIS 发行安装程序里你可以选择安装源码、附加插件、脚本样例或其他。以上每个组件都有自己的一段代码。 当用户选择了安装该组件,那么安装程序就会执行对应的代码。在脚本里,这些代码称为区段。在组件页面里每个区段对应一个组件。区段名就是显示的组件名,如果组件被选中则区段代码将会被执行.你可以只使用一个区段来构建安装程序,但是如果你想要使用组件页来让用户选择可选的安装组件,你必须使用一个以上的区段。

卸载程序也可以有多个区段。卸载程序区段名前要加上前缀 'un.' 。例如:

Section "Installer Section"
SectionEnd

Section "un.Uninstaller Section"
SectionEnd

在区段里使用的指令和安装程序属性指令不一样,他们在用户电脑运行环境里执行。这些指令可以解压文件读取和写入注册表、INI文件或普通文件,创建目录,创建快捷方式和更多功能。你可以在 指令用法说明 找到更多。

更多的基本用法说明 SetOutPath 告诉安装程序要把文件输出到哪里和要解压哪些 文件

例子:

Section "My Program"
  SetOutPath $INSTDIR
  File "My Program.exe"
  File "Readme.txt"
SectionEnd

欲了解更多区段信息,请查看 区段

2.3.4 函数

函数和区段类似,也包含了代码。区段和函数所不同的是他们被调用的形式。一共有两种函数类型:用户函数和回调函数。

用户函数可以从一个区段里或另一个函数使用 Call 指令。用户函数不能直接执行而只能调用它。在函数内的代码都会被执行然后安装程序会继续执行 Call 指令后面的指令,除非你在函数里面使用了中止指令。用户函数当你在安装程序里需要多次、多处使用一组指令的时候非常有用。如果你把代码放到一个函数里你可以节省拷贝的次数并且更容易的去修改、更新代码。

回调函数可以在某些定义事件之前被调用比如当安装程序开始运行时。回调是可选的。例如你想欢迎用户使用你的安装程序你可以定义一个名为 .onInit 的函数。 NSIS 编译器会由它的名字知道它是一个回调函数并且会在安装程序开始时调用它。

Function .onInit
  MessageBox MB_YESNO "即将安装我的程序,要继续吗?" IDYES gogogo
    Abort
  gogogo:
FunctionEnd

Abort 在回调函数里有特殊含义。每个回调函数都有它自己的含义,欲了解更多信息,请查看 回调函数。 在上面的例子中 Abort 告诉安装程序停止初始化安装并立即退出。

欲了解更多函数信息,请查看 函数

2.3.5 脚本的工作方式

2.3.5.1 逻辑代码结构

条件判断或执行代码循环可以使用 StrCmp, IntCmp, IfErrors, Goto 和其它来实现,但是还有更方便直观的方式来实现。头文件 LogicLib 提供了很多简单的宏便于构造复杂的逻辑结构(条件或联合逻辑判断)。这些语法在 LogicLib.nsh 做了解释,并且这些语法很像其它的初学者和高级用户熟悉的语言。

例如, 对变量值的判断(不使用 LogicLib)应该像这样:

StrCmp $0 'some value' 0 +3
  MessageBox MB_OK '$$0 is some value'
  Goto done
StrCmp $0 'some other value' 0 +3
  MessageBox MB_OK '$$0 is some other value'
  Goto done
# else
  MessageBox MB_OK '$$0 is "$0"'
done:

然而,如果使用 LogicLib 的话代码将更具有可读性并更容易理解,当然也更容易维护,看起来就象下面的代码:

${If} $0 == 'some value'
  MessageBox MB_OK '$$0 is some value'
${ElseIf} $0 == 'some other value'
  MessageBox MB_OK '$$0 is some other value'
${Else}
  MessageBox MB_OK '$$0 is "$0"'
${EndIf}

也可以用 switch 来实现相同的效果,像下面的那样:

${Switch} $0
  ${Case} 'some value'
    MessageBox MB_OK '$$0 is some value'
    ${Break}
  ${Case} 'some other value'
    MessageBox MB_OK '$$0 is some other value'
    ${Break}
  ${Default}
    MessageBox MB_OK '$$0 is "$0"'
    ${Break}
${EndSwitch}

支持多个条件判断。下面的例子当 $0 和 $1 为空的时候通知用户:

${If} $0 == ''
${AndIf} $1 == ''
  MessageBox MB_OK|MB_ICONSTOP 'both are empty!'
${EndIf}

LogicLib 不需要格外的跳转标记,当然也没有了标记同名的冲突,并且当代码改动的时候不再需要每次都修改相对跳转。

LogicLib 也可以使用简单的循环,下面的例子将会从 0 到 5 循环:

StrCpy $R1 0
${While} $R1 < 5
  IntOp $R1 $R1 + 1
  DetailPrint $R1
${EndWhile}
${For} $R1 1 5
  DetailPrint $R1
${Next}
StrCpy $R1 0
${Do}
  IntOp $R1 $R1 + 1
  DetailPrint $R1
${LoopUntil} $R1 >= 5

要使用 LogicLib, 必须在脚本的顶部或是需要使用该命令的前一行包含如下头文件:

!include LogicLib.nsh

更多的例子请看 LogicLib.nsi

2.3.5.2 变量

你可以用 Var 命令来声明自己的变量 ($VARNAME) 。变量是全局的并且可以在任何区段或函数中使用。

声明并使用一个用户变量:

Var BLA ;声明变量

Section bla

  StrCpy $BLA "123" ;现在你可以使用该变量 $BLA

SectionEnd

另外堆栈可以用来作临时存储。使用 PushPop 命令来访问堆栈。 Push 把一个值添加到堆栈,Pop 移除一个值并且设置该变量。

对于公共代码,这里有 20 其他可写的变量 (如 $0 和 $R0))。这些静态的变量你不需要声明并且你不应使任何名字与之相冲突。如果你想在公共代码里使用这些变量,可以把原始的值存储在堆栈并随后恢复原始值。

在调用函数后,变量包含原来的值。需要注意使用多个变量时的次序(后进先出):

Function bla

  Push $R0
  Push $R1

    ...code...

  Pop $R1
  Pop $R0

FunctionEnd

2.3.5.3 调试脚本

如果你要用 NSIS 实现更多的功能那么你的脚本就会变得更复杂。这将会增加出错的可能性,特别是当你使用了很多变量的时候。以下将有可能会对你的脚本调试有所帮助。使用 MessageBoxesDetailPrint 来显示变量内容。要简要观察所有变量,你应该使用插件 DumpState 。默认情况下安装程序会把所有的操作显示在操作记录窗口上,你可以把记录的文本复制到剪贴板(Ctrl+C 或使用鼠标右键的 "复制详情到剪贴板")。当然也有方法把它直接写到一个文件里,查看 这里

2.3.6 脚本的执行

当用户运行安装程序或卸载程序,页面将按照脚本中定义的次序显示。当到了安装页面的时候,将执行选中的区段(组件)并按照在脚本中定义的次序执行。如果没有显示组件选择页面,那么所有的区段都会被执行除了在脚本里没有反选或不明原因禁用的区段。

除了区段里的代码,还有一些在回调函数里的代码也会被执行。如果他们被定义的话,可能将会在区段之前就执行了。例如 .onInit 回调函数就最先被执行。或者在页面显示过程中执行某些 页面回调函数

2.3.7 编译器命令

编译器命令会在你编译时的电脑上执行。他们可以用于条件编译,包含头文件,执行应用程序,改变工作目录等。最常见的用法是定义,定义是编译时的常量。你可以定义你的产品版本号并在你的脚本里使用。例如:

!define VERSION "1.0.3"
Name "My Program ${VERSION}"
OutFile "My Program Installer - ${VERSION}.exe"

欲了解更多关于定义信息,请查看 条件编译

另一种较常见的是使用宏。宏用于在编译时插入代码,依赖于定义并使用定义的值。宏命令是在编译时插入代码。这样你只需要写一个通用的代码并只需要作为小的更改就可以多次的使用。例如:

!macro MyFunc UN
Function ${UN}MyFunc
  Call ${UN}DoRegStuff
  ReadRegStr $0 HKLM Software\MyProgram key
  DetailPrint $0
FunctionEnd
!macroend

!insertmacro MyFunc ""
!insertmacro MyFunc "un."

宏帮助你避免在安装程序和卸载程序写入重复的代码。上面两个 !insertmacros 插入了两个函数,一个是 MyFunc 用于安装程序,另一个是 un.MyFunc 用于卸载程序,但他们做的是同一件事。

欲了解更多信息,请查看 编译时命令

上一页 | 目录 | 下一页