当前位置: 首页 > 工具软件 > Inno Setup > 使用案例 >

Inno Setup 打包脚本笔记

凤柏
2023-12-01

Inno Setup 使用版本为 6.1.2
系统为 win7 64位

1.1. 脚本段

1.1.1. #define宏定义常量

#define MyAppDirName "Demo"
#define MyAppVersion "1.0"      
#define MyAppVerData "20210204"
#define MyAppExeName "Demo.exe"   
#define MyAppName "Demo"
...

定义后在后面[Code]代码段需要使用时,用ExpandConstant('{#MyAppVersion}')将其转换为字符串。

除了自定义的常量,还有一些预定义的常量,如常用的{app},表示用户在安装时选择的安装目录,该常量不能再安装过程中使用,可用于卸载过程。
ExpandConstant('{app}')得到安装目录路径的字符串值。

1.1.2. [Setup]

AppName={#MyAppName} 
AppVersion={#MyAppVersion}
WizardStyle=modern
...

这个段包含用于安装程序和卸载程序的全局设置。

1.1.3. AppId

AppId={{1FE691F8-AD24-43CC-B5F7-78481C10D59A}}

这里右边为常量,根据帮助文档说明:

字符“{”视作为常量开始。如果你想将它作为实际字符使用,你必须使用两个连续的“{”字符。(对于“}”则不需要。)

因此AppId实际值为{1FE691F8-AD24-43CC-B5F7-78481C10D59A}}

点击 Tools 可选择Generate GUID生成GUID作为AppIdAppId 再在后面添加一个_is1,可以确定实际卸载注册表键名。

以本脚本为例,安装的软件在卸载注册表中位置为:

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows
\CurrentVersion\Uninstall\{1FE691F8-AD24-43CC-B5F7-78481C10D59A}}_is1]

卸载注册表中可看见软件名字,版本信息,安装文件夹路径,卸载程序位置(如"D:\unins,exe")等信息。
如果卸载注册表键名重复,Inno Setup 会删除之前的键然后新建,但两个重复的程序都会有问题。因此AppId要唯一,区别于其他程序。有些软件以软件名为键名,如360安全卫士

1.1.3.1. ShowLanguageDialog

当设置为 yes 并且有多个[Languages] 段条目时,将显示一个选择语言对话框,让用户有机会选择安装程序的语言。(默认)

当设置为 no 时,将从不显示对话框。

当设置为 auto 时,对话框只在安装程序不能找到匹配的语言标识时显示。

1.1.3.2. ArchitecturesAllowed

有效值: 一个或多个如下内容,以空格分隔:

x86 
x64 
ia64  

默认值: (blank)

确切说明哪种处理器架构允许安装程序在上面运行。如果这指令没被指定或者是空白的,安装将被允许在能执行它的32位代码的全部处理器架构上运行(including ones it doesn’t recognize)。

如果你安装任何32位设备驱动,你应该将此指令设定为 x86,由于32位设备驱动程序无法运行在64位 Windows。

如果你的应用程序的二进制构建成为 X64 或是 Itanium 架构,you should set this directive to either x64 或 ia64 respectively。

Inno Setup 是32位,如果没特别设置,即使系统是64位,打包的软件是32位。

1.1.3.3. LicenseFile

LicenseFile=license.txt

指定许可协议文件名 (可选),用 .txt 或 .rtf (富文本) 格式,在用户选择程序目标目录前显示。在运行安装程序编译器时,这个文件必须位于你的安装程序的来源目录,除非你指定了完整的路径,或用“compiler:”作为前缀,在这种情况下将在编译器目录下查找文件。

如果设置 LicenseFile 则显示。用户只能在选定“我同意该协议”的情况下才能继续到一页。

1.1.4. [Languages]

Name: "Chinese"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"

这里只用了简体中文一种语言,语言文件位于 Inno Setup 软件的安装文件Languages文件夹中,官方没有简体中文语言,需下载 ChineseSimplified.isl语言文件后放在该文件夹中。

语言文件中路径以compiler:为前缀,则会在编译器目录下查找该文件。

因该语言文件非官方,可能有翻译错误地方,如需修改可对照默认的语言文件(与编译器目录相同,名字为Default.isl)进行翻译。

1.1.5. [Files]

Source: "{#OutPut}\backup.bat"; DestDir: "{Demo}"; Flags: replacesameversion  
Source: "{#OutPut}\*.bat"; DestDir: "{app}"; Flags: replacesameversion 

这是定义安装程序安装文件到用户系统中的可选文件段。

Source:文件来源名字,这里指定文件完整路径。
DestDir:文件安装到用户系统中的目录。基本上都是用一个目录常量开头。如果指定的路径在用户系统中不存在,它会自动创建,并在卸载后如果是空的,卸载程序会自动删除。

1.1.6. [Tasks]

Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}";
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}";
;Name: "startupicon"; Description: "开机启动"; GroupDescription: "{cm:AdditionalIcons}";

这个段是只选的。它定义安装程序在执行安装期间所有由用户定制的任务。这些任务以选项框和单选项形式在附加任务向导页中出现。

{cm:CreateDesktopIcon}是自定义消息常量,常用的一些在.isl的语言文件中已经描述,如有 其它需要自定义的可在[CustomMessages]段定义。

[CustomMessages]
CreateDesktopIcon=创建桌面快捷方式(&D)

[Tasks]
Name: desktopicon; Description: "{cm:CreateDesktopIcon}"

GroupDescription为任务组的组描述,可以包含常量。用相同组描述的任务将被连续组合到文字标签下。文字标签显示组描述。

还可添加Flags,参数说明见帮助文档。

这里创建两个任务:创建桌面快捷方式和创建快速运行栏快捷方式,但光任务本身是不会做任何事情的: 它需要“链接”到其它安装条目。

[Icons]
Name: "{commondesktop}\{#MyDemoName}"; Filename: "{Demo}\{#MyDemoExeName}"; Tasks: desktopicon
Name: "{userDemodata}\Microsoft\Internet Explorer\Quick Launch\{#MyDemoName}"; Filename: "{Demo}\{#MyDemoExeName}"; Tasks: quicklaunchicon

1.1.7. [Icons]

[Icons]
Name: "{group}\{#MyDemoName}"; Filename: "{Demo}\{#MyDemoExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyDemoName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyDemoName}"; Filename: "{Demo}\{#MyDemoExeName}"; Tasks: desktopicon
Name: "{userDemodata}\Microsoft\Internet Explorer\Quick Launch\{#MyDemoName}"; Filename: "{Demo}\{#MyDemoExeName}"; Tasks: quicklaunchicon

这个可选段定义所有创建在开始菜单和/或其它位置 (比如桌面) 的快捷方式。

Name:要创建的快捷方式的名字和位置。
Filename:快捷方式的命令行文件名,通常用一个目录常量开头,可执行程序文件位置。
Tasks:与[Tasks]段中创建的任务关联,选择该任务,则处理该条目。

外壳文件夹常量:
{group}:开始菜单文件夹路径。这个文件夹总是创建在所有用户配置文件下,除非安装是在Non Administrative Install Mode,这种情况下它将创建在当前用户配置文件下。
如:C:\ProgramData\Microsoft\Windows\Start Menu\Programs

{commondesktop}:桌面文件夹路径,如C:\Users\Public\Desktop

{userDemodata}:Demolication Data文件夹路径,

1.1.8. [Registry]

Root: HKLM; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; valueName: "Demo"; ValueData: "{Demo}\{#MyDemoExeName}"; Flags: uninsdeletevalue 

这个可选段用来定义一些你想用安装程序在用户系统中创建、修改或删除的注册表键/值。
按默认,用安装程序创建的注册表键和值在卸载时不删除。如果你想让卸载程序删除键或值,你必须包含 uninsdelete* 标记中的一个。

Root:根键,为下列中一个:

HKCR  (HKEY_CLASSES_ROOT) 
HKCU  (HKEY_CURRENT_USER) //当前用户
HKLM  (HKEY_LOCAL_MACHINE) //当前机器,所有用户登录都可执行
HKU  (HKEY_USERS) 
HKCC  (HKEY_CURRENT_CONFIG) 

Subkey:子键名。

ValueType:值的数据类型,为下列一个:

none //默认设置,安装程序将创建一个没有键值的键,在这种情况下,ValueName 和 ValueData 参数将被忽略。
string //安装程序将创建一个字符串 (REG_SZ) 值
expandsz 
multisz
dword
qword
binary 

valueName:要创建的值名,可以包含常量。如果是空白的,将写入到“默认”值。如果 ValueType 参数设置为 none,这个参数被忽略。

ValueData:值的数据。如果 ValueType 参数是 string,expandsz 或 multisz,这是这一个可以包含常量的字符串。如果数据类型是 none,将被忽略。

Flags:这个参数是额外选项设置。多个选项可以使用空格隔开。支持参数见帮助文档。
uninsdeletevalue:当程序卸载时删除该值。

示例中要在注册表中创建开机自启项。注册表添加启动项一般在Run键(如果只执行一次用RunOnce),常用的两个位置在HKCUHKLM两个根键下。
这里创建的键的位置为HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run,在本机(win7 64位)或 win10 64 系统的注册表中查找时,发现实际的位置在HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run

因为系统是64位,而打包的软件为32位,因此创建的键位置重定向在Wow6432Node下。见MSDN官网说明。

给程序添加开机自启除了加到注册表中,还可添加到启动文件夹:

[Tasks]
Name: "startupicon"; Description: "开机启动"; GroupDescription: "{cm:AdditionalIcons}";

[Icons]
Name: "{commonstartup}\{#MyDemoName}"; Filename: "{Demo}\{#MyDemoExeName}"; Tasks: startupicon

{userstartup} & {commonstartup} * :开始菜单启动文件夹路径。
common 常量引用到所有用户配置文件。
user常量引用到当前登录的用户配置文件进行安装。

启动优先级: 注册表启动 > 启动文件夹

1.1.9. [Run]

该段是可选的, 可以放一些程序在程序成功安装后执行, 注意该执行过程是在应用程序弹出最后的安装完成的界面前

Filename: "{app}\MyProg.exe"; Parameters:"传递参数"; Description: "应用程序的描述"; Flags: runhidden runascurrentuser

上述例子中添加 runhidden 标志可以执行该程序而不显示窗口, 无需用户交互时使用
可以设置 postinstall 如果希望在界面显示一个是否执行该程序勾选框, 如果用户取消勾选则不会执行

1.1.10. [UninstallRun]

和 [Run] 一样是可选的, 语法也同 [Run] 相同, 用于执行 uninstallation 的第一步时执行, 即卸载时执行

1.1.11. [UninstallDelete]

Type: filesandordirs; Name: "{Demo}\UserData" //目录,删除所有文件和子目录
Type: files; Name: "{Demo}\temp.bat" //文件

这个可选段定义你想让卸载程序删除除用 [Files][Dirs]条目安装/创建外的其它文件或目录,或由你应用程序创建的一些公共使用的 .INI 文件。
卸载程序在卸载时最后一步处理这些条目。

Type

files: 
该 Name 参数指定一个详细的文件名,或带通配符的文件名。

filesandordirs :
除同时还匹配目录名外,功能与 files 相同,并删除任何名字匹配的目录以及包含它们中的所有文件和子目录。

dirifempty:
当使用这个参数时,Name 参数必须是目录名,但它不能包含通配符。该目录只在不包含任何文件或子目录的情况下才被删除。

1.1.12. [code]

可选的指定 Pascal 脚本的段。

1.2. 安装或卸载前检查程序是否正在运行

1.2.1. 查找程序进程名关闭进程

var
  BCanFindTask: Boolean; //全局变量 查找进程过程出错则为False

function FindTask(): Boolean;
var
  StrTempFilePath, StrCmdFindTask: String;
  StrTempFileContent: AnsiString;
  ResultCode: Integer;  
begin
  //getCurrentDir() 返回返回包含当前目录名的字串。这里返回的路径为 OutputDir 的路径
  StrTempFilePath := getCurrentDir() + '\findTaskTempFile.txt'; //创建临时文件
  Log('StrTempFileDir = ' +  StrTempFilePath); //调式时查看变量值
  StrCmdFindTask := Format('/c tasklist|find /c /i "%s" > "%s"', [ExpandConstant('{#MyDemoExeName}'), StrTempFilePath]);
  BCanFindTask := ShellExec('open', ExpandConstant('{cmd}'), StrCmdFindTask, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
  if BCanFindTask then begin
  	BCanFindTask := LoadStringFromFile(StrTempFilePath, StrTempFileContent); //将文件中内容输出到字符串StrTempFileContent
  	Log('StrTempFileContent = ' +  StrTempFileContent);	
  	if BCanFindTask then begin
  		StrTempFileContent := Trim(StrTempFileContent); //去除字符串中起始和结束部分的空格和控制符
  		Result := StrToInt(StrTempFileContent) > 0; //程序正在运行
  	end;
  end;
  DelTree(StrTempFilePath, False, true, False); //删除临时文件
  if not BCanFindTask then
    Result := False;		
end;

//调用该函数是,StrInfo 为检查到程序正在运行,询问是否先关闭程序提示 
//无程序正在运行或选择关闭进程则返回 True,继续原来操作,否则返回 False
function CloseRunningDemo(StrInfo: String): Boolean;
var
	BFindTask, BCloseRunningDemo: Boolean;
	StrCmdKillTask: String;
	ResultCode: Integer;
begin
	BCloseRunningDemo := True;   
  BFindTask := FindTask();
	if BCanFindTask and BFindTask then begin
		BCloseRunningDemo := Msgbox(StrInfo, mbConfirmation, MB_YESNO or MB_DEFBUTTON1) = IDYES;
		if BCloseRunningDemo then begin //查找到进程,并选择关闭进程
			StrCmdKillTask := '/c taskkill /f /t /im '  + ExpandConstant('{#MyDemoExeName}');
			if not ShellExec('open', ExpandConstant('{cmd}'), StrCmdKillTask, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
				MsgBox('自动退出进程失败,请手动关闭软件后点击 "确定" 继续下一步操作', mbInformation, MB_OK);
		end;
	end
	else if not BCanFindTask then begin
	  MsgBox('查找 Demo 是否正在运行失败,请确保软件没有运行再点击 "确定" 继续下一步操作', mbInformation, MB_OK);
	end;
  Result := BCloseRunningDemo;
end;

查找进程命令:

#define MyDemoExeName "Demo.exe"  //进程名
StrTempFilePath := getCurrentDir() + '\findTaskTempFile.txt'; //将查找进程结果存放到临时文件
StrCmdFindTask := Format('/c tasklist|find /c /i "%s" > "%s"', [ExpandConstant('{#MyDemoExeName}'), StrTempFilePath]);
ShellExec('open', ExpandConstant('{cmd}'), StrCmdFindTask, '', SW_HIDE, ewWaitUntilTerminated, ResultCode)

参数说明:
第一个/c参数:执行字符串指定的命令然后中断;
find /c: 仅显示字符串的行数,这里如果查找到进程,则结果为1,没有则为0。
find /i:查找时忽略大小写
左边字符串"%s":查找的名字字符串
右边字符串> "%s":查找结果输出文件路径
{cmd}:系统标准命令解释器的完整路径名。Windows\System32\cmd.exe
SW_HIDE:不显示命令行窗口
ewWaitUntilTerminated:开启进程后阻塞,直到进程终止以后才返回
ResultCode:如果指定的文件已执行则返回 True,否则返回 False。如果返回 True 并且是 WaitUntilTerminated,那么 ResultCode 返回执行的文件的退出代码。如果返回 False,那么 ResultCode 指定遇到的错误。使用 SysErrorMessage(ResultCode) 获取错误描述。

关闭进程:

StrCmdKillTask := '/c taskkill /f /t /im '  + ExpandConstant('{#MyDemoExeName}');
ShellExec('open', ExpandConstant('{cmd}'), StrCmdKillTask, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);

参数说明:
第一个/c参数:执行字符串指定的命令然后中断;
/f(force): 强制结束正在运行的进程。
/t (Tree kill): 终止指定的进程和任何由此启动的子进程。
/im(image Name): 进程名称 指定要终止的进程的映像名称。通配符 *可用来指定所有映像名。

1.2.2. 查找窗口名关闭进程

var
  WinHwnd: HWND;
	BCloseRunningDemo: Boolean;
begin
  WinHwnd := FindWindowByWindowName('Demo');//查找窗口名,返回窗口句柄
  if WinHwnd <> 0 then //找到符合的窗口名
  begin
    BCloseRunningDemo := Msgbox(info, mbConfirmation, MB_YESNO or MB_DEFBUTTON1) = IDYES; 
		if BCloseRunningDemo then begin   //点击确认再次获取窗口句柄,因为可能此时已关闭窗口或者窗口句柄改变
		  WinHwnd := FindWindowByWindowName('Demo');
			if WinHwnd <> 0 then
				if PostMessage(WinHwnd, 16, 0, 0) = False then   // 退出主进程
				  MsgBox('自动退出进程失败,请手动关闭软件后继续下一步操作', mbInformation, MB_OK);					
    end;
		Result := BCloseRunningDemo;			 
  end 
  else begin
    Result := true;
  end
end;

检查程序是否正在运行通过查找窗口名,这样需保证查找的程序所有界面窗口名相同。

关闭进程是通过找到的窗口句柄,然后PostMessage发送消息来退出程序,存在以下问题:
1、多个窗口,尽管窗口名固定,但句柄不一样,可能查找时和点击关闭时句柄变化,导致关闭进程失败。
该问题可以通过选择关闭进程时再次获取窗口句柄解决。
2、PostMessage 的第二个参数为发送的消息,16WM_CLOSE,发送该消息后程序处理相当于点击程序的退出按钮,如果程序在一个子界面,退出后只是回到主界面,并未完全退出程序。
如果发送消息为WM_QUIT(18),程序无论在哪个界面均能退出,但MSDN说明不建议用PostMessage来发送WM_QUIT消息,PostMessage将消息发送到消息队列后就立即返回,这样可能未释放程序占用的资源。

程序关闭的过程为先收到WM_CLOSE消息,然后用 DestroyWindow函数,该函数完成窗口的清理工作,释放资源并发送WM_DESTROY消息。发送WM_DESTROY消息后会调用PostQuitMessage函数,该函数发送WM_QUIT造成GetMessage返回0来结束消息循环,从而终止程序。

1.2.3. 封装dll检测和关闭进程

网上常用的两个psvince.dllISTask.dll,可直接下载别人封装好的dll或自己封装。
XhmikosR/psvince

1.2.4. Inno Setup 脚本创建互斥量

[Setup]
DemoMutex=MyProgramsMutexName
[Code]
//用 CreateMutex 函数先创建互斥量
//再通过 CheckForMutexes 函数检查是否有互斥量

该方法如再安装时检测,则创建CreateMutex函数不能放在InitializeSetup函数中,否则开始安装时,即使无正在运行的程序,也会判断为有互斥量。
参考 Inno Setup安装程序单例运行说明。

用该方法在安装和卸载时检测不如第一种方便自定义为想要的效果。

1.3. 安装前检测程序已安装过

//安装前检查 有无旧版本
procedure UninstallOldVersion();
var
	StrSubKeyName1: String; 
	StrSubKeyName2: String;
	StrUninstall: String;
	StrOldVersion: String;
	BUninstallOldVersion: Boolean;
	BSameVersion: Boolean;
	ResultCode: Integer;
begin
	StrSubKeyName1 := 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{1FE691F8-AD24-43CC-B5F7-78481C10D59A}}';
	StrSubKeyName2 := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1FE691F8-AD24-43CC-B5F7-78481C10D59A}}';
	//检查是否已安装过相同软件
	if RegQueryStringValue(HKLM, StrSubKeyName1, 'UninstallString', StrUninstall)
		 or
		 RegQueryStringValue(HKLM, StrSubKeyName2, 'UninstallString', StrUninstall) then
	begin  //已安装过,检查版本号是否相同	
		RegQueryStringValue(HKLM, StrSubKeyName1, 'DisplayName', StrOldVersion);
		RegQueryStringValue(HKLM, StrSubKeyName2, 'DisplayName', 
										StrOldVersion);											  
		BSameVersion := StrOldVersion = ExpandConstant('{#MyDemoName} {#MyDemoVersion}');
		if BSameVersion then begin
			BUninstallOldVersion := MsgBox('已经安装过该版本的软件,是否继续?' #13#13 
			'选择 "是" 卸载软件再安装,选择 "否" 退出安装,是否继续?',
			mbConfirmation,MB_YESNO or MB_DEFBUTTON2) = IDYES;
		end
		else begin
			BUninstallOldVersion := MsgBox('已经安装过该软件,必须先卸载 '#13#13'
				选择 "是" 卸载软件,选择 "否" 退出安装,是否继续?',
				mbConfirmation,MB_YESNO or MB_DEFBUTTON1) = IDYES;	
		end;
		if BUninstallOldVersion then //卸载旧版本
			Exec(RemoveQuotes(StrUninstall), '/silent', '', SW_HIDE, 
				ewWaitUntilTerminated, ResultCode)
		else //退出安装
			BContinueInstall := False  
	end;
end;

通过查找卸载注册表,之前设置AppId时创建的键,路径为HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{1FE691F8-AD24-43CC-B5F7-78481C10D59A}}_is1,查找UninstallString的值查看是否有相同名字程序未卸载,然后查看DisplayName的值得到未卸载程序的版本,与单签安装版本的版本比较,如果相同则提示。

如要继续安装软件,需先卸载已安装的软件,卸载是执行的安装文件夹中的卸载可执行文件,路径为UninstallString的值,因为该值包含引号,通过RemoveQuotes(StrUninstall)移除引号。/silent参数表示静默卸载,即卸载时不执行Inno Setup自带的“您确认完全删除Demo及他的所有组件吗?”消息框,直接开始卸载。

1.4. 卸载前确认是否备份数据

1.4.1. 卸载前检查

//卸载时先执行该函数,如返回 `True` 则继续卸载,返回`False`则终端卸载,可用该函数处理卸载前需检查的事
//这里卸载前先检查程序是否运行,如运行则需关闭再卸载,否则不能卸载干净,因此如选择不关闭程序则中断卸载。
function InitializeUninstall(): Boolean;
begin
	BContinueInstall := CloseRunningDemo('卸载程序检测到客户端正在运行' #13#13 '单击 “是” 关闭进程,继续卸载,或按 “否” 退出'); 
	Result := BContinueInstall;
end;

1.4.2. 确认卸载后备份数据再卸载

确定开始卸载后,开始卸载过程,执行下面CurUninstallStepChanged过程,确认卸载后不可中断卸载。

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  case CurUninstallStep of
	  usUninstall: //卸载前执行
		begin 																								
	    BNeedBackup := MsgBox('数据备份:' #13#13 '即将卸载软件,是否 "备份文件" 再卸载?' #13#13 '单击 "是" 备份数据, 或按 "否" 直接卸载', mbConfirmation, MB_YESNO or MB_DEFBUTTON1) = IDYES;
			if not BNeedBackup then
				NoBackupVerification();  //选择 否 不备份,则二次确认
			if BNeedBackup then
					UninstallBackup();
    end;		
	end;
end;

CurUninstallStep的种类有:

usDemoMutexCheck, usUninstall, usPostUninstall, usDone 

各参数说明见Innosetup的状态页面和向导页面解释
#13#13:用来换行。

1.4.3. 卸载时不备份数据进行身份验证

如选择不备份,则说明风险并需输入密码验证。

var
	Form: TSetupForm;
	PasswordEdit: TPasswordEdit;		
// 输入密码 点击确认,密码正确则关闭窗口不备份数据,直接卸载
procedure CheckPasswordOKClick(Sender: TObject);
begin
	if PasswordEdit.Text = 'Demo' then begin
		BNeedBackup := False;
	  Form.Close;
	end
	else begin
	  MsgBox('密码错误!', mbInformation, mb_Ok);
	end;	
end; 
// 输入密码 点击 取消 关闭窗口,点击取消或者关闭窗口则备份数据
procedure CheckPasswordCancelClick(Sender: TObject);
begin
	Form.Close;
end;

//身份验证窗口
procedure NoBackupVerification();
var		
	DescriptionText: TNewStaticText;
	OKButton, CancelButton: TButton;
	W: Integer;	
begin
	BNeedBackup := True; //关闭 窗口 相当于 取消 则备份
	Form := CreateCustomForm();	
	try
		Form.ClientWidth := ScaleX(300);
		Form.ClientHeight := ScaleY(200);
    	Form.Caption := '身份验证';
		
		DescriptionText := TNewStaticText.Create(Form);
	    DescriptionText.Parent := Form;
	    DescriptionText.Top := ScaleY(10);
	    DescriptionText.Left := ScaleY(10);
	    DescriptionText.Width := Form.ClientWidth - ScaleX(2);
	    DescriptionText.AutoSize := True;
	    DescriptionText.ShowAccelChar := False;
		DescriptionText.WordWrap := False;
	    DescriptionText.Caption := '风险说明' #13#13 '请输入 "密码" 以验证身份' #13#13 '
	    							点击 "取消" 则备份数据再卸载';
		
		PasswordEdit := TPasswordEdit.Create(Form);
    	PasswordEdit.Parent := Form;
		PasswordEdit.Top := DescriptionText.Top + DescriptionText.Height + ScaleY(23);
		PasswordEdit.Left := ScaleX(23);
    	PasswordEdit.Width := ScaleX(200);
    	PasswordEdit.Height := ScaleY(23);    
		PasswordEdit.Anchors := [akLeft, akTop, akRight];
		
		CancelButton := TButton.Create(Form);
		CancelButton.Parent := Form;
		CancelButton.Top := Form.ClientHeight - ScaleY(23 + 10);
		CancelButton.Left := Form.ClientWidth - ScaleX(75 + 50);
		CancelButton.Height := ScaleY(23);
		CancelButton.Anchors := [akRight, akBottom];		
		CancelButton.Caption := '取消';
		CancelButton.OnClick := @CheckPasswordCancelClick; //点击取消按钮时执行 
		CancelButton.Default := True;
		CancelButton.Cancel := True;
		
		OKButton := TButton.Create(Form);
		OKButton.Parent := Form;
		OKButton.Top := CancelButton.Top;
		OKButton.Height := ScaleY(23);
		OKButton.Left := Form.ClientWidth - ScaleX(75 + 6 + 75 + 50);
		OKButton.Anchors := [akRight, akBottom];
		OKButton.Caption := '确定';
		OKButton.OnClick := @CheckPasswordOKClick; //点击确定按钮时执行 		

		W := Form.CalculateButtonWidth([OKButton.Caption, CancelButton.Caption]);
    	OKButton.Width := W;
    	CancelButton.Width := W;
		
		Form.ActiveControl := PasswordEdit;
    	Form.KeepSizeY := True;
		Form.ShowModal();  //让窗口一直显示
	finally	
		Form.Free();		
	end;		
end;

创建身份验证窗口设置参考官方示例CodeClasses.iss

1.4.4. 备份数据

复制文件用 FileCopy函数,复制文件夹则需用windows命令:

//函数复制文件夹,参数为:旧文件夹路径,新文件夹路径,执行复制文件夹命令的.bat文件
function MoveFolder(StrOldFileDir, StrNewFileDir, BackupBatDir: String): Boolean;
var
  StrCmd: String;
	ResultCode: Integer;
begin
	if FileOrDirExists(StrOldFileDir) then
	begin
	  StrCmd := 'xcopy /e/i/q '+ StrOldFileDir + ' ' + StrNewFileDir + #13#10;
		SaveStringToFile(BackupBatDir, StrCmd, False);//命令写入.bat文件中
		Exec(BackupBatDir, '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode); //执行.bat文件
		Result := FileOrDirExists(StrNewFileDir);
	end
	else begin
		Result := true;
	end
end;

1.4.5. 压缩文件夹

//压缩备份文件夹	
StrCmd := 'call ' + DemoDir + '\zipjs.bat zipDirItems -source '+ BackupDir + ' -destination ' + BackupDir + '.zip' + ' -keep yes -force no';
SaveStringToFile(BackupBatPath, StrCmd, False);
Exec(BackupBatPath, '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);

将文件夹压缩为.zip格式且不使用外部压缩工具,用到脚本文件为 zipjs.bat
测试用该脚本压缩成功,即使系统未安装任何压缩工具。
压缩文件夹使用的方法:Using Shell.Application
脚本调用语法:在命令行窗口定位到脚本所在的目录后,输入zipjs.bat,会有帮助文档说明。

1.5. 添加 readme 文件

想要程序在安装完成后打开一个 readme 文件,可在 [Files] 段添加,加上 isreadme 标志即可。

;readme.txt
Source: "{#OutPut}\readme.txt"; DestDir: "{app}"; Flags: isreadme replacesameversion

效果:在程序安装完成后,会有个勾选框选择是否查看 readme。
见帮助文档说明:

File is the “README” file. Only one file in an installation can have this flag.
When a file has this flag, the user will asked if he/she would like to view the README file after the installation has completed.
If Yes is chosen, Setup will open the file, using the default program for the file type.
For this reason, the README file should always end with an extension like .txt, .wri, or .doc.
Note that if Setup has to restart the user’s computer (as a result of installing a file with the flag restartreplace
or if the AlwaysRestart [Setup] section directive is yes), the user will not be given an option to view the README file.

1.6. 参考

1、Basic Pascal Tutorial
2、中文翻译语言文件
3、WOW6432Node
4、inno setup卸载时弹出意见反馈窗口和使用WinHttpRequest上传
5、注册表——Run、RunOnce 键值解析
6、常用批处理命令总结3之Find和FindStr
7、Windows 进程 Tasklist查看 与 Taskkill结束
8、Delphi 模式窗体返回值ModalResult的使用方法及注意事项
9、演示控件的 Anchors 属性
10、Delphi 常用属性说明(超长)
11、ShowModal() = mrOk
12、互联网软件的安装包界面设计-Inno setup
13、Inno Setup Translations
14、Innosetup的状态页面和向导页面解释
15、ShellExecuteA function (shellapi.h)
16、Inno Setup Help
17、How can I compress (/ zip ) and uncompress (/ unzip ) files and folders with batch file without using any external tools?

1.7 软件安装包

安装包百度网盘:Inno Setup 6.1.2 提取码:14k4

 类似资料: