Tools-Inno-Setup

window系统免费安装软件制作系统,用于打包封装nginx、emqx、mysql、redis、springboot等合成一个windows的exe安装包。

安装脚本

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
[Setup]

#define MyAppName "myapp"
#define MyAppVersion "1.0"
#define MyAppPublisher "LP"
#define MyAppURL "http://www.lp.top:8090/"
#define MyAppExeName "myapp.exe"

[Setup]
AppId= {{ED9D5968-F178-48C5-AC61-2AED59BBCEF6}} //每次编译需要修改该uuid
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableDirPage=yes
OutputDir=D:\innosetup\output
OutputBaseFilename=gateId
Compression=lzma
SolidCompression=yes
LicenseFile=D:\workspace\license.rtf #软件安装申明
;AlwaysRestart=yes
;PrivilegesRequired=admin

[Code]
//#############################自定义函数###################################
// 判断单个端口占用
function IsNotPortOccupation(strPortNum: String): Boolean;
// 变量定义
var ErrorCode: Integer;
var bRes: Boolean;
var strFileContent: AnsiString;
var strTmpPath: String; // 临时目录
var strTmpFile: String; // 临时文件,保存查找软件数据结果
var strCmdFind: String; // 查找端口命令, netstat -natp tcp |findstr "LISTENING" |findstr ":80 "| find /C ":80 " 找到的话返回个数,找不到为0
begin
strTmpPath := GetTempDir();
strTmpFile := Format('%sfindProtRes.txt', [strTmpPath]);

strCmdFind := Format('/c netstat -natp tcp |findstr "LISTENING" |findstr ":%s "|find /C ":%s " > "%s "', [strPortNum, strPortNum ,strTmpFile]);
log(strCmdFind);

bRes := ShellExec('open', ExpandConstant('{cmd}'), strCmdFind, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
bRes := LoadStringFromFile(strTmpFile, strFileContent);
strFileContent := Trim(strFileContent);
if StrToInt(strFileContent) > 0 then begin
result:=true;
end else result:=false;
end;
// 判断多个端口占用
function IsNotPortsOccupation(const portList: array of String): array of String;
var
i: Integer;
begin
for i := 0 to GetArrayLength(portList)-1 do
begin
if IsNotPortOccupation(portList[i]) then
begin
SetLength(Result,Length(Result)+1);
Result[High(Result)] := portList[i];
end;
end;
end;
// 数组转换为字符串
function JoinArrayToString(arr: array of String; delimiter: String): String;
var
i: Integer;
begin
Result := '';
for i := 0 to GetArrayLength(arr) - 1 do
begin
if Result <> '' then
Result := Result + delimiter;
Result := Result + arr[i];
end;
end;
// 检查是否需要初始化数据
function IsInitMySqlData: Boolean;
begin
if MsgBox('存在历史数据,是否初始化历史数据?',mbInformation,MB_YESNO) = IDYES then
begin
Result := true;
end else
Result := false;
end;
//#############################自定义界面###########################################
//----------------安装类型界面-------------------------------------
var
Page: TWizardPage;

RadioButton1, RadioButton2, RadioButton3, RadioButton4: TRadioButton;
Lbl1, Lbl2: TNewStaticText;


procedure CreateTypeSelectPage;
begin
Page := CreateCustomPage(wpInfoBefore, '选择安装类型', '请根据您的需要选择安装的类型');

RadioButton1 := TRadioButton.Create(Page);
RadioButton1.Left := ScaleX(80);
RadioButton1.Top := ScaleY(40);
RadioButton1.Width := Page.SurfaceWidth;
RadioButton1.Height := ScaleY(17);
RadioButton1.Caption := '标准安装';
RadioButton1.Checked := True;
RadioButton1.Parent := Page.Surface;

Lbl1 := TNewStaticText.Create(Page);
Lbl1.Left := ScaleX(95);
Lbl1.Top := ScaleY(60);
Lbl1.Width := ScaleX(250);
Lbl1.Height := ScaleY(50);
Lbl1.Caption := '按照标准模式安装软件到您的电脑';
Lbl1.Parent := Page.Surface;

RadioButton2 := TRadioButton.Create(Page);
RadioButton2.Left := ScaleX(80);
RadioButton2.Top := RadioButton1.Top + ScaleY(60);
RadioButton2.Width := Page.SurfaceWidth;
RadioButton2.Height := ScaleY(17);
RadioButton2.Caption := '自定义安装';
RadioButton2.Checked := false;
RadioButton2.Parent := Page.Surface;

Lbl2 := TNewStaticText.Create(Page);
Lbl2.Left := ScaleX(95);
Lbl2.Top := Lbl1.Top + ScaleY(60);
Lbl2.Width := ScaleX(250);
Lbl2.Height := ScaleY(50);
Lbl2.Caption := '您可以选择单个安装项,建议经验丰富的用户使用';
Lbl2.Parent := Page.Surface;
end;
//------------------------安装状态界面--------------------------------------------
procedure CreateShowStatusPage;
begin
Page := CreateCustomPage(wpInfoAfter, '等待服务状态', '请耐心等待服务启动完成');
RadioButton3 := TRadioButton.Create(Page);
RadioButton3.Left := ScaleX(80);
RadioButton3.Top := ScaleY(40);
RadioButton3.Width := Page.SurfaceWidth;
RadioButton3.Height := ScaleY(17);
RadioButton3.Caption := 'redis';
RadioButton3.Checked := false;
RadioButton3.Parent := Page.Surface;

RadioButton4 := TRadioButton.Create(Page);
RadioButton4.Left := ScaleX(80);
RadioButton4.Top := RadioButton1.Top + ScaleY(60);
RadioButton4.Width := Page.SurfaceWidth;
RadioButton4.Height := ScaleY(17);
RadioButton4.Caption := 'emqx';
RadioButton4.Checked := false;
RadioButton4.Parent := Page.Surface;
end;
//-------------------------参数配置界面--------------------------------------------


//#############################安装开始时掉用###################################
procedure InitializeWizard();
var
UsePorts: array of String;
UsePortsMessage: String;
begin
UsePorts := IsNotPortsOccupation(['80','1883','8083','8084','8883','18083','3306','6379','8080','8081','8082','8085']);
if Length(UsePorts)>0 then //检测这些端口是否占用,包含nginx、emqx、mysql、redis、springboot
begin
UsePortsMessage := '占用的端口:'+ JoinArrayToString(UsePorts,',');
MsgBox(UsePortsMessage, mbInformation, MB_OK);
Abort;
end;
CreateTypeSelectPage;
CreateShowStatusPage;
end;

function ShouldSkipPage(PageID: Integer): Boolean; //是否跳过组件选择界面
begin
if (PageID = wpSelectComponents) and (RadioButton1.Checked) then
Result := True
else if (PageID = wpSelectProgramGroup) and (RadioButton1.Checked) then
Result := True
end;
//#############################安装结束时掉用#########################################
procedure CurStepChanged(CurStep: TSetupStep);
var
UsePorts: array of String;
UsePortsMessage: string;
begin
if CurStep = ssPostInstall then
begin
UsePorts := IsNotPortsOccupation(['80','1883','8083','8084','8883','18083','3306','6379','8080','8081','8082','8085']);
if Length(UsePorts)<12 then //检测服务是否正常运行,有些服务还没启动成功,这里就已经运行了,会导致一些服务检测不到,而且检测到没运行,也不支持安装回退
begin
UsePortsMessage := '启动成功的服务端口:'+ JoinArrayToString(UsePorts,',');
MsgBox(UsePortsMessage, mbInformation, MB_OK);
Abort;
end;
end;
end;

[Types]
Name: "Custom"; Description: "Custom Installation"; Flags: iscustom

[Components]
Name: MySql; Description: MySql ; Types: Custom //设置组件树(安装选择组件界面显示的内容)
Name: Redis; Description: Redis ; Types: Custom
Name: Emqx; Description: Emqx ; Types: Custom
Name: Nginx; Description: Nginx ; Types: Custom
Name: Java; Description: Java ; Types: Custom
//通过 exclusive 完成 DMR、XPT 的互斥选择
Name: Java\Gateway; Description: Gateway; Types: Custom;
Name: Java\Gateid; Description: Gateid; Types: Custom;
Name: Java\Base; Description: Base; Types: Custom;
Name: Java\Auth; Description: Auth; Types: Custom;

[Languages]
Name: "chinesesimp"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1

[Files]
Source: "D:\workspace\mysql\*"; DestDir: "{app}\mysql"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: MySql
Source: "D:\workspace\redis\*"; DestDir: "{app}\redis"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: Redis
Source: "D:\workspace\emqx\*"; DestDir: "{app}\emqx"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: Emqx
Source: "D:\workspace\nginx\*"; DestDir: "{app}\nginx"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: Nginx
Source: "D:\workspace\project\*"; DestDir: "{app}\project"; Flags: ignoreversion recursesubdirs createallsubdirs;Components: Java
; 注意: 不要在任何共享系统文件上使用“Flags: ignoreversion ?

[Icons]
; Name: "{commondesktop}\project";Filename: "{app}\project\start.exe"; WorkingDir: "{app}\HSDServer"

[INI]
;修改数据库配置文
Filename:"{app}\mysql\my.ini";Section:"mysqld";Key:"basedir"; String:"{app}\mysql";Components:MySql;
Filename:"{app}\mysql\my.ini";Section:"mysqld";Key:"datadir"; String:"{app}\mysqlData";Components:MySql;
Filename:"{app}\mysql\my.ini";Section:"mysqld";Key:"port"; String:"3306";Components:MySql;
Filename:"{app}\mysql\my.ini";Section:"client";Key:"port"; String:"3306";Components:MySql;

[Run] //安装脚本,包含数据初始化脚本
Filename: "{app}\mysql\bin\mysql_install.bat";Components:MySql;
Filename: "{app}\mysql\bin\mysql_init.bat";Components:MySql;Check:IsInitMySqlData;
Filename: "{app}\redis\init-redis.bat";Components:Redis;
Filename: "{app}\redis\start-redis.bat";Components:Redis;
Filename: "{app}\emqx\bin\mqttSatrt.bat";Components:Emqx;
Filename: "{app}\nginx\startNginx.bat";Components:Nginx;
Filename: "{app}\project\start.bat";Components:Java;

[UninstallRun] //卸载执行的脚本
Filename: "{app}\mysql\bin\mysql_stop.bat";Components:MySql;
Filename: "{app}\redis\stop-redis.bat";Components:Redis;
Filename: "{app}\emqx\bin\mqttStop.bat";Components:Emqx;
Filename: "{app}\nginx\stopNginx.bat";Components:Nginx;
Filename: "{app}\project\stop.bat";Components:Java;

[UninstallDelete] //删除目录
Type:filesandordirs;Name:"{app}\mysql";Components:MySql;
Type:filesandordirs;Name:"{app}\redis";Components:Redis;
Type:filesandordirs;Name:"{app}\emqx";Components:Emqx;
Type:filesandordirs;Name:"{app}\nginx";Components:Nginx;
Type:filesandordirs;Name:"{app}\project";Components:Java;

[Code]
//卸载时,弹窗提示删除数据
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
DeleteProfile: string;
DeleteConfirm: Boolean;
ErrorCode: Integer;
begin
case CurUninstallStep of
//卸载后的收尾工作
usPostUninstall:begin
// 确认是否删除整个目录
DeleteProfile := ExpandConstant('{app}');
DeleteConfirm :=MsgBox('是否保留数据库数据?',mbConfirmation,MB_YESNO) = idYes;
if DeleteConfirm=False then
DelTree(ExpandConstant('{app}'), True, True, True);
end;
end;
end;

参考:

Inno Setup添加自定义页面

使用innoSetup将mysql+nginx+redis+jar包打包成windows安装包