最新消息:

使用NSIS制作安装程序

nsis 永恒心锁 1311浏览 0评论

首先看一看NSIS的最简单的例子提供了什么,NSIS的Example目录下有一个例子叫做:example1.nsi,用文本编辑器打开它,其内容为:

; 注释说明
;--------------------------------

; 安装程序的名字,该名字会显示在安装程序对话框的标题中
Name "Example1"

; 安装程序的最终文件名,编译后,所有文件被打包生成一个独立的安装程序,名叫example1.exe
OutFile "example1.exe"

; 缺省安装到的目录,一般为C:\Program Files\Example1
InstallDir $PROGRAMFILES\Example1

;--------------------------------
; 页,表示安装程序的对话框一共会变化几页,一般首页是版权信息,然后第二页让用户选择安装目录,
; 接下来安装文件等等。这个例子只有两个页,选择目录,和复制文件。

Page directory
Page instfiles

;--------------------------------
; 每页有若干节(section),各个节内部才真正进行各种操作
Section "" ;由于没有让用户选择需要安装的组件,所以节的名字可以忽略,脚本将从这里真正执行

; 安装程序解包后,将文件复制到OutPath中。本例将文件复制到用户选择的安装目录内
SetOutPath $INSTDIR

; 将与脚本处于同一目录下的文件压缩打包到安装程序中,将来用户安装时,
; 这些文件会被解包复制到OutPath里
File example1.nsi ; 将脚本自己打包

SectionEnd ; 本节结束

这个例子非常简单,他把脚本自己打包进example1.exe中,然后可以发布这个example1.exe,它本身是一个安装程序。用户在自己的计算 机上一旦运行此程序,就会出现一个对话框,让用户选择安装目录,用户选择好后,其会将example1.nsi从包内解出,并复制到用户选择好的安装目录 内。可以用这个脚本做一个测试,有两个方法可以编译脚本生成可执行的安装程序,一个方法时在这个脚本上点鼠标右键,选择“Compile NSIS script”,然后NSIS编译器就会启动,编译脚本打包文件生成example1.exe,第二个方法是在Eclipse内选择菜单 EclipseNSIS | Compile Script,或者使用快键Alt+C,也会生成example.exe。双击这个exe就会运行此安装程序将example.nsi复制安装的指定目 录。

在这个例子的基础上,很容易写出我自己的安装程序。

例子脚本和我的要求有若干不同,主要如下:

我需要从网络下载zip到用户计算机

我需要亲自解开zip包到用户目录

我需要建立桌面和程序快捷方式

我需要建立卸载程序

首先针对第1点要求,经过查阅资料,发现NSIS带有一个下载插件可以完成此功能,其典型用法是:

NSISdl::download http://www.yoursite.org/yourpack.zip "$INSTDIR\yourpack.zip"
Pop $R0 ; 获得下载结果的返回值
StrCmp $R0 success download_ok
SetDetailsView show
DetailPrint "download failed: $R0"
Abort
download_ok:
DetailPrint "download $R0 OK"

上面这段代码的意思是,首先调用NSISdl::download这个插件去网络上下载yourpack.zip文件到用户本地的安装目录下,并且文件名保持不变。是否下载成功的结果放在寄存器变量$R0中,如果下载成果这个变量中的指应该是字符串success,所以StrCmp的作用就是比较返回结果是否成功,如果成功,就跳转到download_ok标记,否则如果下载失败(包括网络问题等等),就打印出失败信息,并且终止安装。

这段代码具有一定的代表性,实际上可以利用它从网络下载多个文件到用户计算机,唯一不同的就是下载地址和保存到本地的文件名。因此可以把它制作成一个函数,如下:

Function DownloadFile
NSISdl::download $remote_zip_file "$INSTDIR\$local_zip_file"
 ; 略...
download_ok:
DetailPrint "download $R0 OK"
FunctionEnd

这个函数的参数,用两个全局变量$remote_zip_file和$local_zip_file传入。调用方法如下:

Var remote_zip_file
Var local_zip_file

StrCpy $remote_zip_file "http://ftp.squeak.org/current_stable/win/Squeak-Win32-3.7.1-VM.zip"
StrCpy $local_zip_file "Squeak-Win32-3.7.1-VM.zip"
Call DownloadFile

NSIS中的变量用Var语句声明,声明时不带有$前缀,使用时,利用$前缀进行引用,这一点和Unix的Shell一样,赋值不采用等号,而使用StrCpy语句,进行字符串复制。

至此第一个需求就可以得到完全满足了,我可以分别下载Squeak的虚拟机和Squeak的映像到用户的计算机,此时的安装脚本如下:

; 安装程序的名称
Name "Squeak 3.9 Installer"

; 安装程序的文件名
OutFile "squeak3.9_win_installer.exe"

; 缺省安装目录
InstallDir "$PROGRAMFILES\Squeak3.9"

;--------------------------------
; 安装对话框包含的页内容
; Pages

Page directory
Page instfiles

;--------------------------------
; 自定义的全局变量
Var remote_zip_file
Var local_zip_file

; 安装Section
Section ""

; 安装输出的目录
SetOutPath $INSTDIR

; 从网络分别下载虚拟机和映像
Call DownloadVM
Call DownloadImage

SectionEnd ; Section结束

; 下载虚拟机
Function DownloadVM
StrCpy $remote_zip_file "http://ftp.squeak.org/current_stable/win/Squeak-Win32-3.7.1-VM.zip"
StrCpy $local_zip_file "Squeak-Win32-3.7.1-VM.zip"
Call DownloadFile
FunctionEnd

; 下载映像
Function DownloadImage
StrCpy $remote_zip_file "http://ftp.squeak.org/3.9/Squeak3.9-RC2-7064.zip"
StrCpy $local_zip_file "Squeak3.9-RC1-7064.zip"
Call DownloadFile
Call ExtractFile
FunctionEnd

; 下载文件的通用函数
Function DownloadFile
NSISdl::download $remote_zip_file "$INSTDIR\$local_zip_file"
Pop $R0 ; Get the return value
StrCmp $R0 success download_ok
SetDetailsView show
DetailPrint "download failed: $R0"
Abort
download_ok:
DetailPrint "download $R0 OK"
FunctionEnd

读者可以使用NSIS编译这个脚本并运行安装程序,它会将虚拟机和映像的zip文件下载到指定目录下(例如C:\Program Files\Squeak3.9\)并结束。下面着手实现第二个需求,将zip包解开。查阅NSIS手册,没有发现类似功能的函数或者插件。其原因是, NSIS在打包时,会自动将普通文件按照zip标准的压缩算法打包,而执行exe时,则自动解包。所以NSIS没有考虑将zip再次打包,以及显式解压缩 zip文件的功能。经过在网络上使用搜索引擎查找,发现了一个第三方插件NsisUnz[3],其可以从这里下载http://home.no.net/nxs/nsis/nsisunz.7z,该文件是7zip格式,可以在这里下载其压缩解压缩工具:http://www.7-zip.org/。解开软件包后,将其中的nsisunz.dll复制到NSIS目录下的Plugins子目录下即可(例如C:\Program Files\NSIS\Plugins\),该Plugin的使用方式为:

nsisunz::UnzipToLog "$INSTDIR\myfile.zip" "$INSTDIR"

若解压缩成功,该命令返回字符串success,否则表示解压缩失败。因此可以仿照上面的下载函数,写出一个通用的解压缩函数,它接受一个zip文件的文件名字符串,然后对其解压缩,如下:

Function ExtractFile
nsisunz::UnzipToLog "$INSTDIR\$local_zip_file" "$INSTDIR"
Pop $R0
StrCmp $R0 "success" unzip_ok
DetailPrint "$R0"
Abort
unzip_ok:
DetailPrint "extract $R0 OK"
Delete "$INSTDIR\local_zip_file"
FunctionEnd

这个解压缩函数一旦成功,就会删除原来下载的zip文件,以节约用户空间。采用这个通用的解压缩函数,可以修改上面的虚拟机和映像下载函数为:

Function DownloadVM
StrCpy $remote_zip_file "http://ftp.squeak.org/current_stable/win/Squeak-Win32-3.7.1-VM.zip"
StrCpy $local_zip_file "Squeak-Win32-3.7.1-VM.zip"
Call DownloadFile
Call ExtractFile
FunctionEnd

Function DownloadImage
StrCpy $remote_zip_file "http://ftp.squeak.org/3.9/Squeak3.9-RC2-7064.zip"
StrCpy $local_zip_file "Squeak3.9-RC1-7064.zip"
Call DownloadFile
Call ExtractFile
FunctionEnd

编译这个改进的脚本并运行,可以发现zip被下载后解开成各自的文件了。这里有一些小问题,有些zip包里,就包含一些文件,但是有些zip包里,却包含目录,例如上面两个zip包解开后,在$INSTDIR下就会出现这样的文件结构:

+Squeak.exe
+SqueakFFIPrims.dll
+Squeak3.9-RC2-7064\
+Squeak3.9-RC2-7064.image
+Squeak3.9-RC2-7064.changes
+SqueakV39.source
+WelcomeSqueak39

而我需要所有这6个文件,都在同一目录下,因此需要使用NSIS的Rename函数移动这些文件。为此修改DownloadImage函数如下:

Function DownloadImage
 ;略...
Call DownloadFile
Call ExtractFile

; 将文件移动到$INSTDIR下,并删除空掉的子目录
Rename "$INSTDIR\Squeak3.9-RC2-7064\Squeak3.9-RC2-7064.changes" "$INSTDIR\Squeak3.9-RC2-7064.changes"
Rename "$INSTDIR\Squeak3.9-RC2-7064\Squeak3.9-RC2-7064.image" "$INSTDIR\Squeak3.9-RC2-7064.image"
Rename "$INSTDIR\Squeak3.9-RC2-7064\SqueakV39.sources" "$INSTDIR\SqueakV39.sources"
Rename "$INSTDIR\Squeak3.9-RC2-7064\WelcomeSqueak39" "$INSTDIR\WelcomeSqueak39"
RMDir "$INSTDIR\Squeak3.9-RC2-7064"
FunctionEnd

至此,第二个需求就满足了,为了方便用户使用,下面实现第3个需求——在桌面和程序菜单中建立Squeak的快捷方式,这样用户只需要双击这些快捷方式的图标,就可以运行Squeak了。squeak的运行方式是按照这样的命令行:

squeak.exe squeak_iamge_filename.image

但是Windows的目录名可能会带有空格,例如C:\ Program Files\Squeak3.9\中,Program和Files之间就存在一个空格,这样squeak.exe会把空格前的部分,C:\Program 当作映像文件名,而把后面的Files\Squea…当作参数,这就出现了歧义。为此需要把路径用””括起来。但是NSIS中,会把””忽略掉,办法 是在””外再括一层”。此后就可以使用NSIS的CreateShortCut函数创建快捷方式了。当必要的文件下载并解压缩成功后就进行这一步的内 容,为此修改Section如下:

Section ""

SetOutPath $INSTDIR

Call DownloadVM
Call DownloadImage

; 创建快捷方式
CreateDirectory "$SMPROGRAMS\Squeak\3.9\"
CreateShortcut "$SMPROGRAMS\Squeak\3.9\squeak.lnk" $INSTDIR\Squeak.exe
'"$INSTDIR\Squeak3.9-RC2-7064.image"'
CreateShortcut "$DESKTOP\squeak3.9.lnk" $INSTDIR\Squeak.exe
'"$INSTDIR\Squeak3.9-RC2-7064.image"'

Exec '$INSTDIR\Squeak.exe "$INSTDIR\Squeak3.9-RC2-7064.image"' ; 安装成功后自动运行Squeak
SetAutoClose true ; 安装结束后自动关闭安装程序
SectionEnd

为了进一步增强用户友好性,还在安装成功后,自动运行Squeak并关闭安装程序。

最后,良好的安装程序还应该提供卸载功能,并干净地清除用户计算机上的内容。为此可以利用NSIS提供的 UnistPage命令创建卸载程序页面,并提供一个名叫Uninstall的Section实际进行卸载工作。对于Squeak这点卸载工作的内容包 括,删除程序文件,删除快捷方式等,其实现如下:

; 用于安装的页

Page directory
Page instfiles

; 用于卸载的页
UninstPage uninstConfirm
UninstPage instfiles
;--------------------------------
; 略...

Section "Uninstall"
 ; 删除文件
Delete "$INSTDIR\*.image"
Delete "$INSTDIR\*.changes"
Delete "$INSTDIR\*.dll"
Delete "$INSTDIR\*.sources"
Delete "$INSTDIR\*.exe"
Delete "$INSTDIR\WelcomeSqueak39"
RMDir "$INSTDIR"

; 删除快捷方式
Delete "$SMPROGRAMS\Squeak\3.9\squeak.lnk"
Delete "$DESKTOP\squeak3.9.lnk"
RMDir "$SMPROGRAMS\Squeak\3.9"

SetAutoClose true
SectionEnd

提供Uninstall功能的脚本,需要在安装的最后一步身成uninstall.exe供用户日后使用,为此在安装Section最后增加这样一行:

CreateShortcut "$SMPROGRAMS\Squeak\3.9\uninstall.lnk" "$INSTDIR\uninstall.exe"
 WriteUninstaller "$INSTDIR\uninstall.exe"

并在Uninstall的Section中增加对卸载快捷方式的删除动作:

Delete "$SMPROGRAMS\Squeak\3.9\uninstall.lnk"

至此一个完整的安装程序就制作完成了

永恒心锁,版权所有丨如未注明,均为转载丨本网站采用BY-NC-SA协议进行授权

转载请注明:永恒心锁-分享互联网 » 使用NSIS制作安装程序

您必须 登录 才能发表评论!