飘在云端

东西南北,海角天涯

· 随笔 · · 483次浏览

Inno Setup 集成32/64位安装程序到同一个安装包

环境:Inno Setup v6.05 + win7 32/64、win10 x64 测试(UAC)

目前实现了 自动判断系统是32/64位 释放相应架构的安装文件到目标系统,也就是一个安装包里面同时包含了32和64位的安装文件,32/64位相同的资源文件可以复用降低安装包大小的。

如果不做成集成包,一个显而易见的办法是分别发布32位和64位的安装包,但是这样做不具备便携性,没办法使用同一个安装包实现完全覆盖不同位数系统。除非你又把2个安装包给打包成压缩文件发布,这样额外嵌套了压缩,也没办法自动判断,还是不够友好的。

脚本处理流程很简单,64位系统释放64位专用文件,32位释放32位专用文件,在两者系统都能用的文件就都释放,实现复用。

另外目录设计也需要跟上面的相符合,至少分成3部分,64位目录+32位目录+通用资源目录。

直接放脚本了:

#define MyAppName "Abc"
#define MyAppVersion "1.0.0"
#define MyAppExeName "abc.exe"

[Setup]
SourceDir=C:\Users\Administrator\Desktop\Abc
ArchitecturesInstallIn64BitMode=x64
;注释下面那行让安装包允许在非64位系统运行
;ArchitecturesAllowed=x64
;创建互斥安装包进程防止同时打开多个安装包程序
SetupMutex=Abc,Global\Abc
AppId={{3EC2AD97-D0E0-42A3-2035-044FA0033E8C}
; 注: AppId的值为单独标识该应用程序。
; 不要为其他安装程序使用相同的AppId值。
; (若要生成新的 GUID,可在菜单中点击 "工具|生成 GUID"。)
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppCopyright=Copyright © 2016-2021 飘在云端  www.0z.gs All Rights Reserved.  
AllowRootDirectory=yes
DefaultDirName={userappdata}\{#MyAppName}
DefaultGroupName={#MyAppName}
DisableProgramGroupPage=yes
UsedUserAreasWarning=no
LicenseFile=C:\Users\Administrator\Desktop\Agreement.rtf
;请求管理员权限(UAC)
PrivilegesRequired=admin
OutputDir=C:\Users\Administrator\Desktop\setup
OutputBaseFilename=Abc_1.0.0
SetupIconFile=C:\Users\Administrator\Desktop\1.ico
Password=123456
Encryption=yes
Compression=lzma/ultra64
SolidCompression=yes
WizardStyle=modern

[code]
;安装前后台隐藏检测旧的程序相关进程是否运行,并强制结束,返回相应代码
function InitializeSetup(): boolean;
var
ResultCode: integer;
begin

// Launch Notepad and wait for it to terminate


//if Exec(ExpandConstant('{cmd} /c taskkill /f /t /im abc.exe & taskkill /f /t /im subabc.exe &  reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable & reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d "" /f '), '', '', SW_SHOW,
  //if Exec(ExpandConstant('{win}\notepad.exe'), '', '', SW_SHOW, 
  // if Exec(ExpandConstant('{cmd}'),'/c ping -n 99 127.0.0.1', '', SW_SHOW,
   if Exec(ExpandConstant('{cmd}'),'/c taskkill /f /t /im abc.exe & taskkill /f /t /im subabc.exe &  reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable /f & reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer /d "" /f', '',SW_HIDE,
   ewWaitUntilTerminated, ResultCode) then
  begin
    // handle success if necessary; ResultCode contains the exit code
  end
  else begin
    // handle failure if necessary; ResultCode contains the error code
  end;

  // Proceed Setup
  Result := True;

end;
    
    [Files]
    
    ;64 bit 文件都放下面,可执行文件和动态链接库(.dll) 末尾都需要加 Check: Is64BitInstallMode
    Source: "Abc64\deployment\abc.exe"; DestDir: "{app}\deployment"; Flags: ignoreversion; Check: Is64BitInstallMode
    ;详细定义安装文件覆盖策略
      ; / 
    
          ; /lib/
             Source: "Abc64\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion ; Check: Is64BitInstallMode
           ; /deployment/
              Source: "Abc64\deployment\bearer\*"; DestDir: "{app}\deployment\bearer"; Flags: ignoreversion ; Check: Is64BitInstallMode
              Source: "Abc64\deployment\iconengines\*"; DestDir: "{app}\deployment\iconengines"; Flags: ignoreversion ; Check: Is64BitInstallMode 
              Source: "Abc64\deployment\imageformats\*"; DestDir: "{app}\deployment\imageformats"; Flags: ignoreversion ; Check: Is64BitInstallMode
              Source: "Abc64\deployment\lang\*"; DestDir: "{app}\deployment\lang"; Flags: ignoreversion; Check: Is64BitInstallMode
              Source: "Abc64\deployment\platforms\*"; DestDir: "{app}\deployment\platforms"; Flags: ignoreversion ; Check: Is64BitInstallMode
              Source: "Abc64\deployment\plugins\*"; DestDir: "{app}\deployment\plugins"; Flags: ignoreversion ; Check: Is64BitInstallMode
              Source: "Abc64\deployment\styles\*"; DestDir: "{app}\deployment\styles"; Flags: ignoreversion ; Check: Is64BitInstallMode
              Source: "Abc64\deployment\translations\*"; DestDir: "{app}\deployment\translations"; Flags: ignoreversion ; Check: Is64BitInstallMode
    
           ; /deployment
             Source: "Abc64\deployment\*"; DestDir: "{app}\deployment"; Flags: ignoreversion; Check: Is64BitInstallMode
    
           ; /deployment 卸载时保留用户数据
                         ;非全新安装使用模板文件覆盖默认设置
             Source: "Abc64\deployment\config\connections.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
             Source: "Abc64\deployment\config\groups.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
             Source: "Abc64\deployment\config\routes.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
             Source: "Abc64\deployment\config\UIState.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
             Source: "Abc64\deployment\config\connections";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist recursesubdirs createallsubdirs uninsneveruninstall sharedfile
             Source: "Abc64\deployment\config\generated";  DestDir: "{app}\deployment\config"; Flags: solidbreak uninsneveruninstall onlyifdoesntexist recursesubdirs createallsubdirs
             Source: "Abc64\deployment\config\plugin_settings";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist recursesubdirs createallsubdirs uninsneveruninstall sharedfile
             ;强制覆盖首选项设置
             Source: "Abc64\deployment\config\Abc.conf";  DestDir: "{app}\deployment\config"; Flags: solidbreak ignoreversion
             ;强制覆盖插件,动态链接库、可执行程序需要加系统架构检测
             Source: "Abc64\deployment\config\plugins\*";  DestDir: "{app}\deployment\config\plugins"; Flags: ignoreversion ; Check: Is64BitInstallMode
    
    
       ;32 bit 文件都放下面,从第一个32位资源开始,需要含Check: not Is64BitInstallMode,Flags参数需要含solidbreak
    
       Source: "Abc32\deployment\abc.exe"; DestDir: "{app}\deployment";  Check: not Is64BitInstallMode; Flags: solidbreak ignoreversion
      ;详细定义安装文件覆盖策略
          ; / 
              ; /lib/
                 Source: "Abc32\lib\*"; DestDir: "{app}\lib"; Check: not Is64BitInstallMode;Flags: solidbreak ignoreversion recursesubdirs createallsubdirs 
    
               ; /deployment/
                  Source: "Abc32\deployment\bearer\*"; DestDir: "{app}\deployment\bearer"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\iconengines\*"; DestDir: "{app}\deployment\iconengines"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\imageformats\*"; DestDir: "{app}\deployment\imageformats"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\lang\*"; DestDir: "{app}\deployment\lang"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\platforms\*"; DestDir: "{app}\deployment\platforms"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\plugins\*"; DestDir: "{app}\deployment\plugins"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\styles\*"; DestDir: "{app}\deployment\styles"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
                  Source: "Abc32\deployment\translations\*"; DestDir: "{app}\deployment\translations"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion recursesubdirs createallsubdirs
    
               ; /deployment
                 Source: "Abc32\deployment\*"; DestDir: "{app}\deployment"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion 
    
               ; /deployment 安装时保留用户数据,卸载时禁止删除
                             ;非全新安装使用模板文件覆盖默认设置
                 Source: "Abc32\deployment\config\connections.json";  DestDir: "{app}\deployment\config";   Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
                 Source: "Abc32\deployment\config\groups.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
                 Source: "Abc32\deployment\config\routes.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
                 Source: "Abc32\deployment\config\UIState.json";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist uninsneveruninstall sharedfile
                 Source: "Abc32\deployment\config\connections";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist  recursesubdirs createallsubdirs
                 Source: "Abc32\deployment\config\generated";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist  recursesubdirs createallsubdirs
                 Source: "Abc32\deployment\config\plugin_settings";  DestDir: "{app}\deployment\config"; Flags: solidbreak onlyifdoesntexist  recursesubdirs createallsubdirs
                 ;强制覆盖首选项设置
                 Source: "Abc32\deployment\config\Abc.conf";  DestDir: "{app}\deployment\config"; Flags: solidbreak ignoreversion  recursesubdirs createallsubdirs
                 ;强制覆盖插件,动态链接库、可执行程序需要加系统架构检测
                 Source: "Abc32\deployment\config\plugins\*";  DestDir: "{app}\deployment\config\plugins"; Check: not Is64BitInstallMode;  Flags: solidbreak ignoreversion  recursesubdirs createallsubdirs
    
         ;32/64 bit 通用的资源文件,如相同的动态链接库,程序,配置文件,文档等,我这里32和64位能通用的文件不多
     
            Source: "友情提示.docx"; DestDir: "{app}"; Flags: solidbreak ignoreversion
             Source: "使用协议.rtf"; DestDir: "{app}"; Flags: solidbreak ignoreversion 
    
    [Languages]
    Name: "chinesesimp"; MessagesFile: "compiler:Default.isl"
    
    [Tasks]
    Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone
    Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode
    
    [InstallDelete]
     ;删除旧插件
    Type: filesandordirs; Name: "{app}\deployment\config\plugins"
    
    
    
    [Icons]
    Name: "{group}\{#MyAppName}"; Filename: "{app}\deployment\{#MyAppExeName}"
    Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
    Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\deployment\{#MyAppExeName}"; Tasks: desktopicon;  Comment: "全协议客户端"
    Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\deployment\{#MyAppExeName}"; Tasks: quicklaunchicon
    
    [Run]
    Filename: "{app}\使用说明.docx"; Description: "查看使用教程"; Flags: shellexec skipifdoesntexist postinstall skipifsilent unchecked
    Filename: "{app}\deployment\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

[UninstallRun]
;卸载前杀死正在运行的旧版程序
Filename: "{app}\deployment\stopProcess.bat"; Flags: runhidden

还有一个坑,安装目录下总是多出空的子目录,搞了好久,下了各种蜜汁断点和步步运行,愣是没搞定,直到看了文档对执行流程的说明...

[InstallDelete]。
•[UninstallDelete] 
•如果需要,创建应用程序目录。
•处理 [Dirs]。
•如有必要,将保留卸载日志的文件名。
•处理 [Files] (文件注册暂不发生)。
•处理 [Icons]
......

这里文档的如果需要,创建应用程序目录,需要是由你在Files配置段里面的这个参数recursesubdirs createallsubdirs决定的,也就是不要乱用这个参数,不然安装目录会多了很多奇奇怪怪的空文件目录,同时目录结构会出现预期以外的结果,十分混乱。
除了必须要预创建的空目录存放配置文件数据,其他一律不要给这2个参数,并且 recursesubdirs createallsubdirs 的必要不充分条件,释放子文件时,已经隐含自动创建子目录的行为了。
然后就是每个64位模式的可执行文件和动态链接库文件都必须要末尾加64位的那个参数 Check: Is64BitInstallMode,32位的文件,必须要带 Check: not Is64BitInstallMode; Flags: solidbreak,那个Flags因为启用了固实压缩,所以必须加,通用不区分架构的普通文件,必须带 Flags: solidbreak
另外一些细节就是,最好先开头定义一个待打包的源路径,,如 桌面\abc,这样后面的路径都可以写成相对路径。
如果要对安装目录下的不同层级嵌套下的配置文件实现精确读写覆盖的条件判断控制,安装目录得分开写,不能偷懒直接安装目录作为顶层,企图 xxx\*,这样不行的,会完全丧失对子目录文件的覆盖行为控制,这样特定文件要删还是保留无法控制。
关于图标文件的说明,最好同时包含256*256/128*128/64*64/32*32/16*16这些分辨率,以实现低高分辨率的图标缩放支持,这里推荐使用IconWorkshop这个专业的图标制作软件。
Inno setup自带一个安装时检测相关进程是否运行的功能,但是那个没啥用,测试发现一个普通的无任何特权的进程,都大概率无法结束,还是自己写个批处理申请管理员权限,来预处理掉相关运行的进程。
还有一点,网上一堆孤儿教程和过气教程,我在卸载时如何保留指定文件吃了不少苦头,单独的uninsneveruninstall没任何用处,自带卸载程序一定删的干干净净必须是同时还指定另一个参数 sharedfile才能保留文件不被删除。

评论 (0条)