Inno Setup
常见问题解答(中文翻译:王苏)

Inno Setup 常见问题解答包含了在帮助文档中没有的补充信息。

此页面的内容也可以在 GitHub 上找到,您可以使用编辑按钮建议新的条目或其他改进。

功能性

问题

安装任务

兼容性

其他


功能性

翻译 Inno Setup 的文本

将 Inno Setup 的文本翻译为其他语言不需要修改源代码。只需复制 Default.isl 文件(包括在 Inno Setup 中),并开始编辑其中的文本。(不要直接编辑 Default.isl 文件,否则当您安装新的 Inno Setup 版本时,您的更改将丢失。有关某些重要提示,请参阅帮助文档中的 "[Messages] 区段" 主题。

一旦你完成了创建新的 .isl 文件,创建一个 [Languages] 区段,告诉编译器使用它:

[Languages]
Name: mytrans; MessagesFile: "compiler:MyTranslation.isl"

Inno Setup Translations 网页上有许多贡献的翻译可供下载。

请注意,消息框中的按钮标题无法翻译。这些字幕始终与 Windows 本身的语言相同。因此,如果用户正在运行 Windows 的英文版,他们将看到英文按钮字幕。对于使用 Windows MessageBox() 函数显示消息框的任何应用程序,这是正常行为。

它是否支持 MBCS (多字节字符集)?

支持。它在所有文件名和常量解析中都进行了前导字节检查,因此不会将尾字节误认为反斜杠 ("\") 或大括号 ("{")。

它将来会支持 Windows Installer 吗?

目前,没有计划推出 Inno Setup 的 Windows Installer 版本。"支持" Windows Installer 可能会涉及程序的近乎完全重写。

如何更改 Setup.exe 的图标?

安装程序的图标可以通过设置 [Setup] 区段的 SetupIconFile 指令来更改。要设置卸载程序的图标,可设置 UninstallDisplayIcon

Inno Setup 能否进行有条件的安装 - 例如,只有当某个注册表项或文件存在时才进行安装?

可以,可通过 Pascal 脚本功能

是否有下载功能?

有,可以通过 Pascal 脚本功能。请参阅 CodeDownloadFiles.iss 示例脚本示例。

是否可以在不使用 /SILENT 或 /VERYSILENT 命令行参数的情况下进行静默安装?

不可以,也没有计划此类功能(它可能被滥用)。如果您打算将用户交互保持在最低限度,请使用禁用* [Setup] 区段指令。

安装程序是否可以将注册表条目的值用作默认目录名称?

可以。在 DefaultDirName 中使用 {reg:...} 常量。例如:

[Setup]
DefaultDirName={reg:HKA\Software\My Program,Path|{autopf}\My Program}
 

有关 {reg:...} 常量和 {autopf} 常量的更多信息,请参阅帮助文档中的常量主题

有关 HKA 键值的详细信息,请参阅帮助文档中的非管理安装模式主题

是否可以删除每个用户 HKEY_CURRENT_USER 注册表配置单元内的项?

不可以。没有简单的方法可以访问属于其他用户的注册表项。

为了访问给定的用户注册表配置单元,必须首先加载用户的配置文件,为此,必须进行身份验证。卸载者不会知道用户的密码。

"但它不能调用 RegLoadKey 手动安装用户的注册表配置单元 (NTUSER.DAT) 吗?" 在不冒充用户的情况下,运行卸载程序的用户需要在用户的配置文件目录上写入权限。在 Windows XP 上,用户配置文件可以标记为"私有",除了用户本人,任何人都无法访问其中的文件。

在 Roaming 配置文件设置中,如果不首先进行身份验证,甚至不可能知道给定用户的配置文件所在的路径。

要处理这种情况,像其他安装程序那样:只需保留其他用户的 HKCU 项即可。

应用程序必须部署哪些系统文件?

这主要取决于您的应用程序是使用哪个开发工具创建的。检查其文档。

如果您确定您的应用程序依赖于特定的 Microsoft DLL,而该 DLL 不是随 Windows 预装的,那么首先不要从自己的 Windows 目录中部署 DLL。您自己的 Windows 目录中的文件通常针对特定版本的 Windows 量身定做,并且不会在其他版本的 Windows 上工作 -- 或者更糟(参见下文)。当您运行最新版本的 Windows 时,情况尤其如此。

相反,在微软网站上搜索被视为"可重新分配"的 DLL 版本。(http://www.microsoft.com/downloads/ 是一个很好的开始。) 此类版本通常可以安全地安装在任何 Windows 版本上(但请查看 README 文件以确定)。

如果出现任何情况,则可能不允许单独部署有问题的 DLL。

如何创建对现有安装的"更新"或"附加"的安装?

在将"更新"(或"附加")的安装部署到现有安装时,您可能希望满足以下标准:

  1. 更新必须安装到与原始应用程序相同的目录。
  2. 卸载原始应用程序时,必须删除更新安装的任何新文件。
  3. 更新不应在添加/删除程序 列表中创建新条目,也不应更改原始应用程序的条目。卸载程序显示的应用程序名称也不应更改。

1 和 2 可以通过为更新安装提供与原始应用程序相同的 AppId 设置来实现。(如果您从未在原始应用程序中设置 AppID,则将 AppID 设置为原始应用程序中使用的 AppName 的值。) 如此,当与 UsePreviousAppDir=yes(默认设置)组合时,将导致更新安装默认为相同目录作为原始应用程序,并共享相同的卸载日志文件 (unins???.dat)。有关详细信息,请参阅帮助文档中的相同的应用程序主题

3 可以通过设置 CreateUninstallRegKey=noUpdateUninstallLogAppName=no 来实现


问题

编译器显示 "参数上的引号不匹配或错位"

如果尝试在参数数据中嵌入引号 (") 字符,则通常会显示此消息,但不会根据需要将其加倍。请阅读文档中的 "区段中的参数" 主题以获取更多信息。

当我的应用程序从安装程序创建的快捷方式启动时,找不到任何文件。但我在资源管理器中双击应用程序的 EXE 时,它的工作正常。

您的应用程序很可能没有在它试图打开的文件上指定路径名,因此它期望在当前目录中找到它们。默认情况下,Inno Setup 不会在其创建的快捷方式上设置"开始"字段:这会导致 Windows 自行选择目录,这通常不会包含您的应用程序的目录。

在几乎所有情况下,这都是应该在应用级别上纠正的。正确设计的 GUI 应用程序不应期望从特定目录开始;他们应该总是在打开的文件上指定完整的路径名。例如,在 Delphi 或 C++Builder 中,可以通过调用: ExtractFilePath(ParamStr(0)) 来获取包含应用程序 EXE 目录的完整路径名。要获取应用程序目录中名为“file.txt”文件的完整路径,可使用: ExtractFilePath(ParamStr(0)) + 'File.txt'

如果由于某种原因无法在应用程序层面解决此问题,可以告诉 Inno Setup 通过在 [Icons] 条目中添加 "WorkingDir: {app}" 来设置“Start In”字段。

为什么某些系统上会显示错误消息 "安装文件已损坏"?

当与安装有关的文件 (如 setup.exe, setup.1) 大小错误,或者文件的一部分未通过 CRC 检查时,将显示此错误消息。它不会因为任何其他原因而显示。

如果您的安装通过互联网分发,并且您收到大量有关此错误的报告,则可能是您的 Web 服务器通过过早断载连接来提供部分文件。让受影响的用户检查他们下载的文件的字节中的大小。

如果您的安装是通过 CD-ROM 或软盘分发的,则可能是 CD-ROM 或软盘不好,或者驱动器可能有缺陷。

当我安装新版本的应用程序而不首先卸载旧版本时,我在控制面板的添加/删除程序 中会有第二个条目。

当您在版本之间更改 AppId,或者未指定 AppId 时,就会发生这种情况。如果这样做,安装程序就无法知道这两个版本是同一个应用程序,因此将在添加/删除程序 中创建一个新条目。此外,一个新的卸载日志文件 (unins???.dat) 将被创建。这显而易见的解决方案是不要更改 AppId 或 AppName。

如果必须在新版本中更改 AppName,则将 AppId 设置为上一版本的 AppId 或 AppName 的值。

安装程序会显示 "无法注册 DLL/OCX: DllRegisterServer 导出找不到" 的消息。

此消息通常意味着您指定了不具备注册能力的文件上的 "regserver" 标志。从 [Files] 条目中删除 "regserver" 标记,消息将消失。

卸载后,安装过程中创建的目录仍然存在。

目录可能无法删除的原因有几个:

我在 [Run] 区段运行了一个批处理文件,但是在完成执行后窗口仍留在屏幕上。我希望它 "退出时关闭"。

来自 Tim Rude:
要让批处理文件在退出时自动关闭,最简单的方法是用 CLS 命令在批处理文件结束时清除屏幕。

---批处理文件 1---

@echo off
echo 你好,世界
echo 该批处理文件在退出时不关闭

---批处理文件 2---

@echo off
echo 你好,世界
echo 该批处理文件在退出时关闭
cls

我已经更改了脚本中的 DefaultDirName,但是当我运行安装程序时,它仍默认为我以前的目录。

在启动时,安装程序会在注册表中查看是否有相同的应用程序被安装,如果有,它将使用上一个安装的目录作为向导中向用户呈现的默认目录。如果卸载应用程序并再次运行安装程序,它将使用新的 DefaultDirName 设置。如果您希望禁用此功能,请将 UsePreviousAppDir 设置为 "no"。

我有两个同名的 [Icons] 条目,但其中只有一个被安装。

两个文件不能具有相同的名称,并且由于快捷方式是文件,因此两个快捷方式不能具有相同的名称。

安装程序不会等待由 [Run] 条目执行的程序结束。

首先,确保你没有 在 [Run] 条目上使用 "nowait" 或 "waituntilidle" 标记。这些标志阻止安装程序等待,直到进程完全终止。

如果您没有使用这些标志,并且它似乎仍未等待程序完成,那么可能发生的情况是,您正在运行的 EXE 可能会生成其他进程,然后立即终止自身,导致安装程序认为程序已完成。众所周知,基于 InstallShield 的旧版安装程序会出现这种情况 (要解决它,请尝试使用 /SMS 开关)。

检查程序是否这样做的简单方法是从命令行运行 "START /WAIT ProgramName.exe",并在程序退出之前查看是否返回到命令提示。

某些语言在选择安装程序语言 对话框中丢失,或者即使我添加了多种语言,它也不会显示出来。

您正在使用旧的非 Unicode 版本的 Inno Setup。

映射驱动器未显示在选择目标位置 向导页面上,或无法浏览。

您的安装需要管理员权限,并且正在提升:

映射驱动器(默认情况下)不可用到任何提升的应用程序。这是在 Windows Vista 中介绍的。

有一个选项使他们可用于相同的用户级别,但这对从 LUA 运行时用户发生变化的情况没有帮助。

我的安装需要做一些 Inno Setup 显然没有的功能。

使用 Pascal 脚本功能或 [Run] 区段:

[Run] 区段是一种通常被忽视但简单的执行自定义安装任务的方法。首先,在您选择的开发工具(最好是创建独立的 EXE (如 Delphi )中编写一个小程序,以执行所需的任务,并将其 EXE 复制到脚本目录。接下来,在 [Files] 脚本区段放置一个条目,告诉安装程序将 EXE 复制到安装的临时目录 ("{tmp}"):

[Files]
Source: "ModifyAutoexec.exe"; DestDir: "{tmp}"

然后添加 [Run] 区段条目,告诉安装程序在所有其他安装步骤后执行 EXE:

[Run]
Filename: "{tmp}\ModifyAutoexec.exe"

如果程序需要其他信息,例如 "{app}" 常量值,则可以通过命令行参数,即:

[Run]
Filename: "{tmp}\ModifyAutoexec.exe"; Parameters: """{app}"""

您也可以将安装任务纳入应用程序的主要 EXE,并在调用特殊命令行参数时将其执行该任务。 例如:

[Run]
Filename: "{app}\MyProgram.exe"; Parameters: "/DoTheTask"

通配符匹配意外的扩展名。

如果在 [Files] 区段条目中使用以下通配符:

[Files]
Source: "*.htm"; DestDir: "{app}"

您可能会发现它不仅匹配扩展名为 .htm 的文件,还匹配扩展名为 .html 的文件。

这是因为在 Windows 中,通配符匹配长文件名和 8.3 别名("短文件名")。默认情况下,名为“webpage.html”的文件将具有 8.3 别名 "WEBPAG~1.HTM"; 因此,*.htm 匹配该文件。

要避免这种情况,请添加一个 Excludes 参数明确过滤掉扩展名为 .html 的文件:

[Files]
Source: "*.htm"; Excludes: "*.html"; DestDir: "{app}"

当 [Files] 条目中使用 "recursesubdirs" 标记时,不包括空目录。

createallsubdirs 标记添加到您的 [Files] 区段条目中,空目录将在安装时创建。

[Dirs] 区段也可用于创建空目录。

安装程序不会替换特定文件。

通过在 Windows 资源管理器中右键单击它们并选择属性 来比较现有文件和新文件上的版本号。默认情况下,Inno Setup 不会替换现有文件,除非现有文件没有版本信息或具有较低的版本号。

文件的二进制版本号是 Inno Setup 实际比较的内容,/LOG 在这里的切换很方便。日志将显示文件的二进制版本号以及某些文件未被替换的原因。

如果您想强制更换文件,无论其版本号如何,请将 ignoreversion 标记添加到 [Files] 区段条目中。此标志仅应用于与您的应用程序私有文件,而不应用于共享系统文件。


安装任务

创建互联网 (URL) 快捷方式

首先创建一个名为 "website.url" 的文件,并将这些行放在其中:

[InternetShortcut]
URL=http://web.site.address/

然后将这些行添加到脚本中:

[Files]
Source: "website.url"; DestDir: "{app}"

[Icons]
Name: "{group}\Visit My Web Site"; Filename: "{app}\website.url"
 

在快捷方式上设置"开始"字段

在 [Icons] 区段条目上使用 WorkingDir 参数。

创建文件关联

首先设置 [Setup] 区段指令 "ChangesAssociations" 为 "yes"。然后创建以下 5 个 [Registry] 条目,以创建文件关联。

[Registry]
Root: HKA; Subkey: "Software\Classes\.myp\OpenWithProgids"; ValueType: string; ValueName: "MyProgramFile.myp"; ValueData: ""; Flags: uninsdeletevalue

".myp" 是我们关联的扩展名。"MyProgramFile.myp" 是存储在注册表中的文件类型的内部名称。请确保为此使用唯一的名称,这样您就不会无意中覆盖其他应用程序的注册表项。

Root: HKA; Subkey: "Software\Classes\MyProgramFile.myp"; ValueType: string; ValueName: ""; ValueData: "My Program File"; Flags: uninsdeletekey

上面的 "My Program File" 是资源管理器中显示的文件类型的名称。

Root: HKA; Subkey: "Software\Classes\MyProgramFile.myp\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\MyProg.exe,0"

"DefaultIcon" 是注册表项,该项指定包含图标的文件名,以便与文件类型关联。",0" 告诉资源管理器使用 MyProg.exe 的第一个图标。(",1" 将表示第二个图标。)

Root: HKA; Subkey: "Software\Classes\MyProgramFile.myp\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\MyProg.exe"" ""%1"""

"shell\open\command" 是注册表项,该注册表项指定在资源管理器中双击该类型的文件时执行的程序。周围的引号在命令行中,因此它可以正确处理长文件名。

Root: HKA; Subkey: "Software\Classes\Applications\MyProg.exe\SupportedTypes"; ValueType: string; ValueName: ".myp"; ValueData: ""

有关 HKA 键值的详细信息,请参阅帮助文档中的非管理安装模式主题

设置环境变量

环境变量以字符串值存储在注册表中,因此可以使用 [Registry] 区段操作它们。系统范围的环境变量位于:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment

特定于用户的环境变量位于:

HKEY_CURRENT_USER\Environment

在 MS-DOS 程序的快捷方式上设置"关闭退出"框

使用 [Icons] 区段中的 "closeonexit" 和 "dontcloseonexit" 标志。

在替换文件之前进行备份

Inno Setup 目前没有用于执行此操作的特定功能,但您可以在文件被替换之前使用类似于此的 [Files] 区段条目进行复制:

Source: "{app}\MyProg.exe"; DestDir: "{app}\backup"; Flags: external skipifsourcedoesntexist uninsneveruninstall

根据 Windows 版本安装不同的文件

这可以通过输入中的 MinVersion 和/或 OnlyBelowVersion 参数完成。有关详细信息,请参阅帮助文档中的公共参数主题

文件、目录或注册表项的设置权限

[Dirs]、[Files] 和 [Registry] 区段分别支持用于设置目录、文件和注册表项权限的权限参数。

如果您有更高级的需求,请查看 SetACL

当 Windows 启动时启动程序

有两种不同的方法可以做到这一点:

  1. 要么在启动组中创建快捷方式:
    [Icons]
    Name: "{autostartup}\My Program"; Filename: "{app}\MyProg.exe"
  2. 或在注册表的 Run 项中创建值:
    [Registry]
    Root: HKA; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "MyProg"; ValueData: """{app}\MyProg.exe"""; Flags: uninsdeletevalue

有关 {autostartup} 常量的更多信息,请参阅帮助文档中的常量主题

有关 HKA 键值的详细信息,请参阅帮助文档中的非管理安装模式主题

运行批处理文件

您可以通过直接在 [Run] 区段条目的 Filename 参数中指定文件名来运行批处理文件

[Run]
Filename: "{app}\YourBatchFile.bat"

检测使用 AppMutex 在任何用户会话中运行的实例

默认情况下,AppMutex 找不到在运行安装/卸载程序的用户会话之外的用户会话中创建的互斥体。这是因为每个用户会话都有自己的内核命名空间。

要检测在其他会话中创建的互拆体,您的应用程序必须创建两个互拆体:一个带有 Global\ 前缀,另一个没有。

从任何用户会话都可以访问带有 Global\ 前缀的互拆体。在会话命名空间(即没有 Global\ 前缀)中还必须创建一个类似名称的互拆体,以防由于安全限制而无法创建全局互拆体。

此外,必须在每个 CreateMutex() 调用中传递特殊的安全描述符,以确保不同用户访问互拆体。

下面是如何在 Delphi 创建两个互拆体的示例:

procedure CreateMutexes(const MutexName: String);
{ 创建安装/卸载程序检查的两个互斥体,以查看程序是否仍在运行。}
const
  SECURITY_DESCRIPTOR_REVISION = 1;
var
  SecurityDesc: TSecurityDescriptor;
  SecurityAttr: TSecurityAttributes;
begin
{ 默认情况下,创建的互拆体只能由运行进程的用户访问。我们需要所有用户都能访问互斥体,以便互拆体检测可以跨用户会话工作。为此,我们使用带有空 DACL 的安全描述符。}
  InitializeSecurityDescriptor(@SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
  SetSecurityDescriptorDacl(@SecurityDesc, True, nil, False);
  SecurityAttr.nLength := SizeOf(SecurityAttr);
  SecurityAttr.lpSecurityDescriptor := @SecurityDesc;
  SecurityAttr.bInheritHandle := False;
  CreateMutex(@SecurityAttr, False, PChar(MutexName));
  CreateMutex(@SecurityAttr, False, PChar('Global\' + MutexName));
end;

...

begin
  CreateMutexes('YourMutexNameGoesHere');
end;

在脚本中,将 AppMutex 设置如下:

[Setup]
AppMutex=YourMutexNameGoesHere,Global\YourMutexNameGoesHere

安装 OCX 文件

建议安装 OCX 文件的方法如下。

[Files]
Source: "ComCtl32.ocx"; DestDir: "{sys}"; Flags: restartreplace sharedfile regserver


兼容性

操作系统兼容性

请参阅 "关于"页面

管理员权限

典型的 Inno Setup 安装不需要管理权限。但是,下面指出了一些例外情况。

需要管理权限的情况:

  • 在脚本的 [Setup] 区段使用 "PrivilegesRequired=admin"。如果用户缺少管理权限,这将导致安装程序中止并显示错误消息。
  • 使用 [Files] 区段中的 "restartreplace" 标记。此标志导致 Inno Setup 调用 MoveFileEx 函数,该函数试图写到 "HKEY_LOCAL_MACHINE\ SYSTEM\ CurrentControlSet\ Control\ Session Manager"。编写此项的访问仅限于管理员。
  • 使用 [Registry] 区段写入到 HKEY_USERS\.DEFAULT 下的任何项。编写此项的访问仅限于管理员。
  • 使用 [Files] 区段中的 "regserver" 标记。在大多数情况下,注册 DLL 涉及写入给 HKEY_CLASSES_ROOT,不授予普通用户的特权。
  • 使用 "sharedfile" 标志是 [Files] 区段。此标志导致 Inno Setup 在 "HKEY_LOCAL_MACHINE\ SOFTWARE\ Microsoft\ Windows\ CurrentVersion\ SharedDLLs" 中创建/更新一个值。普通用户不允许写到该项。
  • 使用 [Registry] 区段向 HKEY_LOCAL_MACHINE 或 HKEY_CLASSES_ROOT 下的任何项写入。普通用户不允许向这些项写入。

Inno Setup 本身不需要写入 Windows 目录或上述任何其他注册表项。

当安装由没有 管理权限的用户运行时,有什么不同?

  • 添加/删除程序 控制面板条目的注册表项是在 HKEY_CURRENT_USER 下创建的,而不是 HKEY_LOCAL_MACHINE。因此,只有安装程序的用户才会看到其添加/删除程序 条目。
  • "{group}" 常量始终指向当前用户的配置文件,而不是 "所有用户" 配置文件。
  • 程序可能由任何用户卸载。(当管理员安装程序时,仅允许管理员卸载它。)

有关详细信息,请参阅帮助文档中的非管理安装模式主题


其他

安装中可能包含多少个文件等是否有任何限制?

Inno Setup 对安装中可能包含的文件、快捷方式、注册表条目等数量没有任何限制。

当用户在安装期间单击"取消"时,会发生什么情况?

点击 "取消" 后,安装程序将开始以与卸载程序完全相同的方式还原其进行的更改。因此,不会遗留部分已安装的应用程序。

此 _iu14D2N.tmp 文件在我的 TEMP 目录中是什么?

卸载使用 Inno Setup 为安装程序的程序时,会创建一个名称为 "_iu14D2N.tmp" 的临时文件。卸载进程完成后,文件仍保留在目录中的原因是 Windows 不允许运行可执行文件自行删除。因此,它所做的是安排下次重新启动计算机时自动删除文件。如果您不想等到那时,手动删除文件是完全安全的,前提是当前没有卸载程序正在运行。

请注意,此行为并非 Inno Setup 所独有。

为什么安装程序会在文件未被替换时注册它们?

当文件具有 regserver 标志时,即使在安装期间未更换文件(例如,如果现有文件是较新版本),安装程序也会尝试注册该文件。

这种行为表面上似乎是多余的,但事实上这是很有必要的。因为最初安装该文件的人可能没有注册该文件。或者,现有的文件可能以某种方式被取消注册而没有被删除。如果安装程序仅替换已注册文件,那么在这两种情况下,文件在安装结束时将保持未注册状态,这样您的应用程序将无法工作。

为什么卸载程序 EXE 的名称中有数字?

经常有新用户想知道为什么卸载 EXE 的名称中有数字(例如 unins000.exe )。

这是因为 Inno Setup 允许将多个应用程序安装到同一目录中。当这种情况发生时,第一个应用程序的卸载程序被命名为 unins000.exe,第二个应用程序的卸载程序被命名为 unins001.exe,等等。如果使用了固定名称,则只能卸载最近安装的应用程序。

我可以将 Inno Setup 编译器与我的应用程序一起重新分发吗?

如果你的应用程序需要动态创建安装,则允许在遵守 Inno Setup 许可证条款的情况下,将其随 Inno Setup 编译器的文件一起部署。


网站内容版权所有 © 1997-2021 Jordan Russell。保留所有权利。
部分版权所有 © 2000-2021 Martijn Laan。保留所有权利。