如何制作更进阶一点的软件包?比如根据安装包选择的语言设置软件启动时的语言,比如对注册表进行操作,再比如检测电脑是否安装相关的.NET环境等等。
下面来一一介绍,根据前面制作的简单脚本安装包来升级,请参考我的上一篇Inno Setup 软件安装包制作
一 添加快捷方式的图标
1 准备图标
这是在阿里巴巴图库上找的图片, 在[Files] 段,将图片添加进来
[Files]
Source: "E:\安装包测试\logo.ico"; DestDir: "{app}"; Flags: ignoreversion
2 创建图标快捷方式
在[Icons]段,设置图标,比如下面设置了桌面快捷方式的图标是logo.ico,卸载程序的图标是delete.ico, 如果你还有其它exe程序需要设置图标可以参考下面的脚本
[Icons]
Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\logo.ico"; Tasks: desktopicon
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"; IconFilename: "{app}\delete.ico"
二 根据安装时选择的语言设置软件的初始语言
思路是对软件中的某个配置语言文件写文字。
1 初始脚本语言
在 [Languages]段里,设置了中文和英文两种,注释掉的是原始的脚本,因为Name名称有点长,在这里我们改一下,将english更改为en, chinesesimplified更改为ch,便于后面的使用。
[Languages]
;Name: "english"; MessagesFile: "compiler:Default.isl"
;Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "ch"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
还有一个将要更改的文件加入到[Files]段中
[Files]
Source: "E:\安装包测试\ZedgraphMulY\Config.ini"; DestDir: "{app}"; Flags: ignoreversion
2 写脚本,将选择的语言写入文件中
在[Code]段写一段脚本,使用系统提供的函数来处理,在软件安装完成之后将修改Config.ini的值。
procedure CurStepChanged(CurStep: TSetupStep);
你可以用这个事件函数执行你自己的预安装和安装后任务。
TSetupStep 值,可以取下面三个
ssInstall, ssPostInstall, ssDone
含义分别是:
在实际安装开始之前用 CurStep=ssInstall 调用,
或在实际安装完成之后用 CurStep=ssPostInstall 调用,
或在安装程序终止之前和安装完成之后用 CurStep=ssDone 调用。
;执行脚本
[Code]
//修改软件语言信息
procedure CurStepChanged(CurStep: TSetupStep);
var
languageName: string;
begin
if CurStep=ssDone then //软件安装后执行
begin
languageName := ActiveLanguage(); // 获取用户选择的语言
if 'ch' = languageName then
begin
SetIniString('Lang','CurLang','Chinese',ExpandConstant('{app}/Config.ini'));
end
else if 'en' = languageName then
begin
SetIniString('Lang','CurLang','English',ExpandConstant('{app}/Config.ini'));
end;
end;
end;
三 对注册表进行操作
1 注册表[Registry] 区段
Root
[Registry] 区段
这个可选区段用来定义一些你想用安装程序在用户系统中创建、修改或删除的注册表键/值。
按默认值,用安装程序创建的注册表键和值在卸载时不删除。如果你想让卸载程序删除键或值,你必须包含下面描述的 uninsdelete* 标志之一。
Root (必需的)
根键。必须是下列值中的一个:
HKCU (HKEY_CURRENT_USER)
HKLM (HKEY_LOCAL_MACHINE)
HKCR (HKEY_CLASSES_ROOT)
HKU (HKEY_USERS)
HKCC (HKEY_CURRENT_CONFIG)
Subkey
Subkey (必需的)
子键名称,可以包含常量。
示例:
Subkey: "Software\My Company\My Program"
Subkey: "Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags"
ValueType
值的数据类型。必须是下面中的一个:
none
string
expandsz
multisz
dword
qword
binary
如果指定了 none(默认设置),安装程序将创建一个没有键值的键,在这种情况下,ValueName 和 ValueData 参数将被忽略。
如果指定了 string,安装程序将创建一个字串(REG_SZ)值。
如果指定了 expandsz,安装程序将创建一个扩展字串(REG_EXPAND_SZ)值。
如果指定了 multisz,安装程序将创建一个多行文本(REG_MULTI_SZ)值。
如果指定了 dword,安装程序将创建一个32-位整数(REG_DWORD)值。
如果指定了 qdword,安装程序将创建一个64-位整数(REG_QDWORD)值。
如果指定了 binary,安装程序将创建一个二进制(REG_BINARY)值。
示例:
ValueType: string
ValueData
值的数据。
如果 ValueType 参数是 string,expandsz 或 multisz,这是这一个可以包含常量的字串。
如果数据类型是 dword或qdword,这可以是一个十进制整数(例如“123”),一个十六进制整数(例如“$7B”)或解析为整数的常量。
如果数据类型是 binary,这可以是下列形式的十六进制字节序列: “00 ff 12 34”。如果数据类型是 none,将被忽略。
示例:
ValueData: "1.0"
Flags
仅介绍了两个常用的flags
uninsdeletekey
当卸载程序时,删除整个键,包含其中的所有值和子键。这对于 Windows 自身使用的键明显不是一个好方法。你只能用于你的应用程序特有的键中。
为防止意外,安装期间如果 Subkey 是空白或只包含反斜杠符号,该标志被忽略。
uninsdeletekeyifempty
当程序卸载时,如果这个键的内部没有值或子键,则删除这个键。该标志可以与 uninsdeletevalue 组合使用
为防止意外,安装期间如果 Subkey 是空白或只包含反斜杠符号,该标志被忽略。
2 注册表的使用
[Registry]
Root: HKLM; Subkey: Software\ZedgraphMulY; ValueType: string; ValueName: Installed version; ValueData: '1.0'; Flags: uninsdeletekey
Root: HKCR; Subkey: "ZedgraphMulY工程文件"; ValueType: string; ValueData: "ZedgraphMulY工程文件"; Flags: uninsdeletekey
Root: HKCR; Subkey: "ZedgraphMulY\DefaultIcon"; ValueType: string; ValueData: "{app}\logo.ico"; Flags: uninsdeletekey
Root: HKCR; Subkey: "ZedgraphMulY工程文件\shell\open\command"; ValueType: string; ValueData: """{app}\ZedgraphMulY.exe"" ""%1"""; Flags: uninsdeletekey
Root: HKCR; Subkey: ".zt"; ValueType: string; ValueData: "ZedgraphMulY工程文件"; Flags: uninsdeletekey
;解决解决提示你要允许来自未知发布者的此应用对你的设备进行更改吗的问题
Root: HKCU; Subkey: "Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"; ValueType: string; ValueName: "{app}\ZedgraphMulY.exe" ; ValueData: RunAsInvoker; Flags: uninsdeletekey
键盘按WIN+R键,调出运行界面,输入regedit,点击回车调出注册表信息。这是一个树形节点结构的。
四 检测电脑的.NET环境
使用VS开发.net框架的桌面应用程序,如果要在其它电脑上正常运行起来需要相应的.net框架支持。我们想在客户安装软件的时候就可以将环境一起安装好,而不是用户自己手动去下载安装。
这里给的例子是离线安装(会导致我们的安装包会比较大),因为连网安装一个是速度比较慢,还有一个是客户可能没有网。
先说一下思路,将.net离线安装包放到制作安装包的文件里面,检测到电脑没有这个.net 框架时就运行.net安装包,等待程序全部安装完成之后会将.net安装包删除掉。
1 先准备.net环境安装包
根据自己软件需要的环境,下载.net离线安装包,可参考我的这篇找.NET Framework 离线安装包下载地址
将.NET安装包放在“E:\安装包测试\ZedgraphMulY\tmp\“目录下
使用脚本将.NET安装包添加的我们制作的安装包中,在[Files]段添加如下脚本
[Files]
;.net环境安装包
Source: "E:\安装包测试\ZedgraphMulY\tmp\*"; DestDir: "{app}\tmp"; Flags: ignoreversion recursesubdirs createallsubdirs
2 检测.NET环境
在这里我们通过访问电脑的注册表信息 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4.0来判断是否安装了.net
在Code段中,定义了Framework40IsNotInstalled()函数来检测是否有安装.NET 4.0,如果没有,则安装InstallFramework
;执行脚本
[Code]
//判断当前是否有安装.net4.0 运行环境
function Framework40IsNotInstalled() : Boolean;
var
bSuccess: Boolean;
regVersion: Cardinal;
tmppath: string;
begin
Result := True;
tmppath := ExpandConstant('{app}') + '\tmp';
//检查版本
bSuccess := RegKeyExists(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4');
if(True = bSuccess) then begin
Result := False;
//不需要安装,则删除安装包tmp
// 删除目录 C:\Test 和它内部的一切
//DelTree('C:\Test', True, True, True);
if FileOrDirExists(tmppath) then
begin
DelTree(tmppath, true, true, true);
end;
end;
end;
procedure InstallFramework;
var
StatusText: string;
ResultCode: Integer;
tmppath:string ;
setupOk: Boolean;
begin
//先抽取到临时目录 ,将相对目录 展开到常量(绝对)目录 ExpandConstant('{app}\tmp\ndp40.exe')
tmppath := ExpandConstant('{app}') + '\tmp\dotNetFx40_Full_x86.exe';
StatusText := WizardForm.StatusLabel.Caption;
WizardForm.StatusLabel.Caption := ExpandConstant('{cm:CmCaption}');
WizardForm.ProgressGauge.Style := npbstMarquee;
try
// if not Exec(tmppath, '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
if FileOrDirExists(tmppath) then
begin
setupOk := Exec(tmppath, '/q', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
if( setupOk = False) then
begin
MsgBox(tmppath + IntToStr(ResultCode) + '.', mbError, MB_OK);
end;
end;
finally
WizardForm.StatusLabel.Caption := StatusText;
WizardForm.ProgressGauge.Style := npbstNormal;
// 删除目录 C:\Test 和它内部的一切
//DelTree('C:\Test', True, True, True);
tmppath := ExpandConstant('{app}') + '\tmp';
DelTree(tmppath, true, true, true);
end;
end;
在[Code]字段前面的判断语言处,添加该脚本
//检测.net环境,如果没有则安装
if CurStep=ssPostInstall then
begin
if Framework40IsNotInstalled() then
begin
InstallFramework();
end;
end;
五 整个脚本代码
最后附上整个安装包文件的结构和整个脚本的代码
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "ZedgraphMulY"
#define MyAppVersion "1.0"
#define MyAppPublisher "唠嗑一夏"
#define MyAppURL "http://www.example.com/"
#define MyAppExeName "ZedgraphMulY.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{22AED403-1AC3-4712-BD48-CDE942CEB8AD}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DisableProgramGroupPage=yes
OutputDir=E:\安装包测试
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
[Languages]
;Name: "english"; MessagesFile: "compiler:Default.isl"
;Name: "chinesesimplified"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "ch"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "E:\安装包测试\ZedgraphMulY\ZedgraphMulY.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\安装包测试\ZedgraphMulY\ZedGraph.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\安装包测试\ZedgraphMulY\ZedGraph.xml"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\安装包测试\ZedgraphMulY\ZedgraphMulY.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\安装包测试\ZedgraphMulY\es\*"; DestDir: "{app}\es"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "E:\安装包测试\ZedgraphMulY\zh-cn\*"; DestDir: "{app}\zh-cn"; Flags: ignoreversion recursesubdirs createallsubdirs
;.net环境安装包
Source: "E:\安装包测试\ZedgraphMulY\tmp\*"; DestDir: "{app}\tmp"; Flags: ignoreversion recursesubdirs createallsubdirs
;语言配置文件
Source: "E:\安装包测试\ZedgraphMulY\Config.ini"; DestDir: "{app}"; Flags: ignoreversion
;图片
Source: "E:\安装包测试\logo.ico"; DestDir: "{app}"; Flags: ignoreversion
Source: "E:\安装包测试\delete.ico"; DestDir: "{app}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\logo.ico"; Tasks: desktopicon
[Run]
;安装完成是否需要直接运行,如果不需要该功能可以删除Run段
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Registry]
Root: HKLM; Subkey: Software\ZedgraphMulY; ValueType: string; ValueName: Installed version; ValueData: '1.0'; Flags: uninsdeletekey
Root: HKCR; Subkey: "ZedgraphMulY工程文件"; ValueType: string; ValueData: "ZedgraphMulY工程文件"; Flags: uninsdeletekey
Root: HKCR; Subkey: "ZedgraphMulY\DefaultIcon"; ValueType: string; ValueData: "{app}\logo.ico"; Flags: uninsdeletekey
Root: HKCR; Subkey: "ZedgraphMulY工程文件\shell\open\command"; ValueType: string; ValueData: """{app}\ZedgraphMulY.exe"" ""%1"""; Flags: uninsdeletekey
Root: HKCR; Subkey: ".zt"; ValueType: string; ValueData: "ZedgraphMulY工程文件"; Flags: uninsdeletekey
;解决解决提示你要允许来自未知发布者的此应用对你的设备进行更改吗的问题
Root: HKCU; Subkey: "Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"; ValueType: string; ValueName: "{app}\ZedgraphMulY.exe" ; ValueData: RunAsInvoker; Flags: uninsdeletekey
; //用于定义{cm:...}常量的自定义消息值
[CustomMessages]
en.CmCaption = Installing.NET Framework 4.0 May take a few minutes...
en.CmNetErr = .NET installation failed, please contact administrator, code:
ch.CmCaption = 正在安装 .NET Framework 4.0 可能需要几分钟的时间...
ch.CmNetErr = .NET 安装失败,请联系管理员,代码:
;执行脚本
[Code]
//卸载程序清除注册表信息
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usUninstall then
begin
RegDeleteKeyIncludingSubkeys(HKEY_LOCAL_MACHINE, 'Software\ZedgraphMulY');
RegDeleteKeyIncludingSubkeys(HKEY_CLASSES_ROOT, 'ZedgraphMulY');
DelTree(ExpandConstant('{app}'), True, True, True);
end;
end;
//判断当前是否有安装.net4.0 运行环境
function Framework40IsNotInstalled() : Boolean;
var
bSuccess: Boolean;
regVersion: Cardinal;
tmppath: string;
begin
Result := True;
tmppath := ExpandConstant('{app}') + '\tmp';
//检查版本
bSuccess := RegKeyExists(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4');
if(True = bSuccess) then begin
Result := False;
//不需要安装,则删除安装包tmp
// 删除目录 C:\Test 和它内部的一切
//DelTree('C:\Test', True, True, True);
if FileOrDirExists(tmppath) then
begin
DelTree(tmppath, true, true, true);
end;
end;
end;
procedure InstallFramework;
var
StatusText: string;
ResultCode: Integer;
tmppath:string ;
setupOk: Boolean;
begin
//先抽取到临时目录 ,将相对目录 展开到常量(绝对)目录 ExpandConstant('{app}\tmp\ndp40.exe')
tmppath := ExpandConstant('{app}') + '\tmp\dotNetFx40_Full_x86.exe';
StatusText := WizardForm.StatusLabel.Caption;
WizardForm.StatusLabel.Caption := ExpandConstant('{cm:CmCaption}');
WizardForm.ProgressGauge.Style := npbstMarquee;
try
// if not Exec(tmppath, '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
if FileOrDirExists(tmppath) then
begin
setupOk := Exec(tmppath, '/q', '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
if( setupOk = False) then
begin
MsgBox(tmppath + IntToStr(ResultCode) + '.', mbError, MB_OK);
end;
end;
finally
WizardForm.StatusLabel.Caption := StatusText;
WizardForm.ProgressGauge.Style := npbstNormal;
// 删除目录 C:\Test 和它内部的一切
//DelTree('C:\Test', True, True, True);
tmppath := ExpandConstant('{app}') + '\tmp';
DelTree(tmppath, true, true, true);
end;
end;
//修改软件语言信息
procedure CurStepChanged(CurStep: TSetupStep);
var
languageName: string;
begin
if CurStep=ssDone then //软件安装后执行
begin
languageName := ActiveLanguage(); // 获取用户选择的语言
if 'ch' = languageName then
begin
SetIniString('Lang','CurLang','Chinese',ExpandConstant('{app}/Config.ini'));
end
else if 'en' = languageName then
begin
SetIniString('Lang','CurLang','English',ExpandConstant('{app}/Config.ini'));
end;
end;
//检测.net环境,如果没有则安装
if CurStep=ssPostInstall then
begin
if Framework40IsNotInstalled() then
begin
InstallFramework();
end;
end;
end;
六 效果图
1桌面快捷方式的图标
2 设置软件语言
3 检测.net环境
4 注册表信息
控制面板
安装过程的效果图可参考 第一篇的软件安装包的制作