Inno Setup打包美化

正文

原项目

https://github.com/anchengjian/vue-nw-seed/tree/win-beautiful-setup

我们只优化打包的美化,所以只用到下面的两个

另一个美化的地址
https://github.com/Iseason2000/MinecraftInstaller

其中主要就是 [code] 块下面的 Pascal Script ,通过它来控制安装流程和界面的美化。

  • 控制安装流程的原理是 InnoSetup 通过 Pascal Scripting: Event Functions 这种事件机制,把流程节点的控制交给 Pascal Script ,使其可以控制上一步下一步等等的操作。
  • 界面的美化,主要是调用两个美化插件动态库:botva2.dllInnoCallback.dll。用其来控制贴图的位置和样式,和给按钮绑定相应的事件等等的。

美化包

链接:https://pan.baidu.com/s/1LiksgirjJLYRDEP0-t8xUA
提取码:psvm

运行效果

image-20220922104258733

image-20220922104322556

image-20220922104340736

整体代码

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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
; 该执行目录为 setup.iss 所在的目录,请注意拼接相对目录
#define MyAppId "{{1AC4D338-0D28-47E4-9FC7-18929EDDF90D}"
#define MyAppName "xhschool_test"
#define MyAppNameZh "星火智慧课堂测试版"
#define MyAppVersion "3.4.5"
#define MyAppPublisher "码客说"
#define MyAppURL "www.psvmc.cn"
; 打包文件
#define MyAppExeName "xhschool.exe"
#define SourceMain "D:\Project\CSharp\schoolclient\bin\x86\Debug\xhschool.exe"
#define SourceFolder "D:\Project\CSharp\schoolclient\bin\x86\Debug\*"
#define SetupIconFilePath "D:\Project\CSharp\schoolclient\bin\x86\Debug\favicon256.ico"
; 打包生成位置
#define OutputPath "D:\程序打包\星火智慧课堂-测试版\"
#define OutputFileName "星火智慧课堂测试版"
; license文件
#define LicenseFilePath "D:\Tools\InnoSetup\setup_resources\license.txt"
; 美化资源文件
#define ResourcesPath "D:\Tools\InnoSetup\setup_resources\*"

[setup]
AppId={#MyAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppName}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#MyAppName}
LicenseFile={#LicenseFilePath}
OutputDir={#OutputPath}
OutputBaseFilename={#OutputFileName}v{#MyAppVersion}
SetupIconFile={#SetupIconFilePath}
Compression=lzma
SolidCompression=yes
PrivilegesRequired=admin
Uninstallable=yes
UninstallDisplayName={#MyAppNameZh}
DefaultGroupName={#MyAppNameZh}
Versioninfodescription={#MyAppName} 安装程序
versioninfocopyright=Copyright(c) 2022
VersionInfoProductName={#MyAppName}
DisableReadyPage=yes
DisableProgramGroupPage=yes
DirExistsWarning=no
DisableDirPage=yes

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce

[Files]
Source: {#ResourcesPath}; DestDir: {tmp}; Flags: dontcopy solidbreak ; Attribs: hidden system
Source: {#SourceMain}; DestDir: "{app}"; Flags: ignoreversion
Source: {#SourceFolder}; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Messages]
SetupAppTitle={#MyAppName} 安装向导
SetupWindowTitle={#MyAppName} 安装向导

[Icons]
Name: "{commondesktop}\{#MyAppNameZh}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{group}\{#MyAppNameZh}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\卸载{#MyAppNameZh}"; Filename: "{uninstallexe}"


[Code]
// for dll
type
TBtnEventProc = procedure (h:HWND);
TPBProc = function(h:hWnd;Msg,wParam,lParam:Longint):Longint; //百分比
TTimerProc = procedure(h:longword; msg:longword; idevent:longword; dwTime:longword);
const
Radius = 9;
GWL_EXSTYLE = (-20);
//窗口移动
WM_SYSCOMMAND = $0112;
WS_EX_LAYERED = $80000;
WS_EX_TRANSPARENT = $20;
LWA_COLORKEY = 1;
TransparentColor = clLime; //要去掉的图片底色
TransparentPercent = 80;
BTN_MAX_PATH = 1024;

BtnClickEventID = 1;
BtnMouseEnterEventID = 2;
BtnMouseLeaveEventID = 3;
BtnMouseMoveEventID = 4;
BtnMouseDownEventID = 5;
BtnMouseUpEventID = 6;

//function WrapBtnCallback(Callback: TBtnEventProc; ParamCount: Integer): Longword; external 'wrapcallback@files:innocallback.dll stdcall';
function WrapTimerProc(callback: TTimerProc; Paramcount: Integer): Longword; external 'wrapcallback@files:innocallback.dll stdcall';

function DeleteObject(p1: Longword): BOOL; external 'DeleteObject@gdi32.dll stdcall';
function GetPM(nIndex:Integer):Integer; external 'GetSystemMetrics@user32.dll stdcall';
//botva2
function ImgLoad(Wnd :HWND; FileName :PAnsiChar; Left, Top, Width, Height :integer; Stretch, IsBkg :boolean) :Longint; external 'ImgLoad@{tmp}\botva2.dll stdcall delayload';
procedure ImgSetVisibility(img :Longint; Visible :boolean); external 'ImgSetVisibility@{tmp}\botva2.dll stdcall delayload';
procedure ImgApplyChanges(h:HWND); external 'ImgApplyChanges@{tmp}\botva2.dll stdcall delayload';
procedure ImgSetPosition(img :Longint; NewLeft, NewTop, NewWidth, NewHeight :integer); external 'ImgSetPosition@files:botva2.dll stdcall';
procedure ImgRelease(img :Longint); external 'ImgRelease@{tmp}\botva2.dll stdcall delayload';
procedure gdipShutdown; external 'gdipShutdown@{tmp}\botva2.dll stdcall delayload';
function WrapBtnCallback(Callback: TBtnEventProc; ParamCount: Integer): Longword; external 'wrapcallback@{tmp}\innocallback.dll stdcall delayload';
function BtnCreate(hParent:HWND; Left,Top,Width,Height:integer; FileName:PAnsiChar; ShadowWidth:integer; IsCheckBtn:boolean):HWND; external 'BtnCreate@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetText(h:HWND; Text:PAnsiChar); external 'BtnSetText@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetVisibility(h:HWND; Value:boolean); external 'BtnSetVisibility@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetFont(h:HWND; Font:Cardinal); external 'BtnSetFont@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetFontColor(h:HWND; NormalFontColor, FocusedFontColor, PressedFontColor, DisabledFontColor: Cardinal); external 'BtnSetFontColor@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetEvent(h:HWND; EventID:integer; Event:Longword); external 'BtnSetEvent@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetCursor(h:HWND; hCur:Cardinal); external 'BtnSetCursor@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetEnabled(h:HWND; Value:boolean); external 'BtnSetEnabled@{tmp}\botva2.dll stdcall delayload';
function GetSysCursorHandle(id:integer):Cardinal; external 'GetSysCursorHandle@{tmp}\botva2.dll stdcall delayload';
function BtnGetChecked(h:HWND):boolean; external 'BtnGetChecked@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetChecked(h:HWND; Value:boolean); external 'BtnSetChecked@{tmp}\botva2.dll stdcall delayload';
procedure CreateFormFromImage(h:HWND; FileName:PAnsiChar); external 'CreateFormFromImage@{tmp}\botva2.dll stdcall delayload';
procedure BtnSetPosition(h:HWND; NewLeft, NewTop, NewWidth, NewHeight: integer); external 'BtnSetPosition@{tmp}\botva2.dll stdcall delayload';
function SetLayeredWindowAttributes(hwnd:HWND; crKey:Longint; bAlpha:byte; dwFlags:longint ):longint;
external 'SetLayeredWindowAttributes@user32 stdcall'; //函数声明
function SetWindowLong(Wnd: HWnd; Index: Integer; NewLong: Longint): Longint; external 'SetWindowLongA@user32.dll stdcall';
function PBCallBack(P:TPBProc;ParamCount:integer):LongWord; external 'wrapcallback@files:innocallback.dll stdcall';
function CallWindowProc(lpPrevWndFunc: Longint; hWnd: HWND; Msg: UINT; wParam, lParam: Longint): Longint; external 'CallWindowProcA@user32.dll stdcall';
procedure ImgSetVisiblePart(img:Longint; NewLeft, NewTop, NewWidth, NewHeight : integer); external 'ImgSetVisiblePart@files:botva2.dll stdcall';
function SetTimer(hWnd: LongWord; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord; external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: LongWord; nIDEvent: LongWord): LongWord; external 'KillTimer@user32.dll stdcall';
function GetWindowLong(Wnd: HWnd; Index: Integer): Longint; external 'GetWindowLongA@user32.dll stdcall';
function ReleaseCapture(): Longint; external 'ReleaseCapture@user32.dll stdcall';
function CreateRoundRectRgn(p1, p2, p3, p4, p5, p6: Integer): THandle; external 'CreateRoundRectRgn@gdi32 stdcall';
function SetWindowRgn(hWnd: HWND; hRgn: THandle; bRedraw: Boolean): Integer; external 'SetWindowRgn@user32 stdcall';
procedure ShapeForm(aForm: TForm; edgeSize: integer); //圆角
var
FormRegion:LongWord;
begin
FormRegion:=CreateRoundRectRgn(0,0,aForm.Width,aForm.Height,edgeSize,edgeSize);
SetWindowRgn(aForm.Handle,FormRegion,True);
end;

// 安装前强制杀进
// 该函数在安装程序初始化时调用,返回False 将中断安装,True则继续安装.程
function InitializeSetup(): Boolean;
var ErrorCode: Integer;
begin
ShellExec('open','taskkill.exe','/f /im {#MyAppExeName}','',SW_HIDE,ewNoWait,ErrorCode);
ShellExec('open','tskill.exe',' {#MyAppName}','',SW_HIDE,ewNoWait,ErrorCode);
result := True;
end;

// 卸载前强制杀进程
function InitializeUninstall(): Boolean;
var ErrorCode: Integer;
begin
ShellExec('open','taskkill.exe','/f /im {#MyAppExeName}','',SW_HIDE,ewNoWait,ErrorCode);
ShellExec('open','tskill.exe',' {#MyAppName}','',SW_HIDE,ewNoWait,ErrorCode);
result := True;
end;

var
BGimg:longint;
btnShowLicense,MinBtn,CancelBtn,btnBrowser,btnSetup,btnBack:HWND;
isWelcomePage:boolean;
pathEdit:tedit;
labelReadImg,licenseImg,progressbgImg,PBOldProc,labelAutoRunImg:longint;
checkboxLicense,checkboxAutoRun:HWND;
licenseRich:TRichEditViewer;

// 向导调用这个事件函数确定是否在所有页或不在一个特殊页 (用PageID 指定) 显示。如果返回True,将跳过该页;如果你返回False,该页被显示。
// 注意: 这个事件函数不被wpWelcome、wpPreparing 和wpInstalling 页调用,还有安装程序已经确定要跳过的页也不会调用
// wpWelcome, wpLicense, wpPassword, wpInfoBefore, wpUserInfo, wpSelectDir, wpSelectComponents, wpSelectProgramGroup, wpSelectTasks, wpReady, wpPreparing, wpInstalling, wpInfoAfter, wpFinished
function ShouldSkipPage(PageID: Integer): Boolean;
begin
if PageID=wpLicense then
result:=true;
if PageID=wpInfoBefore then
result:=true;
if PageID=wpUserInfo then
result:=true;
if PageID=wpSelectDir then
result:=true;
if PageID=wpSelectComponents then
result:=true;
if PageID=wpSelectProgramGroup then
result:=true;
if PageID=wpSelectTasks then
result:=true;
end;

// 关闭按钮
procedure CancelBtnOnClick(hBtn:HWND);
begin
WizardForm.CancelButton.OnClick(WizardForm);
end;

// 最小化按钮
procedure MinBtnOnClick(hBtn:HWND);
begin
SendMessage(WizardForm.Handle,WM_SYSCOMMAND,61472,0);
end;

// 浏览文件夹按钮
procedure btnBrowserclick(hBtn:HWND);
begin
WizardForm.DirBrowseButton.OnClick(WizardForm);
pathEdit.text := WizardForm.DirEdit.text;
end;

// 路径选择器 change
procedure pathEditChange(Sender: TObject);
begin
WizardForm.DirEdit.text:=pathEdit.Text ;
end;

// 立即安装等按钮的操作就是不断地下一步
procedure nextSetpBtnClick(hBtn:HWND);
begin
WizardForm.NextButton.OnClick(WizardForm);
end;

// 安装的进度条
function PBProc(h:hWnd;Msg,wParam,lParam:Longint):Longint;
var
pr,i1,i2 : Extended;
w : integer;
begin
Result:=CallWindowProc(PBOldProc,h,Msg,wParam,lParam);
if (Msg=$402) and (WizardForm.ProgressGauge.Position>WizardForm.ProgressGauge.Min) then
begin
i1:=WizardForm.ProgressGauge.Position-WizardForm.ProgressGauge.Min;
i2:=WizardForm.ProgressGauge.Max-WizardForm.ProgressGauge.Min;
pr:=i1*100/i2;
w:=Round(650*pr/100);
ImgSetPosition(progressbgImg,0,320,w,15);
ImgSetVisiblePart(progressbgImg,0,0,w,15);
ImgApplyChanges(WizardForm.Handle);
end;
end;

// 鼠标拖动
procedure WizardMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture
SendMessage(WizardForm.Handle, $0112, $F012, 0)
end;

// 查看 license
procedure btnShowLicenseClick(hBtn:HWND);
begin
if isWelcomePage=true then
begin
licenseImg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\bg_license.png'),0,0,650,450,false,false);
isWelcomePage:=false
licenseRich.Height:=295
BtnSetVisibility(checkboxLicense,false)
BtnSetVisibility(btnShowLicense,false)
BtnSetVisibility(btnSetup,false)
BtnSetVisibility(btnBrowser,false)
pathEdit.Hide
BtnSetVisibility(btnBack,true)
end else
begin
isWelcomePage:=true
BGimg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\bg_welcome.png'),0,0,650,450,false,true);
labelReadImg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\label_read.png'),243,398,72,20,false,true);
licenseRich.Height:=0
BtnSetVisibility(checkboxLicense,true)
BtnSetVisibility(btnShowLicense,true)
BtnSetVisibility(btnSetup,true)
ImgRelease(licenseImg)
BtnSetVisibility(btnBrowser,true)
pathEdit.show
BtnSetVisibility(btnBack,false)
end;
ImgApplyChanges(WizardForm.Handle)
end;

// 勾选查看 license
procedure checkboxLicenseClick(hBtn:HWND);
begin
if BtnGetChecked(checkboxLicense)=true then
begin
BtnSetEnabled(btnSetup,true)
end else
begin
BtnSetEnabled(btnSetup,false)
end
end;

// 该过程在开始的时候改变向导或者向导页,不要指望使用InitializeSetup函数实现改变向导页的功能,因为InitializeSetup函数触发时向导窗口并不存在。
procedure InitializeWizard();
var
MainLabel: TLabel;
begin
// 设置欢迎向导页的尺寸大小
WizardForm.OuterNotebook.hide;
WizardForm.Bevel.Hide;
WizardForm.BorderStyle:=bsnone;
WizardForm.Position:=poScreenCenter;
// WizardForm.Center;
WizardForm.Width:=650;
WizardForm.Height:=450;
// WizardForm.Color:=clWhite;
isWelcomePage:=true;
// WizardForm.InnerNotebook.Hide;
// wizardform.Color:=TransparentColor;

// 添加可以拖动窗口的Label
MainLabel := TLabel.Create(WizardForm);
MainLabel.Parent := WizardForm;
MainLabel.AutoSize := False;
MainLabel.Left := 0;
MainLabel.Top := 0;
MainLabel.Width := WizardForm.Width;
MainLabel.Height := WizardForm.Height;
MainLabel.Caption := '';
MainLabel.Transparent := True;
MainLabel.OnMouseDown := @WizardMouseDown;

// 加载资源到 tmp 临时目录
ExtractTemporaryFile('bg_welcome.png');
ExtractTemporaryFile('bg_installing.png');
ExtractTemporaryFile('bg_license.png');
ExtractTemporaryFile('label_read.png');
ExtractTemporaryFile('label_license.png');
ExtractTemporaryFile('license.txt');
ExtractTemporaryFile('btn_close.png');
ExtractTemporaryFile('btn_min.png');
ExtractTemporaryFile('btn_back.png');
ExtractTemporaryFile('btn_setup.png');
ExtractTemporaryFile('btn_browser.png');
ExtractTemporaryFile('checkbox.png');
ExtractTemporaryFile('bg_finished.png');
ExtractTemporaryFile('btn_complete.png');
ExtractTemporaryFile('loading.png');
ExtractTemporaryFile('label_autorun.png');

// 关闭按钮样式
CancelBtn:=BtnCreate(WizardForm.Handle,627,8,12,12,ExpandConstant('{tmp}\btn_close.png'),1,False)
BtnSetEvent(CancelBtn,BtnClickEventID,WrapBtnCallback(@CancelBtnOnClick,1));

// 最小化按钮样式
MinBtn:=BtnCreate(WizardForm.Handle,607,8,12,12,ExpandConstant('{tmp}\btn_min.png'),1,False)
BtnSetEvent(MinBtn,BtnClickEventID,WrapBtnCallback(@MinBtnOnClick,1));

// 立即安装按钮样式
btnSetup:=BtnCreate(WizardForm.Handle,195,340,260,44,ExpandConstant('{tmp}\btn_setup.png'),1,False)
BtnSetEvent(btnSetup,BtnClickEventID,WrapBtnCallback(@nextSetpBtnClick,1));

// 返回按钮样式
btnBack:=BtnCreate(WizardForm.Handle,285,390,80,32,ExpandConstant('{tmp}\btn_back.png'),1,False)
BtnSetEvent(btnBack,BtnClickEventID,WrapBtnCallback(@btnShowLicenseClick,1));
BtnSetVisibility(btnBack,false)

pathEdit:= TEdit.Create(WizardForm);
with pathEdit do
begin
Parent:=WizardForm;
text:=WizardForm.DirEdit.text;
Font.Name:='宋体'
BorderStyle:=bsNone;
SetBounds(110,272,340,15)
OnChange:=@pathEditChange;
TabStop:=false;
end;

// 浏览按钮样式
btnBrowser:=BtnCreate(WizardForm.Handle,470,263,80,32,ExpandConstant('{tmp}\btn_browser.png'),1,False)
BtnSetEvent(btnBrowser,BtnClickEventID,WrapBtnCallback(@btnBrowserclick,1));

PBOldProc:=SetWindowLong(WizardForm.ProgressGauge.Handle,-4,PBCallBack(@PBProc,4));

// 查看 license 的文本区域
licenseRich:= TRichEditViewer.Create(WizardForm);
with licenseRich do
begin
Parent:=WizardForm;
ReadOnly:=true;
SCROLLBARS:=ssVertical;
font.Name:='宋体'
Color:=clWhite;
BorderStyle:=bsNone;
SetBounds(40,65,570,0)
Lines.LoadFromFile(ExpandConstant('{tmp}\license.txt'));
TabStop:=false;
end;

ImgApplyChanges(WizardForm.Handle)
end;

// 该过程在安装终止时被调用,注意及时在用户没有安装任何文件之前退出也会被调用。
procedure DeinitializeSetup();
var RCode: Integer;
begin
// 检查是否需要自动运行
if BtngetChecked(checkboxAutoRun)=true then
begin
Exec(ExpandConstant('{app}\{#MyAppExeName}'),'','',SW_SHOW, ewNoWait,RCode);
end;

gdipShutdown;
end;

// 在新向导页 (由CurPageID 指定) 显示后调用。
procedure CurPageChanged(CurPageID: Integer);
begin
// 默认的流程按钮隐藏掉
WizardForm.NextButton.Visible:=false;
WizardForm.CancelButton.Height:=0;
WizardForm.BackButton.Height:=0;

if CurPageID=wpWelcome then
begin
BGimg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\bg_welcome.png'),0,0,650,450,true,true);

// license 提示
checkboxLicense:=BtnCreate(WizardForm.Handle,220,400,16,16,ExpandConstant('{tmp}\checkbox.png'),1,true)
BtnSetEvent(checkboxLicense,BtnClickEventID,WrapBtnCallback(@checkboxLicenseClick,1))

// 默认勾选 阅读并同意
BtnSetChecked(checkboxLicense,true)
labelReadImg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\label_read.png'),243,398,39,20,false,true);
btnShowLicense:=BtnCreate(WizardForm.Handle,282,398,65,20,ExpandConstant('{tmp}\label_license.png'),4,false)
BtnSetEvent(btnShowLicense,BtnClickEventID,WrapBtnCallback(@btnShowLicenseClick,1))

WizardForm.Width:=650;
WizardForm.Height:=450;
WizardForm.Show;
end;

if CurPageID = wpInstalling then
begin
BtnSetPosition(checkboxLicense,560,421,75,15);
pathEdit.Hide;
BtnSetVisibility(btnBrowser,false)
WizardForm.Height:=450
BtnSetVisibility(btnShowLicense,false);
BtnSetVisibility(checkboxLicense,false);
BGimg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\bg_installing.png'),0,0,650,450,false,true);

progressbgImg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\loading.png'),0,320,0,0,True,True);

BtnSetVisibility(btnSetup,false);
end;

if CurPageID = wpFinished then
begin
ImgSetVisibility(progressbgImg,false)
btnSetup:=BtnCreate(WizardForm.Handle,195,340,260,44,ExpandConstant('{tmp}\btn_complete.png'),1,False)
BtnSetEvent(btnSetup,BtnClickEventID,WrapBtnCallback(@nextSetpBtnClick,1));

BGimg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\bg_finished.png'),0,0,650,450,false,true);

// 是否自动运行
checkboxAutoRun:=BtnCreate(WizardForm.Handle,275,400,16,16,ExpandConstant('{tmp}\checkbox.png'),1,true)
labelAutoRunImg:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}\label_autorun.png'),295,398,84,20,false,true);

// 默认勾选
BtnSetChecked(checkboxAutoRun,true);

// 完成页面隐藏关闭和最小化
BtnSetVisibility(CancelBtn,false);
BtnSetVisibility(MinBtn,false);
end;

ImgApplyChanges(WizardForm.Handle)
end;

兼容问题

窗口拖动

因为Inno5.5之后,WizardForm不再支持OnMouseDown, 所以首先我们要先创建一个Label覆盖窗口,再将label设置为透明,由Label来重载OnMouseDown。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var
MainLabel: TLabel;

MainLabel := TLabel.Create(WizardForm);
MainLabel.Parent := WizardForm;
MainLabel.AutoSize := False;
MainLabel.Left := 0;
MainLabel.Top := 0;
MainLabel.Width := WizardForm.Width;
MainLabel.Height := 50;
MainLabel.Caption := '';
MainLabel.Transparent := True;
MainLabel.OnMouseDown := @WizardFormMouseDown;


//窗口移动
procedure WizardFormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
SendMessage(WizardForm.Handle, WM_SYSCOMMAND, $F012, 0);
end;

高分屏缩放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Code]
var
DpiScalePctg:integer;
CurrentDPI:integer;

procedure InitializeWizard();
begin
CurrentDPI := WizardForm.Font.PixelsPerInch;
DpiScalePctg := 1000* CurrentDPI / 96;
end;

function DpiScale(v:integer):integer;
begin
Result:=v*DpiScalePctg/1000;
end;

自定义语法

创建文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var lblWelcome:TLabel;

begin
lblWelcome := TLabel.Create(WizardForm);
with lblWelcome do
begin
Parent := WizardForm;
Caption := '欢迎安装XXX应用程序';
Transparent := true;
Font.Size:= 20
Font.Name:='黑体'
Font.Color:=$ffffff
Left := DpiScale(190);
Top := DpiScale(195);
end;
end;

创建按钮

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
var
btnOneKey:HWND;
BtnOneKeyFont:TFont;
begin
// 创建按钮
btnOneKey:=BtnCreate(WizardForm.Handle,DpiScale(240),DpiScale(260),DpiScale(177), DpiScale(43),
ExpandConstant('{tmp}\btnOneKeyInstall.png'), 1, False);

//设置按钮文字
BtnSetText(btnOneKey, '一键安装');
//文字字体
BtnOneKeyFont:= TFont.Create;
with BtnOneKeyFont do begin
Size := 20;
Name:='黑体';
Color:=$ffffff;
end;
//应用字体
BtnSetFont(btnOneKey, BtnOneKeyFont.Handle);
BtnSetFontColor(btnOneKey,$FAFAFA,$FFFFFF,$FFFFFF,$FFFFFF);
//设置按钮点击函数
BtnSetEvent(btnOneKey, BtnClickEventID, WrapBtnCallback(@btnOneKey_OnClick,1));
end;

// 按钮点击回调
procedure btnOneKey_OnClick(hBtn:HWND);
begin
WizardForm.NextButton.OnClick(WizardForm);
WizardForm.NextButton.OnClick(WizardForm);
end;

创建图片

1
2
3
4
5
6
7
8
9
10
11
12
13
var
imgBg1:Longint;
winW:integer;
winH:integer;
begin
//窗口宽高
winW:=DpiScale(660)
winH:=DpiScale(480)
//创建背景图
imgBg1 := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\bg.png'), (0), (0), winW, winH, True, True);
//设置背景图的隐藏
//ImgSetVisibility(imgBg1, false);
end

启动定时器

1
2
3
4
5
6
SetTimer(0, 0, 50, WrapTimerProc(@PageInstall_TimerProc, 4));

procedure PageInstall_TimerProc(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
begin
//轮播背景图逻辑
end

创建输入编辑框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
begin
edtSelectDir1 := TEdit.Create(WizardForm);
with edtSelectDir1 do
begin
Parent:= WizardForm;
Text := WizardForm.DirEdit.Text;
Font.Size:= 10
Font.Color:=$555555
Left:= DpiScale(132);
Top := DpiScale(189);
Width:= DpiScale(311);
Height:= DpiScale(24);
BorderStyle:=bsNone;
TabStop := false;
OnChange:=@EdtSelectDir1_EditChanged;
end;
end

设置UI对象显示与隐藏

1
2
3
4
5
6
7
//隐藏按钮
BtnSetVisibility(btn, false);
//隐藏图片
ImgSetVisibility(imgBig, false);
//隐藏文本TLabel、隐藏输入框TEdit
TconSetVisible(lbl, false);
TconSetVisible(edt, false);

监听安装进度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//设置监听
PBOldProc:=SetWindowLong(WizardForm.ProgressGauge.Handle,-4, PBCallBack(@PBProc,4));

//回调
function PBProc(h:hWnd;Msg, wParam,lParam:Longint):Longint;
var
pr, pos,total: Longint;
w : integer;
begin
// CallWindowProc是将消息信息传送给指定的窗口过程的函数
Result:=CallWindowProc(PBOldProc, h, Msg, wParam,lParam);
if (Msg=$402) and (WizardForm.ProgressGauge.Position > WizardForm.ProgressGauge.Min) then
begin
pos:=WizardForm.ProgressGauge.Position-WizardForm.ProgressGauge.Min;
total:=WizardForm.ProgressGauge.Max-WizardForm.ProgressGauge.Min;
pr:=pos*100/total;
//更新进度条
PageInstall_SetProgress(pr);
Notify_DoNotifyProgress(pos, total);
end;
end;

解压图片

要先把图片包含在安装包中

1
2
[Files]
Source: {#ResourcesPath}; DestDir: {tmp}; Flags: dontcopy solidbreak ; Attribs: hidden system

将tmp的资源, 解压到安装运行时搞出来的临时目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ExtractTemporaryFile('bg_welcome.png');
ExtractTemporaryFile('bg_installing.png');
ExtractTemporaryFile('bg_license.png');
ExtractTemporaryFile('label_read.png');
ExtractTemporaryFile('label_license.png');
ExtractTemporaryFile('license.txt');
ExtractTemporaryFile('btn_close.png');
ExtractTemporaryFile('btn_min.png');
ExtractTemporaryFile('btn_back.png');
ExtractTemporaryFile('btn_setup.png');
ExtractTemporaryFile('btn_browser.png');
ExtractTemporaryFile('checkbox.png');
ExtractTemporaryFile('bg_finished.png');
ExtractTemporaryFile('btn_complete.png');
ExtractTemporaryFile('loading.png');
ExtractTemporaryFile('label_autorun.png');

使用

1
btnSetup:=BtnCreate(WizardForm.Handle,195,340,260,44,ExpandConstant('{tmp}\btn_setup.png'),1,False)

目录常量

{app}

应用程序目录,这是用户在安装向导的选择安装目录页里面所选择的。这是Inno Setup中最常用的一个变量。

{userappdata}

类似于这样的目录C:\Users\Administrator\AppData\Roaming\

{autopf}

类似于C:\Program Files (x86)\或者C:\Program Files\

{pf}

也是Inno Setup中比较常用的一个常量,这个路径是系统的Program Files目录,典型的是C:\Program Files

{tmp}

临时目录,这个目录并不是用户的 TEMP 环境变量指向的目录,而是安装程序在启动时在用户的临时目录下建立的一个子目录(它有一个类似于C:\WINDOWS\TEMP\IS-xxxxx.tmp这样的名字),在安装程序退出时所有的文件和子目录将会被删除。对于在 [Run] 段里面要被执行且在安装以后又不需要的程序文件来说这个功能是非常有用的。

{win}

系统的Windows目录,一般为C:\WINDOWS。例如:如果你使用了 {win}”MYPROG.INI ,而你的 Windows 目录是C:\WINDOWS,那么安装程序就会将它转换成C:\WINDOWS\MYPROG.INI

{sys}

系统的 Windows 系统(System)目录(在 Windows NT/2000 下是 System32)。 例如:如果你使用了 {sys}\CTL3D32.DLL,并且系统的 Windows 系统目录是C:\WINDOWS\SYSTEM,那么安装程序就会将它转换成C:\WINDOWS\SYSTEM\CTL3D32.DLL

{src}

指向安装程序所在的位置。

{sd}

系统驱动器,它是指 Windows 被安装到的那个驱动器,典型的是C:,对于 Windows NT/2000,这个常量同系统的环境变量“SystemDrive”是等效的。

{cf}

公共文件夹(Common Files),这个路径是系统的 Common Files 文件夹,典型的是C:\Program Files\Common Files

{fonts}

字体目录。

{dao}

DAO 目录,当安装程序运行在 Windows 95/NT 4+ 上时,它被等效为 {cf}\Microsoft Shared\DAO

当运行于 Windows NT 3.51 时,它被等效为 { win}\MSAPPS\DAO