NSIS脚本.docx
《NSIS脚本.docx》由会员分享,可在线阅读,更多相关《NSIS脚本.docx(19页珍藏版)》请在冰豆网上搜索。
NSIS脚本
NSIS(NullsoftScriptableInstallSystem)是一个OpenSource的Windows系统下安装程序制作程序。
它提供了安装、卸载、系统设置、文件解压缩等功能。
这如其名字所指出的那样,NSIS是通过它的脚本语言来描述安装程序的行为和逻辑的。
NSIS的脚本语言和通常的编程语言有类似的结构和语法,但它是为安装程序这类应用所设计的。
NSIS脚本通常以nsi为扩展名,支持include功能,头文件扩展名为nsh。
NSIS的主要特点是:
* 开销小,一个完整功能的安装程序仅需要34k的额外开销。
* 支持大多数Windows平台,包括:
Windows9.x,WindowsNT,Windows2000,WindowsXP,Windows2003
* 支持三大压缩算法:
Zlig,BZips,LZMA
* 支持脚本
* 支持多语言
* 支持安装界面定制
* 提供可扩展的插件接口
* 支持网络安装、补丁
* 支持无人值守的安装模式
* 此外,NSIS的license允许任何用途免费使用。
开发一个NSIS的安装程序通常有以下几步:
1.确定安装的功能和界面元素
2.编写NSIS脚本
3.使用NSIS提供的makensis或者makensisw程序,将步骤2编写的脚本编译成可执行的安装程序
4.调试安装程序,如果有问题退到第二步重复
随着NSIS的流行,有一些第三方的NSIS脚本开发环境出现了,如HMNISEdit,VenisIX,前者是完全开源的,后者仅对个人和非商业用途免费。
在这些集成开发环境下,步骤2,3可以方便的组合在一起。
NSIS脚本的结构
NSIS脚本(下称nsi脚本)主要包含安装程序属性、页面、区段、函数。
属性用来定义安装程序的行为和界面风格,这些属性大部分是编译时刻属性,即不能在运行时刻改变。
页面是指安装程序的向导页面,示例:
Pagelicense
Pagecomponents
Pagedirectory
Pageinstfiles
UninstPageuninstConfirm
UninstPageinstfiles
区段是对应某种安装/卸载选项的处理逻辑,该段代码仅当用户选择相应的选项才被执行。
卸载程序的区段名用"un."作为前缀,示例如下:
Section"InstallerSection"
SectionEnd
Section"un.UninstallerSection"
SectionEnd
在区段中可以使用很多指令用来完成诸如解压缩文件、读写注册表、创建目录、创建快捷方式等任务,但最常用的指令是SetOutPath和File,前者用于指定目的位置,后者用于指定文件。
示例:
Section"MyProgram"
SetOutPath$INSTDIR
File"MyProgram.exe"
File"Readme.txt"
SectionEnd
区段名的修饰符/o表示该区段默认不选上,-表示隐藏区段(匿名区段也是隐藏区段),!
表示需要粗体显示的区段。
SectionIn表示该区段和安装类型之间的关系:
SectionIninsttype_index[insttype_index]...[RO]
RO修饰符表示不可修改。
子区段用于包含多个区段
SubSection[/e]Caption[subsection_nameindexoutput]
修饰符/e用于该子区段的所有区段是否默认展开。
函数包含了模块化的安装逻辑,在nsi脚本中函数分为两种:
用户自定义函数和回调函数。
用户自定义函数仅当是Call指令调用时才被执行,如果函数体中没有abort语句,则安装程序执行完了用户自定义函数,继续运行Call语句和指令。
用户自定义函数的语法如下:
Function<函数名>
#somecommands
FunctionEnd
函数的调用则使用以下语法:
Call<函数名>
可见无论是函数的定义还是函数的调用都没有参数传递。
通常nsi的参数传递是通过堆栈操作Pop,Push和20个寄存器变量$0~$9,$R0~$R9进行的。
也可以通过全局变量完成参数传递。
如:
Varinput;
Varoutput;
Sectionbla
DeteailPrint"inputis$input$\n"
Callsquare
DeteailPrint"squareof$inputis$output$\n"
SectionEnd
Functionsquare
output=input^2
FunctionEnd
回调函数则是由在特定的时间点触发的程序段。
常用的回调函数如.onInit:
Function.onInit
MessageBoxMB_YESNO"ThiswillinstallMyProgram.Doyouwishtocontinue?
"IDYESgogogo
Abort
gogogo:
FunctionEnd
NSIS对于安装逻辑定义以下回调函数:
.onGUIInit、.onInit、.onInstFailed、.onInstSuccess、.onGUIEnd、.onMouseOverSection、.onRebootFailed、.onSelChange、.onUserAbort、.onVerifyInstDir
NSIS对于卸载逻辑定义以下回调函数:
un.onGUIInit、un.onInit、un.onUninstFailed、un.onUninstSuccess、un.onGUIEnd、un.onRebootFailed、un.onUserAbort
nsi脚本的变量定义
nsi脚本的变量定义用Var关键字,后跟变量名,变量是全局的并且是大小写敏感的。
变量引用时需要加上前缀$。
除了用户自定义的变量外,nsi脚本中与定义寄存器变量$0~$9,$R0~$R9用于参数传递,以及系统变量用于特定用途,这些变量主要有:
$INSTDIR,$OUTDIR,$CMDLINE,$LANGUAGE这些变量都是可写的。
$PROGRAMFILES,$COMMONFILES,$DESKTOP,$EXEDIR,${NSISDIR},$WINDIR,$SYSDIR,$TEMP,$STARTMENU,$SMPROGRAMS,$SMSTARTUP,$QUICKLAUNCH,$DOCUMENTS,$SENDTO,$RECENT,$FAVORITES,$MUSIC,$PICTURES,$VIDEOS,$NETHOOD,$FONTS,$TEMPLATES,$APPDATA,$PRINTHOOD,$INTERNET_CACHE,$COOKIES,$HISTORY,$PROFILE,$ADMINTOOLS,$RESOURCES,$RESOURCES_LOCALIZED,$CDBURN_AREA,$HWNDPARENT,$PLUGINSDIR
nsi脚本中可用于调试的系统函数有MessageBoxes,DetailPrint,Dumpstate。
nsi脚本的编译器指令
nsi脚本的编译器指令主要指仅在编译时刻执行的命令。
这些命令主要用来包含文件、条件化编译、定义常量、定义宏等。
定义常量和宏是编译器指令最主要应用。
定义常量的示例:
!
defineVERSION"1.0.3"
Name"MyProgram${VERSION}"
OutFile"MyProgramInstaller-${VERSION}.exe"
定义宏的示例:
!
macroMyFuncUN
Function${UN}MyFunc
Call${UN}DoRegStuff
ReadRegStr$0HKLMSoftware\MyProgramkey
DetailPrint$0
FunctionEnd
ModernUI
ModernUI是感观上模仿最新的Windows系统的界面风格,它由欢迎页面、结束页面和其他向导页面构成。
插件
nsi支持插件,通过插件可以方便的扩展NSIS安装程序的功能。
NSIS插件是用C++,Delphi等语言编写的dll,在nsi脚本中调用nsi中的函数使用如下语法:
DLLName:
:
FunctionName"参数1""参数2""参数3"
示例1:
nsExec:
:
ExecToLog'"${NSISDIR}\makensis.exe"/CMDHELP'
执行makensis.exe命令,显示该命令用法。
示例2:
InstallOptions:
:
dialog"$PLUGINSDIR\test.ini"
显示对话框
示例3:
NSISdl:
:
download$R0
下载文件
NSIS搜索插件的策略
默认情况下NSIS在其安装目录的子目录Plugins中搜索插件,用户可以使用!
addplugindir指定增加插件的目录位置。
nsi脚本的基本语法
注释
单行注释用井号"#"或分号";",跨行注释用可以用c/C++中注释语法。
数据类型
数字
数字常量可以用十进制、十六进制(0x为前缀)、八进制(0为前缀)表示,颜色用类似html的中RGB表示法,但去井号"#"。
字符串
字符串常量可以用引号引用,转意字符用"$\"作前缀。
美元符号、常用转意字符换行、回车、制表符的nsi语法表示分别为:
$$,$\n,$\r,$\t
续行符
nsi脚本用行尾的反斜杠"\"表示下一行和当前行逻辑上是同一行
默认头文件
如果在makensis同目录下有nsisconf.nsh文件,该文件会被自动包含,除非编译时指定/NOCONFIG选项
标号
nsi使用GOTO语句和IfErrors,MessageBox,IfFileExists及StrCmp进行程序控制流表示,标号是这些语句的目标语句。
标号定义的语法:
标号:
语句
标号必须定义在函数和区段中,其作用范围仅限于定义它的区段或函数。
以点号"."开头的标号是全局标号。
相对跳转
nsi脚本常常使用相对跳转表示条件分枝,其语法是[+-][1-9],加号表示从当前位置往前跳转,减号则表示从当前位置往后跳转。
数字表示跳转的语句条数。
示例:
Goto+4
MessageBoxMB_OK"Thefollowingmessagewillbeskipped"
Goto+3
MessageBoxMB_OK"Youwillnevereverseethismessagebox"
Goto-3
MessageBoxMB_OK"Done"
页面
向导页面是NSIS安装程序中最重要的界面元素,在nsi脚本中可以使用NSIS内置页面或者定制界面,通过脚本可以指定页面的顺序、显示样子和行为。
Page指令用来定义安装程序中的页面,UninstPage用来定义,此外PageEx指令提供类是功能,但提供更多选项。
页面的顺序和它在nsi脚本中出现的次序一致。
示例:
Pagelicense
Pagecomponents
Pagedirectory
Pageinstfiles
UninstPageuninstConfirm
UninstPageinstfiles
规定安装程序首先显示license页面,然后显示components选择页面,接着显示安装目录选择页面。
页面选项
不同的页面有不同的选项:
Licensepage有LicenseText,LicenseData,LicenseForceSelection;
Componentsselection页面有ComponentText;
Directoryselection页面有DirText,DirVar(仅能在PageEx中使用),DirVerify;
Un/Installationlog页面有DetailsButtonText,CompletedText;
Uninstallconfirmation页面有DirVar(仅能在PageEx中使用),UninstallText
对于内置的Page,NSIS支持三个回调函数用于定制界面和验证,对于自定义页面NSIS支持两个回调函数。
Page指令语法
PagelicensecomponentsdirectoryinstfilesuninstConfirm)[pre_function][show_function][leave_function]
或者:
Pagecustom[creator_function][leave_function][caption]
示例:
PagelicenseskipLicense""stayInLicense
PagecustomcustomPage""":
custompage"
Pageinstfiles
FunctionskipLicense
MessageBoxMB_YESNO"Doyouwanttoskipthelicensepage?
"IDNOno
Abort
no:
FunctionEnd
FunctionstayInLicense
MessageBoxMB_YESNO"Doyouwanttostayinthelicensepage?
"IDNOno
Abort
no:
FunctionEnd
FunctioncustomPage
GetTempFileName$R0
File/oname=$R0customPage.ini
InstallOptions:
:
dialog$R0
Pop$R1
StrCmp$R1"cancel"done
StrCmp$R1"back"done
StrCmp$R1"success"done
error:
MessageBoxMB_OKMB_ICONSTOP"InstallOptionserror:
$\r$\n$R1"
done:
FunctionEnd
UninstPage指令语法
UninstPagecustom[creator_function][leave_function][caption]
OR
UninstPage(licensecomponentsdirectoryinstfilesuninstConfirm)[pre_function][show_function][leave_function]
PageEx语法
PageEx使用嵌套结构,比如:
PageExlicense
LicenseText"Readme"
LicenseDatareadme.rtf
PageCallbackslicensePrelicenseShowlicenseLeave
PageExEnd
常用的nsi指令
nsi大致可以分为基本指令、注册表及ini操作指令、通用指令、流程控制指令、文件操作指令、卸载指令、字符串处理指令、多语言支持指令、重启指令。
以下是常用的基本指令:
Delete
Delete[/REBOOTOK]file
Exec
Execcommand
ExecShell
ExecShellactioncommand[parameters][SW_SHOWNORMALSW_SHOWMAXIMIZEDSW_SHOWMINIMIZEDSW_HIDE]ExecShell"open"示例
ExecWait
ExecWaitcommand[user_var(exitcode)]
示例:
ExecWait'"$INSTDIR\someprogram.exe"'
ExecWait'"$INSTDIR\someprogram.exe"'$0
DetailPrint"someprogramreturned$0"
File
File[/nonfatal][/a]([/r][/xfilewildcard[...]](filewildcard)[...]/oname=file.datinfile.dat)
/r选项用作递归模式,/x用于排出文件
示例:
Filesomething.exe
File/asomething.exe
File*.exe
File/r*.dat
File/rdata
File/oname=$TEMP\temp.datsomefile.ext
File/nonfatal"afilethatmightnotexist"
File/r/xCVSmyproject
File/r/x*.res/x*.obj/x*.pchsource
Rename
Rename[/REBOOTOK]source_filedest_file
RMDir
RMDir[/r][/REBOOTOK]directory_name
NSISSystem插件
(C)brainsucker(NikMedved),2002
内容表
*简介
*有效函数
o内存相关函数
o调用函数
o64位函数
*FAQ
简介
System插件给开发者提供了从外部DLL调用任何函数的功能。
例如,你可以用它来调用GetLogicalDriveStrings来获取用户电脑里的驱动器列表。
System插件也允许开发者来分配、释放、复制内存;与COM对象相配合并执行64位整数数学操作。
为了理解System插件强烈推荐首先有程序方面的知识。
档案里的一些使用例子
*Getlocaltime
*RegisterconduitswithPalmHotSync
*Getfreememory
*ReadREG_MULTI_SZ
*Getdiskserialnumber
有效函数
内存相关函数
*AllocSIZE
分配SIZE字节并返回一个内存地址到堆栈上。
使用例子
System:
:
Alloc64 Pop$0 DetailPrint"64字节分配在$0" System:
:
Free$0
*Copy DESTINATIONSOURCE
从SOURCE复制SIZE字节到DESTINATION。
如果不指定SIZE,SOURCE的大小必须使用GlobalSize。
这意味着如果你不使用System:
:
Alloc,System:
:
Call或GlobalAllocCopies来分配SOURCE,你就必须指定SIZE。
使用例子
#分配一个缓冲区并把‘测试字串'压入 System:
:
Call"*(&t1024'测试字串',i5)i.s" Pop$0 #复制到一个自动创建的缓冲区 System:
:
Copy0$0 Pop$1 #在$1缓冲区获取字串和整数 System:
:
Call"*$1(&t1024.r2,i.r3)" #释放缓冲区 System:
:
Free$1 #输出结果 DetailPrint$2 DetailPrint$3 #复制到我们自己的缓冲区 System:
:
Alloc1028 Pop$1 System:
:
Copy$1$0 #在$1缓冲区获取字串和整数 System:
:
Call"*$1(&t1024.r2,i.r3)" #释放 System:
:
Free$0 System:
:
Free$1 #输出结果 DetailPrint$2 DetailPrint$3
*FreeADDRESS
释放ADDRESS.
使用例子
System:
:
Alloc64 Pop$0 DetailPrint"64字节分配在$0" System:
:
Free$0
*Store"OPERATION[OPERATION[OPERATION...]]"
执行堆栈操作。
一个操作可以从NSIS堆栈压入或弹出一个已注册的变量或者压入弹出所有系统已注册的变量($0-$9和$R0-$R9)。
操作可以由任何字符分割。
有效的操作
o要压入$#,使用p#,#是一个从0到9的数字。
o要弹出$#,使用r#,#是一个从0到9的数字。
o要压入$R#,使用P#,#是一个从0到9的数字。
o要弹出$R#,使用R#,#是一个从0到9的数字。
o要压入$0-$9和$R0-$R9到系统私有的堆栈,使用s或S。
o要从系统私有的堆栈弹出$0-$9和$R0-$R9使用l或L。