Inno Setup [Run]段结合.NET常量优雅实现try/catch异常处理
Inno Setup 中 .NET 常量解析异常的优雅处理方案
问题背景
该问题最早起源于Inno Setup官方讨论组的技术交流,核心围绕以下[Run]段配置的异常处理需求展开:
Filename: "{dotnet40}\regasm.exe"; \ Parameters: "PTSTools_x86.dll /codebase"; \ WorkingDir: "{app}"; \ Flags: runhidden Filename: "{dotnet4064}\regasm.exe"; \ Parameters: "PTSTools_x64.dll /codebase"; \ WorkingDir: "{app}"; \ Flags: runhidden; \ Check: IsWin64
按照Inno Setup官方常量文档说明,在未安装.NET Framework 4.0及以上版本的系统中尝试解析{dotnet40}、{dotnet4064}常量会直接抛出异常。但结合Inno Setup底层源码与实际用户反馈,该说明存在误导性:即便系统已安装对应版本.NET Framework,只要注册表中InstallRoot键缺失,同样会抛出内部错误异常,最终弹出含义晦涩的系统错误提示,普通用户无法理解问题原因。
实现方案
Inno Setup的内置常量解析发生在脚本逻辑执行之前,脚本层面的异常捕获无法拦截该阶段抛出的错误,因此不要尝试用try/catch包裹常量引用,最可靠的方案是完全绕开内置常量,手动实现带合法性校验的路径探测与注册逻辑:
[Code] function TryGetDotNet40Path(out Path: string): Boolean; var InstallRoot: string; begin Result := False; // 对齐内置常量的注册表读取逻辑,增加存在性校验 if RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\.NETFramework', 'InstallRoot', InstallRoot) then begin Path := AddBackslash(InstallRoot) + 'v4.0.30319\'; Result := FileExists(Path + 'regasm.exe'); end; end; function TryGetDotNet4064Path(out Path: string): Boolean; var InstallRoot: string; begin Result := False; if not IsWin64 then Exit; // 64位系统读取64位注册表节点 if RegQueryStringValue(HKLM64, 'SOFTWARE\Microsoft\.NETFramework', 'InstallRoot', InstallRoot) then begin Path := AddBackslash(InstallRoot) + 'v4.0.30319\'; Result := FileExists(Path + 'regasm.exe'); end; end; procedure Register32BitCom; var DotNetPath: string; ResultCode: Integer; begin if not TryGetDotNet40Path(DotNetPath) then begin Log('未检测到32位.NET Framework 4.0运行时,跳过32位组件注册'); Exit; end; Exec( DotNetPath + 'regasm.exe', '"' + ExpandConstant('{app}\PTSTools_x86.dll') + '" /codebase', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, ResultCode ); Log('32位regasm执行返回码:' + IntToStr(ResultCode)); end; procedure Register64BitCom; var DotNetPath: string; ResultCode: Integer; begin if not IsWin64 then Exit; if not TryGetDotNet4064Path(DotNetPath) then begin Log('未检测到64位.NET Framework 4.0运行时,跳过64位组件注册'); Exit; end; Exec( DotNetPath + 'regasm.exe', '"' + ExpandConstant('{app}\PTSTools_x64.dll') + '" /codebase', ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, ResultCode ); Log('64位regasm执行返回码:' + IntToStr(ResultCode)); end; procedure CurStepChanged(CurStep: TSetupStep); begin if CurStep = ssPostInstall then begin Register32BitCom; Register64BitCom; end; end;
方案优势
- 从根源绕开内置常量解析阶段的未捕获异常,不会弹出晦涩的内部错误提示
- 路径探测逻辑与官方内置常量完全对齐,额外增加了regasm.exe文件存在性校验,可靠性高于原生逻辑
- 异常分支可灵活扩展:既可以写入安装日志方便排查问题,也可以弹出友好提示告知用户缺失.NET依赖,甚至可以触发依赖安装流程
- 原有
[Run]段的对应配置直接删除即可,不需要调整其他安装逻辑,迁移成本极低
注意:不要在脚本中尝试通过异常捕获语句包裹
{dotnet40}这类常量引用,常量解析发生在Pascal脚本执行前,脚本层的异常捕获逻辑根本不会触发,无法达到防护效果。
内容的提问来源于stack exchange,提问作者Andrew Truckle
相关产品推荐
相关产品推荐

