NSIS 从入门到编写完整打包脚本

您所在的位置:网站首页 开源Updater介绍 NSIS 从入门到编写完整打包脚本

NSIS 从入门到编写完整打包脚本

2023-10-12 11:47| 来源: 网络整理| 查看: 265

NSIS是功能强大的安装包制作工具,但其高质量的教程稀少,上手困难。且官方文档罗列知识点,很难组合成实际用法。作者认为比起手册式写法,更需要从使用的角度出发的文章,在过程中引入概念和用法,更符合人学习的思维。

1. 开始使用 1.1 简介

来自官方的介绍:

NSIS (Nullsoft Scriptable Install System) 是 Windows 下的一个安装程序创建工具,它允许程序员来创建这样的安装程序。

NSIS 创建的安装程序能够安装、卸载、设置系统设置、解压文件等等。 因为它基于脚本文件,你可以完全的控制安装程序的每一部分。 脚本语言支持变量、函数、字串操作,就像一个普通的程序语言一样 - 但是设计来创建安装程序。 即使有那么多的特性, NSIS 仍然是最小的安装程序系统。在默认选项下,它仅增加了 34 KB 的开销。

1.2 NSIS常用特性 脚本化,支持多文件的代码组织 注册表编辑、执行脚本、修改环境变量 较小的安装压缩大小 较为美观的界面,还支持自定义界面 插件系统 支持网络安装 支持做补丁安装 1.3 安装

在官网下载NSIS安装包。安装后将安装路径加入系统环境变量,如:C:\Program Files (x86)\NSIS。在命令行中输入nsis或makensis测试是否工作。

1.4 脚本示例项目

本文同时提供有一个示例项目,它包含在文档中内容的代码示例,包括几个示例项目,可以对照脚本与文章内容,会更容易理解到如何使用NSIS。

项目对应关系如下表:

项目主文件介绍base/base/installer.nsi包含安装脚本的主体结构,与本文章节3对应install/install/installer.nsi在base的基础上增加安装与卸载的内容,与本文的章节4对应 2. 开始编写一个脚本

创建代码文件

NSIS脚本文件的拓展名是.nsi,我们创建一个 installer.nsi,文件名可以随意取。一般为要打包的程序名称,本文示例为了不产生误解取为 installer。

.nsi文件可以使用任何文本编辑器打开,建议使用vscode打开,安装NSIS的插件编写更加方便。

在文件中添加一个安装区段

installer.nsi

Section "Section1" SEC01 SectionEnd

这里引入一个区段的概念,区段内包含安装或卸载过程的逻辑,用于组织不同的安装内容,有以下重要特点:

必须至少有一个区段,不然程序没有安装的内容 区段默认为安装区段,un.开头的区段为卸载区段, 区段可不设置区段名,或者在名称前加短横线-,这样让其在安装过程中不可见,悄悄安装 区段可以是一个空区段

区段由Section和SectionEnd组成,Section行中参数依次为:区段名、区段的唯一标识码。代码中Section1为区段名,SEC01为区段的唯一标识码,用于其他地方操作区段的标识使用。官方文档

添加输出文件和安装代码

installer.nsi

有了安装区段后,还必须设置一个输出文件,告诉NSIS编译器安装包的输出位置。在installer.nsi的开头加入下面这行代码:

OutFile "MyApp_Setup.exe" Section "Section1" SEC01 SetOutPath "$INSTDIR" File "..\myapp\MyApp.exe" SectionEnd

这里使用了一个属性命令OutFile,它是必须有的命令。指定生成的安装包的路径和名称,可以设置相对路径与绝对路径。当只有名称时,生成文件与.nsi文件同目录。

OutFile 是必须的命令,指定编译器输出安装包的路径。使用方式如下:

OutFile [路径]安装程序名称.exe eg. OutFile "MyApp.exe" ;只指定程序名称的情况下,安装文件输出到.nsi脚本同目录下 OutFile "D:\installer\MyApp.exe" ;指导路径的情况下,输出到指定路径下

💡Tip1: 这里用到了命令,命令分为安装程序属性命令和编译器命令

💡Tip2: 这里用到了;,它和#一起在NSIS的脚本中作为注释符,后跟注释内容

安装程序属性命令用于指定安装包相关的属性值,编译器命令用于指定编译器在编译时的选项。

Section中使用了两个指令SetOutPath和File,前者用于指定后续指令的输出目录,后者用于指定安装包在打包时要包含进那些文件,且在安装时要将这些文件安装到前者指定的目录中去。

Tip: 这里用到的两个指令都是基础指令,指令还有很多种类型,它们都需要包含在区段或函数中才能运行。与命令的区别是,命令都在编译安装包时运行,指令在安装或卸载时运行。

🌟知识点🌟

SetOutPath 使用了一个值 [INSTDIR](https://www.nsisfans.com/help/Section4.2.html#4.2.2),这是一个已经被声明的变量。变量用来临时存储一些值,它可以被改变,在变量名前面加上``符号使用,自定义的变量要自己声明。查看文档变量了解更多。

💡Tip: 这里有个注意点,$INSTDIR 前后用引号包起来了。这是因为在NSIS里,数值和字符串用法都是一样。区别的方式就是字符串值在使用时,用引号包起来,不然默认会被当成数值处理。

执行脚本编译安装包

这样就完成了一个最简单的脚本文件,在命令行中执行:

> makensis ./installer.nsi

注:如果提示没有找到makensis,那你可能是没有设置nsis的环境变量

3. 完善安装包主要结构

本章代码在示例项目中对应base项目的installer.nsi,可以将本章内容与代码对照,会更容易理解到如何使用NSIS。

3.1 安装程序属性

安装程序属性主要控制安装程序的:程序信息、图标、默认安装目录、外观、安装界面文本、页面、包含的文件。

这里主要介绍常用到的属性(如下例),更多的属性设置在官方文档中可以查到。

# define const value !define PRODUCT_NAME "My app" !define PRODUCT_SHORT_NAME "MyApp" !define PRODUCT_VERSION "1.0" !define PRODUCT_BUILD_VERSION "1.0.0.0" !define PRODUCT_PUBLISHER "My company, Inc." !define PRODUCT_COPYRIGHT "Copyright (c) 2023 My company Inc." !define PRODUCT_WEB_SITE "http://www.mycompany.com" # info of installer Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" ; set name of installer execute OutFile "MyApp_Setup.exe" ; set file name of compiler out Icon "..\myapp\nsis.ico" InstallDir "C:${PRODUCT_SHORT_NAME}" ; set the default install dir # info of installer execute file VIAddVersionKey ProductName "${PRODUCT_NAME} Installer" ; product name VIAddVersionKey ProductVersion "${PRODUCT_VERSION}" ; product version VIAddVersionKey Comments "${PRODUCT_NAME}" ; description VIAddVersionKey CompanyName "${PRODUCT_PUBLISHER}" ; compnay name VIAddVersionKey LegalCopyright "${PRODUCT_COPYRIGHT}" ; copyright VIAddVersionKey FileVersion "${PRODUCT_BUILD_VERSION}" ; file version VIAddVersionKey FileDescription "${PRODUCT_NAME} Installer" ; file description VIProductVersion "${PRODUCT_BUILD_VERSION}" ; product verion(actual replace FileVersion)

常用的设置安装属性的命令都是编辑时命令,更多属性和特殊用法查看安装程序属性:

🌟基础语法🌟

!define是定义常量值的命令,它是一个编译时命令。常量定义好后不能改变值,定义后的常量使用 ${常量名}进行使用。如示例代码中的:${PRODUCT_NAME}

添加安装程序信息

Name 设置安装程序的名称。

Name "My Application" Name "Jhon & Jack App" "Jhon && Jack App"

注意:当名称中使用了&符号时,就需要传入第二个参数“双&名称”,将第一个参数名称中的&用两个&表示。

Icon 设置安装程序的图标,图标文件后缀名为.ico。

Icon [图标文件路径]

InstallDir 设置默认安装目录。

InstallDir [路径] eg: InstallDir "$PROGRAMFILES\YourApp" InstallDir "C:\YourApp"

💡Tip: $PROGRAMFILES 是一个NSIS定义的变量的常量,说是常量其实就是NSIS的提供的系统环境变量,用于获取各种路径。使用方式与变量相同,查看变量的常量章节了解可以使用的值。

安装程序版本信息类

VIAddVersionKey与VIProductVersion共同决定安装程序的版本信息,前方示例代码设置的属性在文件信息上看就是这样了。官方文档

3.2 添加安装界面

大部分的安装包都是有着完善的安装过程,它往往由几个界面组成:

欢迎界面 license界面 安装路径选择界面 安装过程界面 安装完成界面 3.2.1 古典(过气)安装界面

由于古典界面过于的古典,所以简单介绍一下,应该基本不会在当代的主流安装UI中被需要。

使用Page命令指定安装过程要包含的界面,UninstPage命令指定卸载过程界面,通过调整前后顺序来排列安装界面的顺序。中文文档

# 安装界面 Page license Page components Page directory Page instfiles # 卸载界面 UninstPage uninstConfirm UninstPage instfiles

古典安装界面风格:

3.2.2 现代UI界面(MUI)

现代UI简称为MUI,是NSIS安装包最流行的UI库,文档链接

💡💁🗒️Tips: 后续文档中的UI不做特别说明,默认为MUI。

NSIS自带MUI,所以直接引用进来:

!include "MUI.nsh"

先进行基础设置,MUI_ABORTWARNING常量标志关闭安装程序窗口时给出警告提示,MUI_ICON常量是MUI安装程序和界面的logo图标,在作用上替代了前文中Icon 命令。

!define MUI_ABORTWARNING !define MUI_ICON "..\myapp\nsis.ico"

再设置MUI的界面,使用 insertmacro关键字导入不同界面的宏定义。

; Welcome page !insertmacro MUI_PAGE_WELCOME ; License page !insertmacro MUI_PAGE_LICENSE ".\myapp\license.txt" ; Components page !insertmacro MUI_PAGE_COMPONENTS ; Directory page !insertmacro MUI_PAGE_DIRECTORY ; Instfiles page !insertmacro MUI_PAGE_INSTFILES ; Finish page !insertmacro MUI_PAGE_FINISH

这里用到了insertmarco关键字和macro(宏)的概念,宏常用于组织安装与卸载的代码片段。

🌟Tips: 与区段不同的是,宏用于将可重复使用的脚本片段,在各个需要的地方用!insetmarco标记插入位置。宏命令是在编译时插入代码,这样你只需要写一份通用的代码,就可以多处的使用。

MUI的界面风格如下:

!

这样安装界面就定义完成了,可以根据自己的喜好删减和排列不同的界面。

但请注意,如果只有安装界面并不能成功编译出安装包,我们还需要定义卸载程序。

3.3 卸载程序属性

有安装程序,那么与之对应的就是卸载程序。卸载程序对应着我们的程序的卸载过程,对于常规软件来说,必提供卸载程序给用户方便卸载。

🌟Tips: 卸载属性必须在所有安装和卸载页面之前定义。

# uninstaller !define MUI_UNICON "..\myapp\uninstall.ico"

MUI_UNICON常量指定卸载程序使用的图标。

3.4 卸载程序

不同于安装程序,卸载程序包含在安装程序内被一起安装,在安装后运行进行卸载,所以NSIS要求我们在安装的Section中定义卸载程序,由编译器生成。

Section "Section1" SEC01 SetOutPath "$INSTDIR" WriteUninstaller "$INSTDIR\uninstall.exe" File "..\myapp\MyApp.exe" SectionEnd

并且,需要至少编写一个卸载区段,作为卸载程序的执行内容。这里使用唯一特殊的卸载区段Uninstall,这是一个特殊的卸载区段名称,可以不用加un.的前缀。

Section -Uninstall ; your uninstall code here SectionEnd 3.5 添加卸载界面

与安装界面同理,我们给卸载程序加入和界面。

; Uninstaller pages !insertmacro MUI_UNPAGE_COMPONENTS !insertmacro MUI_UNPAGE_INSTFILES 3.6 设置界面语言

最后设置界面使用的语言,🚨需要注意的是,语言设置必须放在所有安装和卸载界面之后,不然编译会出现一个错误,或别的未知错误。

; Language files !insertmacro MUI_LANGUAGE "English"

🌟Tips: 这里涉及到一个代码顺序的问题,NSIS是顺序执行的,所以代码顺序十分重要。因为MUI在使用中包含宏代码,而它的宏代码中的变量又有前后关系,所以使用MUI的过程中会经常遇到一些因为代码顺序导致的问题。

4. 编写安装与卸载内容

在安装程序中,安装与卸载是伴生关系,一般编写了什么安装内容,就需要编写与之相应的卸载内容。

本章代码在示例项目中对应install项目的installer.nsi,可以将本章内容与代码对照,更直观的理解如何编写安装与卸载内容。

4.1 安装文件

从这里开始,我们将前文中Section1中的安装内容移动到Sectionmyapp中进行默认安装。与特定的卸载Section名称Uninstall不同的是,安装Section并没有特定的Section名称,一般我们将程序默认安装内容的Section命名为程序的名称(如: myapp)或者Post,也可以按自己意愿命名。

Section -myapp SetOutPath "$INSTDIR" SetOverwrite ifnewer WriteUninstaller "$INSTDIR\uninstall.exe" File "..\myapp\MyApp.exe" File "/oname=$INSTDIR\repair.file" "..\myapp\s_win_repair.file" SetOutPath "$INSTDIR\bin" File /r "..\myapp\bin*.*" SetOutPath "$INSTDIR\resources" File "/oname=uninstallerIcon.ico" "${MUI_ICON}" SectionEnd Section -Uninstall Delete "$INSTDIR\uninstall.exe" Delete "$INSTDIR\repair.file" Delete "$INSTDIR\MyApp.exe" RMDir /r "$INSTDIR\bin" Delete "$INSTDIR\resources\uninstallerIcon.ico" RMDir "$INSTDIR\resources" RMDir "$INSTDIR" SectionEnd

我们在安装时增加了SetOverwrite命令(文档),这是一个编译器标记命令,它指示编译器后续代码中File指令的覆盖方式(如果存在),ifnewer 值表示当文件更新时覆盖安装。

🌟Tips: NSIS中常常会用用到一些标记类的命令,他们经常需要在后续代码需要什么标记时进行设置,可以在多处设置不同的值。有成对的出现的情况,在设定非常规标记值后,在代码块后再将其设置回来,可以根据需要灵活搭配。

安装中包含了File的常见的几种用法:

用法解析File "文件路径"安装指定文件到当前 SetOutPath 指定的目录下File "/onam=安装全路径" "文件路径"安装指定文件到指定路径下,并重命名文件File "/onam=文件名" "文件路径"安装指定文件到当前 SetOutPath 指定的目录下,并重命名文件File /r "文件夹和通配符"递归安装指定文件夹内所有的文件到当前 SetOutPath 指定的目录下,会保持内部的文件夹层级结构

注意:File指令中的文件路径可以是绝对路径、相对路径或者文件名。安装位置的的相对路径和文件名相对于当前SetOutPath指定的目录,需要安装文件的相对路径和文件名相对于当前执行脚本的目录。更多详实信息查看文档

与安装相对应的的卸载过程,在无特殊需求的情况下,卸载则需要将安装的文件卸载干净,SectionUninstall中包含了卸载时常用的指令:

用法解析Delete "绝对文件路径"删除指定路径的文件RMDir "绝对文件夹路径"删除指定文件夹,必须为空文件夹,不然无法删除并设置错误标记(不影响流程)RMDir /r "绝对文件夹路径"递归删除指定文件夹

一般的做法是,与安装的顺序对应,依次删除安装的文件,最后删除整个安装目录。

4.2 安装程序快捷方式

绝大部分的安装程序都会往桌面和开始菜单中生成安装程序的图标,这是我们的程序安装后便于使用的重要形式。

安装桌面快捷方式

我们先往Section myapp尾部中加入下列代码:

CreateShortCut "$DESKTOP${PRODUCT_NAME}.lnk" "$INSTDIR${PRODUCT_SHORT_NAME}.exe"

使用CreateShortCut指令创建前面使用File指令安装的可执行程序的快捷方式到桌面上。

$DESKTOP 常量表示执行安装的计算机的系统桌面路径,虽然官方文档里叫它常量,但是实际上从用法可以看出来它是个变量🤣 ${PRODUCT_NAME} 常量表示前面用户自定义的产品名 ${PRODUCT_SHORT_NAME} 常量表示前面用户自定义的产品短名称

CreateShortCut 生成的桌面图标默认采用指向的可执行程序的图标。如果之前生成过同名快捷方式,而图标不同,那么生成的新桌面快捷方式图标可能不会更新,需要刷新一下桌面或者注销用户重新登录才可以。

安装开始菜单快捷方式

再往Section myapp尾部中加入下列代码:

IfFileExists "$SMPROGRAMS${PRODUCT_NAME}" +2 0 CreateDirectory "$SMPROGRAMS${PRODUCT_NAME}" CreateShortCut "$SMPROGRAMS${PRODUCT_NAME}${PRODUCT_NAME}.lnk" "$INSTDIR${PRODUCT_SHORT_NAME}.exe"

同理,创建开始菜单快捷方式也是使用CreateShortCut在系统的指定目录下创建可执行程序的快捷方式。

这里我们在$SMPROGRAMS常量表示的开始菜单目录下使用CreateDirectory创建了产品名称的目录,再在其中创建快捷方式。

这种在开始菜单中创建产品目录,然后再在其中放置快捷方式的方式是常规做法。也可以直接将快捷方式直接创建在开始菜单根目录中,这里自由度很高,可以根据需要自行选择。

🌟知识点🌟

这里通过IfFileExists指令来判断路径是否已经存在,它是一个流程控制指令,用法是:

IfFileExists 要检测的文件或路径 文件或路径存在时跳转的位置 [文件或路径不存在时跳转的位置]

位置可以指定行偏移或者标记,行偏移使用 +/-数值或者0,正数值代表从本行起向后的第几行,负数值代表从本行起向前的第几行,0代表从本行起继续执行。

如下例判断记事本程序是否已经安装在操作系统目录下,存在从改行顺序执行弹出 MessageBox。不存在则向后记2行开始执行,跳过MessageBox。

IfFileExists $WINDIR\notepad.exe 0 +2 MessageBox MB_OK "记事本已安装"

指定标记则使用标记名称,直接跳转到标记的代码行开始执行,例如:

IfFileExists $WINDIR\notepad.exe 0 notExists MessageBox MB_OK "记事本已安装" notExists:

Tips: 这样的判断指令跳转的方式在NSIS还有一些,他们都是同样的使用方式,效果与Goto一致。

卸载快捷方式

与安装文件同理,安装了快捷方式后同时也要编写卸载过程。使用Delete与RMDir指令删除桌面和开始菜单中的快捷方式。

; delete Desktop icon Delete "$DESKTOP${PRODUCT_NAME}.lnk" ; delete start menu folder Delete "$SMPROGRAMS${PRODUCT_NAME}${PRODUCT_NAME}.lnk" RMDir "$SMPROGRAMS${PRODUCT_NAME}" 4.3. 注册安装程序

在Windows中,正规的软件在安装后,都可以在win7的控制面板或者win10的安装的应用内找到,供用户很方便的可以查看安装信息和卸载。

但,这并不是Windows自动检测到安装并记录的,而是一个君子协定,需要安装程序自觉进行注册后才能在已安装的列表内找到。(如果你不注册也没人来打你😜

代码如下:

!define PRODUCT_UNINSTALL_KEY "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall${PRODUCT_NAME}" Section -myapp // ... ; Register the installed software WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "DisplayName" "$(^Name)" WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "InstallDir" "$INSTDIR" WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\resources\uninstallerIcon.ico" WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" WriteRegStr HKLM "${PRODUCT_UNINSTALL_KEY}" "Publisher" "${PRODUCT_PUBLISHER}" SectionEnd

这里使用指令WriteRegStr添加注册表字符串值,它是一个注册表指令。基础语法如下:

WriteRegStr rootkey subkey key_name value eg. WriteRegStr rootkey "SOFTWARE\example" "key1" "Hello World!"

💡 注册表的rootkey可以为下列内容,他们分别记录着windows中的不同内容,常用HKLM为本机内容(一般用来记录为所有用户的信息),HKCU为当前用户。

HKCR 或 HKEY_CLASSES_ROOT,前者为缩写,下同。 HKLM 或 HKEY_LOCAL_MACHINE HKCU 或 HKEY_CURRENT_USER HKU 或 HKEY_USERS HKCC 或 HKEY_CURRENT_CONFIG HKDD 或 HKEY_DYN_DATA HKPD 或 HKEY_PERFORMANCE_DATA SHCTX 或 SHELL_CONTEXT

💡subkey为具体注册表项相对于rootkey的全路径,下图中的路径框中的 SOFTWARE\BiliBili 就是subkey。

🌟Tips: 如果子项并不存在,WriteRegStr 会将其创建。

在 SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{程序名} 这个注册表项下创建指定的 DisplayName、InstallDir、UninstallString、DisplayIcon、DisplayVersion、URLInfoAbout、Publisher这些值告诉Windows我们安装的程序信息。然后,我们就可以在安装的程序列表内看到已安装的程序信息。

💡Tips: $(^Name) 用于获取Name命令设定的值

类似的添加注册表值的指令还有:WriteINIStr、WriteRegBin、WriteRegDWORD、WriteRegExpandStr。更多注册表操作可以参考文档。

与其他安装过程同理,安装写入了注册表,那么就需要在卸载的时候清理干净。

Section -Uninstall // ... ; delete reg item DeleteRegKey HKLM "${PRODUCT_UNINSTALL_KEY}" SectionEnd 4.4. 卸载完成自动关闭

受国产软件的荼毒,很多人不喜欢卸载完成之后还要点击完成,总觉得会被装上莫名其妙的软件。如果你也不喜欢这样,那么请在卸载的内容里设置卸载完成自动关闭。

Section -Uninstall // ... ; close after finish SetAutoClose true SectionEnd 5. 定制安装向导 5.1. 基础界面

NSIS提供了一系列的命令用来设置基础界面信息,以下列举最常用的,更多的见文档。

窗口标题

Caption自定义安装程序的窗口标题。安装程序标题默认为 {Name命令指定的名称} Setup,如果你不喜欢可以自己设置。

# base ui info Caption "${PRODUCT_NAME} Installer"

底部分割线文本

BrandingText设置安装窗口内容底部分割线上的文本。如果设置空字符串(""),则显示下图中默认值;如果不想在这里显示文本,设置只有一个空格的字符串" "就行。

BrandingText /TRIMLEFT "文本内容" eg. BrandingText /TRIMLEFT "${PRODUCT_NAME} ${PRODUCT_VERSION}"

退出警告

如果你需要在用户点击关闭按钮退出安装程序时进行提示,那么就加入下面这行代码:

!define MUI_ABORTWARNING

弹出提示窗:

顶部右侧图标

安装过程界面的顶部右侧可以设置图标,默认为NSIS的logo。我们自己程序的安装包肯定是是替换它的,通过定义下列常量来实现:

!define MUI_HEADERIMAGE ; Defining this value is the basis for the follow two definitions !define MUI_HEADERIMAGE_BITMAP ".\resource\header_150x57.bmp" !define MUI_HEADERIMAGE_BITMAP_STRETCH NoStretchNoCropNoAlign !define MUI_HEADERIMAGE_RIGHT ; Display to right MUI_HEADERIMAGE作为开关量,必须定义后后续的常量才会生效 MUI_HEADERIMAGE_BITMAP常量定义使用的图片,格式限定为(.bmp),图片区域尺寸是15057,图片最好是15057的倍数,不然就会被拉伸变形。 MUI_HEADERIMAGE_RIGHT常量定义图片显示为右侧

效果图如下:

5.2. 欢迎界面

定义MUI_WELCOMEFINISHPAGE_BITMAP常量的值为图片路径,格式限定为(.bmp)。图片区域尺寸为164*314,推片最好是区域尺寸的倍数,不然可能会被裁剪。

; Welcome page !define MUI_WELCOMEFINISHPAGE_BITMAP ".\resource\welcome_install.bmp" !insertmacro MUI_PAGE_WELCOME

💁Tips: 一般在使用库时,定义其指定常量要在宏的前面,因为宏内代码会使用到其相关常量。

效果图如下:

5.3. License界面

一般License界面我们定义用户需要勾选确认,而不是直接点击Agree就进入下一步了。在导入Lincese界面宏之前,定义MUI_LICENSEPAGE_CHECKBOX常量,设定必须点击同意选项了之后才能继续进行下一步。

; License page !define MUI_LICENSEPAGE_CHECKBOX !insertmacro MUI_PAGE_LICENSE "..\myapp\license.txt"

效果图如下:

5.3. 组件界面

组件界面在实际使用中不是一个非必须的界面,在有一些可选的内容需要用户选择性安装时才需要这个界面,选择安装列表显示所有可见的Section。反之,不需要的话就移除Components page 。

组件界面的文字信息很多,我们一般定义顶部的标题(MUI_PAGE_HEADER_TEXT)和文本(MUI_COMPONENTSPAGE_TEXT_COMPLIST),与选择框的标题文本(MUI_PAGE_HEADER_SUBTEXT)。

; Components page !define MUI_PAGE_HEADER_TEXT "Component Selection" !define MUI_COMPONENTSPAGE_TEXT_COMPLIST "Select components to install:" !define MUI_PAGE_HEADER_SUBTEXT "Select the components you want to install." !insertmacro MUI_PAGE_COMPONENTS

效果图如下:

但是在实际安装包中,我们需要调整Component界面的布局。因为它默认的这个界面布局实在是利用率很低,无关信息和空白间距太多了。

5.3.1. 调整界面布局

我们可以通过NSIS提供的功能将默认的界面改变成下图的的样子:

主要使用的是GDI设置方式,如果对GDI开发比较熟悉的读者将会很容易理解。下面将逐步介绍调整过程:

(1) 定义界面加载函数

通过GDI调整界面的布局,首先需要界面先完成显示。定义MUI_PAGE_CUSTOMFUNCTION_SHOW常量为一个函数ComponentsPageShow,我们将GDI的操作代码写入这个函数中,它将在组件界面显示后调用。

🌟重点注意🌟:MUI_PAGE_CUSTOMFUNCTION_SHOW是一个MUI定义的自定义函数宏,它不特殊针对某一界面,而是在其定义后插入的第一个MUI界面宏中生效。所以,想要为一个界面设定界面显示后调用的函数,就请将这个常量定义在该界面宏的前面。同类的几个函数常量还有MUI_PAGE_CUSTOMFUNCTION_PRE 、 MUI_PAGE_CUSTOMFUNCTION_LEAVE 、 MUI_PAGE_CUSTOMFUNCTION_DESTROYED,详见官网"Page Custom Functions"章节 。

!define MUI_PAGE_CUSTOMFUNCTION_SHOW ComponentsPageShow !insertmacro MUI_PAGE_COMPONENTS ; When components page show Function ComponentsPageShow FunctionEnd

💡知识点:函数类似于区段,常用于组织可复用的安装过程。函数只能在区段中被调用,跟区段一样区分安装函数与卸载函数,不能混用。

(2) 隐藏头部区域的次级文本

使用FindWindow指令获取安装窗口的句柄,#32770 是安装程序的窗口在windows中注册的类名。

使用GetDlgItem指令获取指定控件的句柄,使用ShowWindow指令设置指定句柄控件的显示/隐藏。

# Variables Var MyApp.Header.SubText Function ComponentsPageShow FindWindow $0 "#32770" "" $HWNDPARENT GetDlgItem $MyApp.Header.SubText $HWNDPARENT 1038 ; header area subtext ShowWindow $MyApp.Header.SubText ${SW_HIDE} ; Hide header area subtext FunctionEnd

💡句柄来源:可以在NSIS安装路径下的 "Contrib\Modern UI 2\Pages" 中的代码文件中找到每个界面上的UI控件句柄。

结果:

(3) 隐藏内容区域的主文本

# Variables Var MyApp.Component.MainText Function ComponentsPageShow FindWindow $0 "#32770" "" $HWNDPARENT GetDlgItem $MyApp.Component.MainText $0 1006 ; The main text of the content area ShowWindow $MyApp.Component.MainText ${SW_HIDE} ; Hide the main text of the content area FunctionEnd

结果:

(4) 隐藏安装类型选择文本和控件

安装类型选择默认下没有显示,但是界面上空出了它的位置,为了避免调整UI受到干扰,我们需要将其一并隐藏。

💡安装类型在额外进行配置了后才会出现(用的比较少),常见于驱动程序安装时选择完整安全、典型安装还是自定义安装。

# Variables Var MyApp.Component.InstallationType Var MyApp.Component.InstallationTypeText Function ComponentsPageShow FindWindow $0 "#32770" "" $HWNDPARENT GetDlgItem $MyApp.Component.InstallationTypeText $0 1021 ; Title text for the installation type GetDlgItem $MyApp.Component.InstallationType $0 1017 ; installation type ShowWindow $MyApp.Component.InstallationTypeText ${SW_HIDE} ; Hide header text for installation types ShowWindow $MyApp.Component.InstallationType ${SW_HIDE} ; Hide installation type FunctionEnd

结果:

(5) 隐藏描述标题文本

组件描述区域显示鼠标指向的组件列表中组件的描述文本,描述标题文本表示环绕描述文本的一个框和框上的标题文本。

💡标题文本本质上是一个GroupBox,但是它和描述文本只是前后叠在了一起,并没有包含关系。所以,隐藏了描述文本并不影响描述文本的显示。

# Variables Var MyApp.Component.DescriptionTitleText Function ComponentsPageShow FindWindow $0 "#32770" "" $HWNDPARENT GetDlgItem $MyApp.Component.DescriptionTitleText $0 1042 ; description title text ShowWindow $MyApp.Component.DescriptionTitleText ${SW_HIDE} ; Hide the title text of the description FunctionEnd

结果:

(6) 调整组件列表标题和组件列表

我们将组件列表文本和组件列表移动到左上角,并调整尺寸大小。

使用NSIS自带的 System.dll 库的 Call 函数调用 Windows 系统函数 SetWindowPos 设置GDI控件的位置和尺寸。System::Call 函数的用法详见文档,SetWindowPos 函数的用法详见MSDN文档。

NSIS可以调用C标准库中的函数,语法为 [dll名]::[函数名]

💡重点注意:SetWindowPos 从第3位参数到第6位为 x, y, cx, cy,x,y 为控件的左侧像素坐标和上侧像素坐标,相对原点为当前区域的左上角。cx,cy 为控件的像素宽高。

# Variables Var MyApp.Component.ComponentListTitleText Var MyApp.Component.ComponentList Function ComponentsPageShow FindWindow $0 "#32770" "" $HWNDPARENT GetDlgItem $MyApp.Component.ComponentListTitleText $0 1022 ; Component list title text GetDlgItem $MyApp.Component.ComponentList $0 1032 ; component list System::Call "User32::SetWindowPos(i $MyApp.Component.ComponentListTitleText, i 0, i 0, i 0, i 270, i 13, i 0)" ; Sets the position of the component list title text System::Call "User32::SetWindowPos(i $MyApp.Component.ComponentList, i 0, i 0, i 18, i 270, i 176, i 0)" ; Set the position of the component list FunctionEnd

结果:

(7) 移动磁盘占用文本和描述文本

我们将组件列表文本和组件列表移动到左上角,并调整尺寸大小。

# Variables Var MyApp.Component.DescriptionText Var MyApp.Component.DiskSizeText Function ComponentsPageShow FindWindow $0 "#32770" "" $HWNDPARENT GetDlgItem $MyApp.Component.DiskSizeText $0 1023 ; required disk size text GetDlgItem $MyApp.Component.DescriptionText $0 1043 ; The content text of the description System::Call "User32::SetWindowPos(i $MyApp.Component.DescriptionText, i 0, i 285, i 16, i 164, i 176, i 0)" ; Sets the position of the content text of the description System::Call "User32::SetWindowPos(i $MyApp.Component.DiskSizeText, i 0, i 0, i 210, i 0, i 0, i 1)" ; Sets the position of the disk size text FunctionEnd

结果:

持续更新中...


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3