前言
最近想把自己写的Windows端的软件打包成安装程序exe,又觉得自带的界面太丑了,想自己完全做一个新的页面
网上找到的只有基础教程,记录一下进阶学习过程
生命周期
按照Vue的说法叫生命周期,Inno Setup中叫 Pascal 脚本: 事件函数。
安装程序事件函数
安装程序支持下列事件函数:
function InitializeSetup(): Boolean;
在安装程序初始化期间调用。返回 False 以中止 Setup,否则返回 True。
// 检查应用程序是否正在运行
function IsAppRunning(const AppName : string) : Boolean;
begin
// 如果找到窗口名称,则应用程序正在运行
Result := (FindWindowByWindowName(AppName) <> 0);
end;
// 检查应用程序是否已安装
function IsAppInstalled() : Boolean;
begin
// 检查注册表项是否存在
Result := RegKeyExists(HKLM, 'SOFTWARE\{#MyAppName}');
end;
// 初始化安装程序
function InitializeSetup(): Boolean;
begin
// 初始化变量
_isInstall := false;
Result := true;
// 检查应用程序是否正在运行
if IsAppRunning('{#MyAppWindowName}') then
begin
_isInstall := true;
Msgbox('{#Tip_AppRunningInstall}', mbInformation, MB_OK);
Result := false;
end;
// 检查应用程序是否已安装
if Result and IsAppInstalled() then
begin
_isInstall := true;
Result := (Msgbox({#Tip_AppReinstall}, mbConfirmation, MB_YESNO) = IDYES);
end;
end;
procedure InitializeWizard();
在启动时使用该事件函数来改变向导或向导页面。你不能在它被触发时使用 InitializeSetup 事件函数,因为向导窗体尚不存在。
procedure DeinitializeSetup();
仅在安装程序终止前调用。注意这个函数在即使用户在任何内容安装之前退出安装程序时也会调用。
procedure CurStepChanged(CurStep: TSetupStep);
你可以用这个事件函数执行你自己的预安装和安装后任务。
在实际安装开始之前用 CurStep=ssInstall 调用,或在实际安装完成之后用 CurStep=ssPostInstall 调用,或在安装程序终止之前和安装完成之后用 CurStep=ssDone 调用。
procedure CurInstallProgressChanged(CurProgress, MaxProgress: Integer);
在安装程序提取文件、创建快捷方式、创建 INI 条目和创建注册表项时,你可以使用该事件函数来监测进程。
function NextButtonClick(CurPageID: Integer): Boolean;
当用户单击下一步按钮时调用。如果你返回 True,向导将移到下一页面;如果返回 False,它仍保留在当前页面(用 CurPageID 指定)。
注意,该函数在静默安装时也会调用,即使没有下一步按钮让用户单击。安装程序会模拟单击下一步按钮。在静默安装中,如果你的 NextButtonClick 函数在安装之前返回 False,安装程序将自动退出。
function BackButtonClick(CurPageID: Integer): Boolean;
当用户单击上一步按钮时调用。如果你返回 True,向导将移到上一页面;如果返回 False,它仍保留在当前页面(用 CurPageID 指定)。
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
当用户单击取消按钮或单击窗口中的关闭按钮时调用。Cancel 参数指定是否是一般的取消进程;默认为 True。Confirm 参数指定是否显示“退出安装程序吗?”的消息框;一般它默认为 True。如果 Cancel 设为 False,那么 Confirm 值被忽略。
function ShouldSkipPage(PageID: Integer): Boolean;
向导调用这个事件函数确定是否在所有页面或不在一个特殊页面(用 PageID 指定)显示。如果返回 True,将跳过该页面;如果你返回 False,该页面被显示。
注意:这个事件函数不被 wpWelcome、wpPreparing 和 wpInstalling 页面调用,还有安装程序已经确定要跳过的页面也不会调用(例如,没有包含组件安装程序的 wpSelectComponents)。
procedure CurPageChanged(CurPageID: Integer);
在新向导页面(用 CurPageID 指定)显示后调用。
function CheckPassword(Password: String): Boolean;
如果安装程序在 Pascal 脚本中发现 CheckPassword 事件函数,它自动显示密码页面并调用 CheckPassword 检查密码。返回 True 表示接受密码,返回 False 拒绝。
要避免在编译的安装程序的 [Code] 区段内部贮存真实的密码,你应该用其它无用的信息进行比较: 计算你自己密码的 SHA1 的无用信息,然后编译到 GetSHA1OfString(Password)。通过这种方法保护实际密码值。
注意:如果安装程序带一个 /PASSWORD= 命令行参数运行,则你的 CheckPassword 函数将在任何其他事件函数之前 被调用,包括 InitializeSetup。
function NeedRestart(): Boolean;
返回 True 告诉安装程序提示用户在安装结束时重新启动系统,False 则反之。
function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
如果安装程序在 Pascal 脚本中发现 UpdateReadyMemo 事件函数,当准备安装 向导页面变为活动页面时自动调用。它返回的文字显示在准备安装 向导页面的设置备注中,作为由 NewLine 参数分隔行的单个字串。参数 Space 包含一个带空格的字串。安装程序使用该字串来进行缩进设置。其它参数将包含安装程序用于设置区段的字串(可能是空的)。例如 MemoDirInfo 参数包含象选择目录 区段的字串。
procedure RegisterPreviousData(PreviousDataKey: Integer);
要在自定义向导页面中贮存用户输入的设置,在 Pascal 脚本中放入一个 RegisterPreviousData 事件函数,并调用 SetPreviousData(PreviousDataKey, ...) 替换它,每个设置一次。
function CheckSerial(Serial: String): Boolean;
如果安装程序在 Pascal 脚本中发现 CheckSerial 事件函数,将在用户信息向导页面中自动出现一个序列号对象(必须在你的 [Setup] 区段中使用 UserInfoPage=yes !)。返回 True 表示接受序列号,返回 False 拒绝。当使用序列号时,请一定要记住,这个软件无加密可言,况且 Inno Setup 源代码是免费获取的,它对于有经验的人从安装程序中删除序列号保护并不是很困难的事。使用这个只是方便用户在你的应用程序中仔细检查输入的序列号(贮存在 {userinfoserial} 常量)。
function GetCustomSetupExitCode: Integer;
返回一个非零值命令安装程序返回一个自定义退出代码。这个函数只在安装程序运行完成并且退出代码已是零时调用。同时请参见安装退出代码。
function PrepareToInstall(var NeedsRestart: Boolean): String;
你可以使用该事件函数来监测并安装丢失的先决条件和/或关闭任何有关被更新的应用程序。
返回非空字串以指示安装程序停止在准备安装向导页面,将返回的字串显示为错误消息。如果需要重新启动,请将 NeedsRestart 设置为 True(并返回非空字串)。如果以这种方式停止安装程序,它将使用安装程序退出代码中所述的专用退出代码退出。在这种情况下,不会使用由 /RESTARTEXITCODE= 命令行参数设置的任何自定义退出代码。
如果 CloseApplications 设置为 yes,则在安装程序对正在使用的文件检查前,该事件函数被调用。
仅当安装程序尚未确定无法继续时才会调用此函数,因为 [Files] 和 [InstallDelete] 区段中指定的一个或多个文件已队列(通过某些其他安装),以便在下次重新启动时进行替换或删除。
procedure RegisterExtraCloseApplicationsResources;
如果 CloseApplications 被设置为 yes,则要注册安装程序会检查正在使用的那个额外文件,在 Pascal 脚本中放置一个 RegisterExtraCloseApplicationsResources 事件函数,并在其内部调用 RegisterExtraCloseApplicationsResource,每次一个文件。
卸载事件函数
卸载支持下列函数:
function InitializeUninstall(): Boolean;
返回 False 中止卸载,True 则反之。
procedure InitializeUninstallProgressForm();
使用该事件函数对进度窗体在启动时进行更改。你不能使用 InitializeUninstall 事件函数,因为在它被触发时该进度窗体尚不存在。
procedure DeinitializeUninstall();
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
function UninstallNeedRestart(): Boolean;
返回 True 以指示卸载程序在成功卸载结束时,提示用户重新启动系统,False 则反之。
通过事件函数,就可以完成部分自己想要的功能,我们在其中最主要的就是禁用原有的安装界面,自己绘制安装界面
页面
在安装流程中一共有这些页面
wpWelcome, wpLicense, wpPassword, wpInfoBefore, wpUserInfo, wpSelectDir, wpSelectComponents, wpSelectProgramGroup, wpSelectTasks, wpReady, wpPreparing, wpInstalling, wpInfoAfter, wpFinished
我们通过在wpWelcome页面的时候,来创建安装界面,再去监听wpInstalling来更新进度条,wpFinished的时候来选择是否打开或者是否重启
废话不多说直接上代码!
利用定义ShouldSkipPage函数才跳过部分页面
// 定义一个函数,决定是否跳过某个安装页面
function ShouldSkipPage(PageID : integer) : boolean;
begin
// 如果页面ID匹配任何一个指定的页面,则返回true表示跳过该页面
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 = wpPassword) then Result := true;
if (PageID = wpSelectComponents) then Result := true;
if (PageID = wpSelectProgramGroup) then Result := true;
if (PageID = wpSelectTasks) then Result := true;
if (PageID = wpReady) then Result := true;
if (PageID = wpPreparing) then Result := true;
if (PageID = wpInfoAfter) then Result := true;
end;
利用页面切换的函数CurPageChanged来创建界面
// 当页面改变时调用此过程
procedure CurPageChanged(CurPageID: integer);
begin
// MsgBox('CurPageID:' + IntToStr(CurPageID), mbError, MB_OK);
// 如果当前页面是欢迎页面
if (CurPageID = wpWelcome) then
begin
// 创建密码输入框
_editPassword := TEdit.Create(WizardForm);
with _editPassword do
begin
Parent := WizardForm;
Font.Name := 'Microsoft YaHei';
Font.Size := 9;
BorderStyle := bsNone;
PasswordChar := '*';
SetBounds(211, 305, 178, 24); // 设置位置和大小
Color := clWhite;
TabStop := true;
end;
// 创建“确定密码”按钮
_btnConfirmPassword := BtnCreate(WizardForm.Handle, 400, 305, 100, 24, ExpandConstant('{tmp}\button_confirm.png'), 0, false);
MyBtnSetEvent(_btnConfirmPassword, @on_btnConfirmPassword_clicked);
// 创建安装按钮(初始隐藏)
_btnInstall := BtnCreate(WizardForm.Handle, 211, 350, 178, 43, ExpandConstant('{tmp}\button_install.png'), 0, false);
MyBtnSetEvent(_btnInstall, @on_btnInstall_clicked);
BtnSetVisibility(_btnInstall, false);
// 创建自定义设置按钮
_btnCustomizeSetup := BtnCreate(WizardForm.Handle, 511, 374, 78, 16, ExpandConstant('{tmp}\button_customize_setup.png'), 0, false);
MyBtnSetEvent(_btnCustomizeSetup, @on_btnCustomizeSetup_clicked);
// 创建取消自定义设置按钮(初始隐藏)
_btnUncustomizeSetup := BtnCreate(WizardForm.Handle, 511, 374, 78, 16, ExpandConstant('{tmp}\button_uncustomize_setup.png'), 0, false);
MyBtnSetEvent(_btnUncustomizeSetup, @on_btnCustomizeSetup_clicked);
BtnSetVisibility(_btnUncustomizeSetup, false);
// 创建目标路径输入框
_editTargetPath := TEdit.Create(WizardForm);
with _editTargetPath do
begin
Parent := WizardForm;
Text := WizardForm.DirEdit.Text;
Font.Name := 'Microsoft YaHei';
Font.Size := 9;
BorderStyle := bsNone;
SetBounds(91, 424, 402, 20);
OnChange := @on_editTargetPath_changed;
Color := clWhite;
TabStop := false;
end;
_editTargetPath.Hide();
// 创建产品已安装提示标签
_labelProductAlreadyInstalled := TLabel.Create(WizardForm);
with _labelProductAlreadyInstalled do
begin
Parent := WizardForm;
AutoSize := false;
Left := 85;
Top := 449;
Width := 200;
Height := 20;
Font.Name := 'Microsoft YaHei';
Font.Size := 9;
Font.Color := clGray;
Caption := '{#Tip_AppDirChangeEnable}';
Transparent := true;
OnMouseDown := @on_mouseDown;
end;
_labelProductAlreadyInstalled.Hide();
// 设置进度条回调
PBOldProc := SetWindowLong(WizardForm.ProgressGauge.Handle, -4, PBCallBack(@ProgressbarProcedure, 4));
// 创建浏览按钮
_btnBrowse := BtnCreate(WizardForm.Handle, 506, 420, 75, 24, ExpandConstant('{tmp}\button_browse.png'), 0, false);
MyBtnSetEvent(_btnBrowse, @on_btnBrowse_clicked);
BtnSetVisibility(_btnBrowse, false);
// 加载背景图像
_imageFormBackground := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\background_welcome.png'), 0, 0, WIZARDFORM_WIDTH_NORMAL, WIZARDFORM_HEIGHT_NORMAL, false, true);
_imageCustomizeBackground := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\background_welcome_more.png'), 0, 0, WIZARDFORM_WIDTH_NORMAL, WIZARDFORM_HEIGHT_MORE, false, true);
ImgSetVisibility(_imageCustomizeBackground, false);
WizardForm.Width := WIZARDFORM_WIDTH_NORMAL;
WizardForm.Height := WIZARDFORM_HEIGHT_NORMAL;
ImgApplyChanges(WizardForm.Handle);
end;
// 如果当前页面是安装页面
if (CurPageID = wpInstalling) then
begin
_editTargetPath.Hide();
BtnSetVisibility(_btnBrowse, false);
BtnSetVisibility(_btnCustomizeSetup, false);
BtnSetVisibility(_btnUncustomizeSetup, false);
WizardForm.Height := WIZARDFORM_HEIGHT_NORMAL;
// 创建安装进度标签
_labelInstallProgress := TLabel.Create(WizardForm);
with _labelInstallProgress do
begin
Parent := WizardForm;
AutoSize := false;
Left := 547;
Top := 349;
Width := 40;
Height := 30;
Font.Name := 'Microsoft YaHei';
Font.Size := 10;
Font.Color := clBlack;
Caption := '';
Transparent := true;
Alignment := taRightJustify;
OnMouseDown := @on_mouseDown;
end;
BtnSetEnabled(_btnExit, false);
_imageFormBackground := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\background_installing.png'), 0, 0, WIZARDFORM_WIDTH_NORMAL, WIZARDFORM_HEIGHT_NORMAL, false, true);
_progressbarBackground := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\progressbar_background.png'), 20, 374, 560, 6, false, true);
_progressbarForeground := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\progressbar_foreground.png'), 20, 374, 0, 0, true, true);
BtnSetVisibility(_btnInstall, false);
ImgApplyChanges(WizardForm.Handle);
end;
// 如果当前页面是完成页面
if (CurPageID = wpFinished) then
begin
ImgSetVisibility(_imageFormBackground, false);
ImgSetVisibility(_progressbarBackground, false);
ImgSetVisibility(_progressbarForeground, false);
_labelInstallProgress.Hide();
BtnSetEnabled(_btnExit, true);
// 创建启动复选框
_checkboxStartup := BtnCreate(WizardForm.Handle, 248, 280, 110, 17, ExpandConstant('{tmp}\checkbox_startup.png'), 0, True);
MyBtnSetEvent(_checkboxStartup, @on_checkboxStartup_clicked);
BtnSetChecked(_checkboxStartup, True);
// 创建完成按钮
_btnInstall := BtnCreate(WizardForm.Handle, 214, 315, 178, 43, ExpandConstant('{tmp}\button_finish.png'), 0, false);
// 加载完成页面背景图像
_imageFormBackground := ImgLoad(WizardForm.Handle, ExpandConstant('{tmp}\background_finish.png'), 0, 0, WIZARDFORM_WIDTH_NORMAL, WIZARDFORM_HEIGHT_NORMAL, false, true);
MyBtnSetEvent(_btnInstall, @on_btnInstall_clicked);
MyBtnSetEvent(_btnExit, @on_btnInstall_clicked);
ImgApplyChanges(_btnInstall);
ImgApplyChanges(WizardForm.Handle);
end;
end;