详细介绍:使用NSIS和VNISEdit制作一个自解压的exe安装包

通常一个需要发布的程序都需要使用安装包进行安装,不可能给客户发送一套程序和依赖性文件,这样如果需要桌面添加软件的快捷方式,就得让客户自己添加(因为每台电脑、每个用户的桌面路径是不一样的),非常的麻烦,而且占用空间非常大,十分不方便,我们需要把他们打包成一个安装包,让用户运行这个安装包进行安装,而且像360软件管家这样的程序也可以识别,就可以通过其他渠道卸载。

本文需要阅读时间:20分钟

步骤:

  1. 使用向导生成标准安装包
  2. 编辑脚本对安装包进行扩展和自定义

我们需要用到的工具有:
1、NSIS安装包制作程序
2、VNISEdit安装包制作程序扩展软件

这两个软件在网上随便一搜就能搜到,比如以下网址,这个网址可以下载到增强版,而且压缩包是整理过的,里面还有其他比较强大的软件:
https://www.onlinedown.net/soft/22742.htm
注意:要使用压缩包内VNISEdit目录下的VNISEdit.exe来制作安装包,而不是外面的NSISEdit.exe,这个有bug,而且功能没有VNISEdit那么强大。

这个压缩包里面含有:
1、NSIS核心编译制作器
2、VNISEdit编译环境
3、NotePad代码编辑器(并非知名的NotePad++,支持各种编程语言和NSIS Script)
4、NSISEditor编译环境(通过向导制作脚本有bug,但可以编辑脚本)
5、zip2exe简易安装包制作器,可以将zip文件做成简单的exe自解压文件。
6、INI2NSI简易ini转nsi的程序
7、修改默认NSIS Script编辑器的程序(没什么用) 8、Reg2nsi注册表转nsi的程序
9、NSISDialogDesigner界面设计程序(需要Microsoft .NET 2.0 及以上环境)

仔细数数,里面能用的东西还是很多的,非常建议大家下载。
NSIS使用代码执行安装过程,这个代码是它独有的,是一个编译型语言,并不是很难,使用的都是比较简单的英语单词,语法也不是非常复杂,可供使用的模块基本帮你做完了很多。但是需要记住的常用函数和关键字很多,一定要有所了解。

由于我们安装了VNISEdit,我们不需要系统地学习NSIS语法和代码,我们可以借助VNISEdit安装包制作向导进行,这样代码和实际效果就能结合起来,我们就能更快的熟悉代码。当我们需要做出一些特殊调整的时候,我们才去手动编辑代码(有些强大设置向导里面是不会给你自定义的)。

1、使用VNISEdit向导制作标准安装包

首先我们找到VNISEdit软件,Win10的请注意,要始终使用管理员模式打开此程序(等会会展示这个问题),否则使用“编译并运行”只能为你做编译这件事,需要你自己到文件夹里面去双击打开。那如果用管理员模式就可以避免这个小问题。
在这里插入图片描述
我们找到上面一栏的向导按钮,就可以按照向导进行制作:
在这里插入图片描述
然后点击下一步,去填写应用程序基本信息:
在这里插入图片描述
其中必填的是程序名称和版本,其他没有的话是可以不填的。应用程序标志会显示在安装包界面下沿,可以写上版权信息,或者是公司信息。好了之后点击下一步:在这里插入图片描述
这一栏的表单非常重要,决定了安装程序语言,但是我们发现安装语言上什么都没有,然而这又是必填的,出现这种状况的原因是VNISEdit调用NSIS核心,但语言文件并不属于VNISEdit,而是NSIS,所有的安装语言的文件都必须让VNISEdit找到,我们需要调整VNISEdit默认读取路径,找到上面一栏的NSIS,然后点击配置:
在这里插入图片描述
在这里插入图片描述
这里最重要的是这个编译器选项,必须要定位到一个叫makensis.exe的程序,这个就是核心编译器,这个程序就在NSIS安装目录。点击“应用”,再回到原来的步骤:在这里插入图片描述现在我们就看到语言设置了,你可以勾选你需要的语言,在这里你要注意,如果是单独从网上下载的VNISEdit,可能生成的脚本文件只包含嵌入的语言,但是没有给你选择语言的界面。 如果是按照本文给的网址下载的话就不会有这样的bug。如果不想重装,也可以继续阅读,等会我会给出添加选择语言界面的方法。

安装程序图标可以自己设置,安装程序文件指的是安装包的文件名,图形界面基本上现代界面就行了,如果你想要用古典界面加XP外观也没问题。

压缩算法可以自己选择,有很多种选法,有zlib,lzma,bzip2和它们的固实(Solid)模式,还有“极限压缩”模式,本质上就是固实lzma模式。

接下来下一步是闪屏、音乐等设置,可以设置在安装时候播放音乐,如果你有闲功夫这样做,可以自行研究,我这里不放图片了。

再下一步:
在这里插入图片描述
这里的第一行非常重要,决定了你的程序一堆文件默认装在哪里,默认地址最好选择 $PROGRAMFILES\你的程序名文件夹,不存在时将被创建,这里的 $PROGRAMFILES每台电脑都不一样,但是都是系统识别的位置, $是一个转义符, $PROGRAMFILES代表程序安装目录,除此之外还有其他地址代号,代表不同的意思。

给大家列举一些常用的地址代号,排除了不常用的代号:

代号 意义
$PROFRAMFILES 代表系统安装目录,在此目录下安装的程序能够被360软件管家、Windows“卸载或更改程序”等检测到存在
$SMPROGRAMS 代表开始菜单目录,一般放置软件快捷方式,Win10不能在开始菜单放置卸载和帮助文档的快捷方式,这是Win10的规定,如果设置了是会被自动删除的
$INSTDIR 代表这一步中设定的“应用程序默认目录”,也就是安装目录,如果用户更改安装目录,它将指向用户指定的目录(可以设置不允许用户改变安装目录)

这三个是最常用的,其他还有一些代号,但是你在编辑的时候通常是不需要使用的。

第二个许可证协议可以放置协议,可以设置三种同意的方式的一种。如果你不需要协议,可以通过删代码来实现,请参照后面的内容。
需要注意的是,中文的协议会乱码,最好使用英文协议或者改变编码形式
在这里插入图片描述
接下来我们进入下一步:
在这里插入图片描述
这一步中我们加入需要自解压的文件,可以更改每个组件的的名字和包含的内容,上面自动会写上两个项目,这两个项目仅仅指示你这里应该加入程序文件,可以把它移除。

左边可以加入每个模块的描述,通常来说,只有一个模块的程序通常不允许也不需要用户选择安装的组件,你可以设置一个主程序模块,其他模块包含一些扩展文件什么的。
注意:如果你的程序目录下还有文件夹的话,一定要选择包含子目录,否则包在文件夹的文件不会被打包。
在这里插入图片描述
目的目录要根据你的需要设置,如果你的各个组件彼此独立,最好每个组件目标目录设置为$INSTDIR\你的独立组件名文件夹,不存在时将被创建,这样就可以做到彼此独立,但是如果各个组件互相依赖,最好放进一个目录下,装进同一组件,解压到同一目录。

做好了组件和目录之后就能进入下一步了:
在这里插入图片描述
接下来是开始菜单文件夹名称,NSIS会在开始菜单加入一个文件夹,用来放你的程序的快捷方式,如果只需要一个快捷方式,不需要设置文件夹,在$SMPROGRAMS放入一个快捷方式就行了,这一点可以在代码中实现,等会继续介绍。通常不需要用户更改开始菜单文件夹名称,如果支持更改的话,可以自己研究,也是非常简单的。
注:为了关照残疾人,Win10不希望在开始菜单发现卸载程序和帮助文件的快捷方式,我们可以解除勾选第三个选项。如果你有写网站的话,你可以勾选第二项。

下一步:
在这里插入图片描述
可以设置安装完成后自动运行程序,实际上它会给用户一个勾选框,征求用户的意见。
如果你的程序是带参数运行的,那么,可以加入参数(就是在cmd运行时的给定的参数),自述文件就是ReadMe.txt之类的文件,如果你在程序目录下写了自述文件,会打开它,同样也会征求用户意见。

再下一步:
在这里插入图片描述这一步可以设置解除安装程序,可以设定卸载时你对用户说的话,解除安装的方式有两种,如果你的NSIS没有日志记录功能,下面会提示你不能使用安全方式,一般来说不移动安装目录的情况下选择简易模式就够了,安全模式会多出一些复杂的代码。

之后我们就完成了:
在这里插入图片描述
转换文件路径为相对路径视自己需要设置。

2、编辑脚本对安装包进行扩展和自定义

单纯的靠向导制作安装包是不够的,更为强大的内容在于脚本。
我们经过向导的制作,已经生成了一个脚本,接下来我们来比较一下脚本和我们刚才进行的向导。这里的示例是一个测试包,以下是生成的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#该脚本使用 HM VNISEdit 脚本编辑器向导产生

#安装程序初始定义常量
!define PRODUCT_NAME "测试包"
!define PRODUCT_VERSION "1.0"
!define PRODUCT_PUBLISHER "My company, Inc."
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"
SetCompressor /SOLID lzma

#------ MUI 现代界面定义 (1.67 版本以上兼容) ------
!include "MUI.nsh"

#MUI 预定义常量
!define MUI_ABORTWARNING
!define MUI_ICON "H:\编程\素材\文件处理器.ico"
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"

#语言选择窗口常量设置
!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"

#欢迎页面
!insertmacro MUI_PAGE_WELCOME
#许可协议页面
!define MUI_LICENSEPAGE_CHECKBOX
!insertmacro MUI_PAGE_LICENSE "H:\编程\素材\licence_English.txt"
#组件选择页面
!insertmacro MUI_PAGE_COMPONENTS
#安装目录选择页面
!insertmacro MUI_PAGE_DIRECTORY
#开始菜单设置页面
var ICONS_GROUP
!define MUI_STARTMENUPAGE_NODISABLE
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "测试包开始菜单"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
!insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP

#安装过程页面
!insertmacro MUI_PAGE_INSTFILES

#安装完成页面
!define MUI_FINISHPAGE_RUN "$INSTDIR\test.exe"
!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\使用方法.txt"
!insertmacro MUI_PAGE_FINISH

#安装卸载过程页面
!insertmacro MUI_UNPAGE_INSTFILES

#安装界面包含的语言设置
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "TradChinese"
!insertmacro MUI_LANGUAGE "French"
!insertmacro MUI_LANGUAGE "SimpChinese"
!insertmacro MUI_LANGUAGE "Korean"
!insertmacro MUI_LANGUAGE "Thai"
!insertmacro MUI_LANGUAGE "German"
!insertmacro MUI_LANGUAGE "Greek"
!insertmacro MUI_LANGUAGE "Russian"
!insertmacro MUI_LANGUAGE "Italian"
!insertmacro MUI_LANGUAGE "Afrikaans"
!insertmacro MUI_LANGUAGE "Portuguese"
!insertmacro MUI_LANGUAGE "SpanishInternational"
!insertmacro MUI_LANGUAGE "Japanese"

#安装预释放文件
!insertmacro MUI_RESERVEFILE_LANGDLL
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
#------ MUI 现代界面定义结束 ------

Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "Setup.exe"
InstallDir "$PROGRAMFILES\测试包"
ShowInstDetails show
ShowUnInstDetails show
BrandingText "安装程序"

Section "HxDTool主模块" SEC01
  SetOutPath "$INSTDIR"
  SetOverwrite ifnewer
  File /r "H:\HxDTool\*.*"
  #创建开始菜单快捷方式
  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  CreateShortCut "$DESKTOP\测试包.lnk" "$INSTDIR\test.exe"
  !insertmacro MUI_STARTMENU_WRITE_END
SectionEnd

Section -AdditionalIcons
  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
  CreateDirectory "$SMPROGRAMS\$ICONS_GROUP"
  CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninst.exe"
  !insertmacro MUI_STARTMENU_WRITE_END
SectionEnd

Section -Post
  WriteUninstaller "$INSTDIR\uninst.exe"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
  WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd

#-- 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题。--

#区段组件描述
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
  !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} "HxDTool"
!insertmacro MUI_FUNCTION_DESCRIPTION_END

Function .onInit
  !insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd

#以下是安装程序的卸载部分
Section Uninstall
  !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP
  Delete "$INSTDIR\uninst.exe"
  Delete "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk"
  Delete "$DESKTOP\测试包.lnk"
  RMDir "$SMPROGRAMS\$ICONS_GROUP"
  RMDir "$INSTDIR"
  DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
  SetAutoClose true
SectionEnd

#-- 根据 NSIS 脚本编辑规则,所有 Function 区段必须放置在 Section 区段之后编写,以避免安装程序出现未可预知的问题。--#
Function un.onInit
  !insertmacro MUI_UNGETLANGUAGE
  MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "您确实要完全移除 $(^Name) ,及其所有的组件?" IDYES +2
  Abort
FunctionEnd

Function un.onUninstSuccess
  HideWindow
  MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从您的计算机移除。"
FunctionEnd

在这里为了方便大家识别,我这里使用了其他编程语言来高亮这些文字。我们翻译一下这些简单的英语单词就能知道它的含义。

我们需要注意每行的第一个单词,它们在VNISEdit中高亮为蓝色,这些就相当于一个封装好的函数,可以直接使用,而且不需要我们在意太多的压缩和解压细节。

函数 意义
Section 最基础的函数,表示一个部门,用来代表一个需要安装的组件,Section中的内容是整个程序除了卸载以外最后执行的部分,但是编译时会第一个检查,如果程序中没有任何Section或Function,将会终止编译,Section内的代码块需要缩进2空格
Function 执行的函数,同样需要缩进,它的函数名会被识别,如果识别为特殊名称,将会在特定情况下进行,下面还会讲解
SectionEnd 表示部门结束,不缩进于Section内部
FunctionEnd 表示函数结束,同上
SetCompressor 设置压缩算法,后面可用的参数就是向导中的压缩算法,固实的用/SOLID作为前缀,例:固实lzma算法记作/SOLID lzma
SetCompressor 设置压缩分卷大小,后接一个数字,通常不写是没关系的
OutFile 决定编译好的安装包的路径(是指未来的安装包的路径,而不是放在哪个文件夹)
Name 设置产品的名称,通常是向导第一步中写的应用程序名称+应用版本
InstallDir 表示默认的安装路径,即向导第四步第一行填入的内容,决定了$INSTDIR的值
ShowInstDetails 表示是否显示安装细节,参数不是简单的true和false,而是show,hide和nevershow,分别表示自动显示细节、用户按键显示细节、不允许看到安装细节
ShowUnInstDetails 表示是否显示卸载细节,参数同上
BrandingText 显示安装包下沿的信息,即向导第一步最后一行自定义文本,可以接受两个参数,一个是要显示的文字,还有可选参数是/TRIM,可以决定文字对齐方向(LEFT,RIGHT或者CENTER,默认为LEFT,必须写作/TRIMLEFT、/TRIMRIGHT或/TRIMCENTER,中间没有任何分隔)
SetOutPath 只能写在Section中第一行,决定了所属Section表示的组件的安装位置,不同于InstallDir,SetOutPath可以让不同的组件安装在总安装目录的不同子目录下,建议设置为$INSTDIR\组件名称的文件夹(或者如果组件互相依赖,可以另行调整组件路径)
SetOverWrite 只能写在Section中,用来设置已安装时是否覆盖,参数可以设置为始终覆盖(on),始终不覆盖(off),较新时覆盖(ifnewer),文件内容不同时覆盖(ifdiff)和尝试覆盖(try),对应向导第五步>编辑目录项目
File 只能写在Section中,表示该Section包含并打包的文件,/r转义参数代表包含子目录的文件和文件夹,对应的向导步骤同上;/x参数用来排除文件,可以写/x “*.ico” “xxx\*”,分别表示排除ico文件和排除xxx子目录下的所有文件,对应向导第五步
CreateDictionary 创建一个文件夹,后面加上的是文件夹的完整路径或相对路径
CreateShortcut 创建一个快捷方式,第一个是快捷方式的路径(后缀.lnk),第二个是快捷方式指向文件的路径,对应向导第六步下面部分
WriteUninstaller 创建解除安装程序,后面接卸载程序的路径名
WriteRegStr 写入注册表,这一般不需要进行更改,按照向导生成的就行了
Delete 通常在卸载Section中,删除单个文件,后接删除的文件的路径,由于删除的是单个文件,所以不能加/r
RMDir 通常在卸载Section中,删除目录和目录下的所有文件,后接删除的目录的路径,前面一般需要手动加上转义/r,向导没给你加,不加会卸载残留,最好每个子目录写一次这个指令,都要加上/r,最后移除总目录RMDir “$INSTDIR”
DeleteRegKey 删除注册表信息,一般按照向导生成就行了
SetAutoClose 只能写在Section中,表示安装完成之后是否自动跳到完成界面,参数为true和false
AutoCloseWindow 似乎并没有什么作用,功能看似和上一个是相同的,但是可以写在Section以外,参数同上
Messagebox 消息框,只能写在Section或Function中,参数有很多,包括显示信息、显示警告、问yes no,问okcancelretry等,VNISEdit中输入Messagebox可以获得全部参数列表,后面再接消息框显示的内容
Abort 阻塞,等待用户回答
HideWindow 隐藏窗口,通常用于卸载Section中,卸载程序先删除自己,再删除其他文件(没错,程序还在运行),删除了之后要自动关掉窗口

我们点击编译运行,如果你不需要协议部分,你在向导应该填写一个不存在的路径,然后让它编译报错,找到license界面的部分,把它删掉:
在这里插入图片描述
通常要删掉一行到两行,根据不同的同意协议的方式,有不同的行数,你只要根据上面的注释删除相应的部分代码,就比如说这个是点击古典按钮的方式同意协议并进入下一步,所以只有一行。

按照我给的网址下载下来的VNISEdit会自动写上语言选择界面的,但是单独下载VNISEdit编出来的可能不会自动添加,导致安装包不能选择语言,对于打包安装包之后不能显示选择语言界面的,我们可以看到,刚才的那张图片,在欢迎界面的上方,就定义了语言选择界面的窗口,把那三行抄下来,放在欢迎界面前面就可以实现:

1
2
3
4
#语言选择窗口常量设置
!define MUI_LANGDLL_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_LANGDLL_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_LANGDLL_REGISTRY_VALUENAME "NSIS:Language"

这样我们就实现了多语言安装包。

附:

我们需要注意的是,如果你没有用管理员模式运行VNISEdit的话,Win10一般“编译并运行”会报这个错误:
在这里插入图片描述
但是这不影响编译,编译是成功的,我们可以自己到输出目录去找,然后手动运行,如果用管理员模式运行就能够支持自动运行安装包,通常这个错误没有大问题。

再给大家附上Messagebox的参数列表:
在这里插入图片描述
后面还有一个MB_YESNOCANCEL,这上面看不到。

那么今天为大家的讲解就到这里结束了,遇到任何问题大家可以在评论区留言,拓宽大家的视野。

本文为作者原创,未经作者允许,禁止转载。

----------------------END------------------------