琐碎记录 琐碎记录

Win系统打包exe工具Inno Setup Compiler相关

2020-07-15

具体参考:

https://jrsoftware.org/isdl.php

下载安装

1,下载主程序并安装
https://jrsoftware.org/isdl.php

2,下载中文语言(非该工具的语言而是编译自己的软件出现的安装界面相关语言)
https://jrsoftware.org/files/istrans/

3, 把中文语言包拷贝到主程序\Inno Setup\Languages目录下

4, 启动 -> File -> new 进入引导式打包编程流程 -> 编译即可(会编译成exe并输出到引导配置时的output参数目录) -> 运行exe

提升exe执行文件权限并替换ico图标

1.如何提升exe执行文件权限:
使用Resource Hacker拖入要修改的exe文件,将程序中的Manifest项新增requireAdministrator然后编译后每次运行exe则会要求管理员权限
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>

2.如何替换ico图标:
打开Resource Hacker,拖入要修改的exe文件,选择Icon Group后右键(或菜单Action)点击Replace Icon替换图标即可

例子test.iss

; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "测试软件"
#define MyAppVersion "v0.0.1."
#define MyAppPublisher "测试公司"
#define MyAppURL "http://www.demo.com"
; 打包的程序所在目录的执行文件(须在打包程序所在目录下)
#define MyAppExeName "demo.exe"
; 定义实际安装到用户系统里的文件夹名
#define InstallDirName "MyDemoDir"
; 安装EXE文件的图标
#define MySetupExeIcon "C:\demo\build\logo.ico"
; 桌面快捷图标文件(须在打包程序所在目录下)
#define DesktopIconFile "desktop.ico"
; 时间戳(注意:使用ISCC.exe外部调用传入相同参数名BuildTimeStr时这里需要注释掉)
#define BuildTimeStr GetDateTimeString('yyyymmddhhnnss', '-', '')
; 定义要打包的程序所在目录(存放demo.exe与desktop.ico等文件)
#define MYAPPSOURCEDIR "C:\demo\app"
; 定义编译输出(编译后的exe在out目录)
#define BUILDTARGETNAME "demo.enterprise"
#define BUILDTARGETDIR "C:\demo\build\out"
; 

[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开头可能需要两个{
AppId={C793C68A-6718-4B15-A684-48FAA7331F4C}
AppName={#MyAppName}
AppVersion={#MyAppVersion}{#BuildTimeStr}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\{#InstallDirName}
;禁止用户选择自定义目录,需要用户自己选择安装目录则写no或注释掉
DisableDirPage=yes
DisableProgramGroupPage=yes
LicenseFile={#MYAPPSOURCEDIR}\LICENSE.TXT
InfoBeforeFile={#MYAPPSOURCEDIR}\README.txt
InfoAfterFile=
;安装模式权限提升lowest/admin,默认lowest(当前用户),取消注释以在管理安装模式下运行
;PrivilegesRequired=admin
OutputDir={#BUILDTARGETDIR}
OutputBaseFilename={#BUILDTARGETNAME}.{#MyAppVersion}{#BuildTimeStr}.win64.setup
SetupIconFile={#MySetupExeIcon}
;压缩zip/1至9;lzma2/max;lzma2(7z压缩方法);none;lzma2/fast;lzma2/ultra64(超级压缩);
Compression=lzma2/max
SolidCompression=yes
WizardStyle=modern

; 安装语言 (对应InnoSetup6\Languages\目录下,默认没有中文需要先下载到该目录)
[Languages]
Name: "chinese"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"

[Tasks]
; 自定义桌面快捷图标方式时的任务
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone

; 打包安装相关主执行程序与其它相关目录
[Files]
Source: "{#MYAPPSOURCEDIR}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
; 排除文件时加上Excludes,\开头表示只排除根目录,非\开头会排除所有子目录相匹;排除多个以逗号分隔如:\test,*.log,*.DS_Store,._*
Source: "{#MYAPPSOURCEDIR}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs;Excludes: "\target,\project\.settings,*.log,*.DS_Store,._*"
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
; 安装完成后根据当前机器信息动态修改配置文件里对应的设置(调用[Code]自定义函数AfterInstallUpdate)
Source: "{#MYAPPSOURCEDIR}\demoConfig.ini"; DestDir: "{app}"; AfterInstall: AfterInstallUpdate

[Icons]
; 默认使用exe图标方式
; Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
; 自定义桌面快捷图标方式
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon; IconFilename:"{app}\{#DesktopIconFile}"

; 安装结束是否允许用户运行
; [Run]
; Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent

; 安装前清空安装目录
[InstallDelete]
Name: "{autopf}\{#InstallDirName}"; Type: filesandordirs

; 自定义函数代码片段(可选)
[Code]
// 对话框使用(如果没有用到可去掉,具体参考InnoSetup6\Examples目录的CodeDll.iss示例)
function MessageBox(hWnd: Integer; lpText, lpCaption: String; uType: Cardinal): Integer;
external 'MessageBoxW@user32.dll stdcall';
// 引入Windows系统API获取内存信息
function GetPhysicallyInstalledSystemMemory(var TotalMemoryInKilobytes: Int64): Boolean;
external 'GetPhysicallyInstalledSystemMemory@kernel32.dll stdcall setuponly';

// -------定义函数过程代码(安装完后调用,通过上面Source指定的AfterInstall)-------
procedure AfterInstallUpdate;
var
  ConfigIniPath: string;
  FileContent: AnsiString;
  FileContentString: string;
  memorySize: Int64;
begin
  if GetPhysicallyInstalledSystemMemory(memorySize) then
  begin
    memorySize := memorySize div (2*1024);
    // Log('打印:' + IntToStr(memorySize) + ' MB');
  end;
  if memorySize > 1000 then
  begin
    // 获取已解压的配置文件路径
    ConfigIniPath := ExpandConstant('{app}\demoConfig.ini');
    // 读取文件内容到FileContent
    LoadStringFromFile(ConfigIniPath, FileContent);
    // 文件的内容类型AnsiString转化为string
    FileContentString := FileContent;
    // 替换字符串
    StringChange(FileContentString, '-Xmx1024m','-Xmx'+IntToStr(memorySize)+'m');
    // 将替换后的内容写入原文件(False:覆盖,True:追加)
    SaveStringToFile(ConfigIniPath, FileContentString ,False);
  end;
end;

// -------简单的自定义安装页面代码-------
var
  CustomPage: TWizardPage;
  Edit1: TNewEdit;
function CustomPageOnNextButtonClick(Page: TWizardPage): Boolean;
begin
  { 在这里添加自定义的下一步操作 }
  MsgBox('自定义下一步操作', mbInformation, MB_OK);
end;

procedure InitializeWizard();
begin
  { 创建自定义页面 }
  CustomPage := CreateCustomPage(wpWelcome,'测试页', '这是一个自定义描述');
  // 自定义下一步(去掉则走正常的下一步流程)
  CustomPage.OnNextButtonClick := @CustomPageOnNextButtonClick;
  { 在自定义页面上添加文本框 }
  Edit1 := TNewEdit.Create(CustomPage);
  Edit1.Parent := CustomPage.Surface;
  Edit1.Left := ScaleX(10);
  Edit1.Top := ScaleY(50);
  Edit1.Width := ScaleX(200);
end;

// -------简单的启动初始化代码-------
function InitializeSetup(): Boolean;
var
  hWnd: Integer;
begin
  // 在此写入安装文件启动时执行逻辑示例:
  hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));
  MessageBox(hWnd, '开始安装...', '提示信息', MB_OK);
  Result := True;
end;

; 操作注册表(可选)
;[registry]
Root:HKLM;Subkey:SOFTWARE\Microsoft\Windows\CurrentVersion\Run;ValueType: string; ValueName:DEMO;ValueData:{app}\demo.exe;Flags: uninsdeletevalue

脚本调用iss文件build.bat

@echo off

:: 清空要打包的软件目录下的一些文件或文件夹(可选)
RMDIR C:\soft\test\configuration\.settings /S /Q
DEL C:\soft\test\configuration\*.log /A /F /Q
DEL C:\soft\test\configuration\org.test.core\*.* /A /F /Q
DEL C:\soft\test\configuration\org.eclipse.update\history\*.* /A /F /Q

:: 基于时间的版本 ———————————————
set CURRENT_TIME=%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%%time:~6,2%
set "CURRENT_TIME=%CURRENT_TIME: =0%"

::打包前替换一些配置值———————————————
:: 替换固定值(比如把TEST_FREE_PRODUCT替换为TEST_ENTERPRISE_PRODUCT)...
@ECHO start replace...
set filepath=C:\test\config.ini
(for /f "delims=" %%a in (%filepath%) do (
set "str=%%a"
setlocal enabledelayedexpansion
set "str=!str:TEST_FREE_PRODUCT=TEST_ENTERPRISE_PRODUCT!"
echo,!str!
endlocal
))>#
MOVE /y # %filepath%
:: 替换变量=后的动态值(比如变量名为'当前时间戳',使用正则替换为上面设置的CURRENT_TIME)
set filenumcmd='findstr /r /n "当前时间戳=*" %filepath%'
for /F "delims=:" %%i in (%filenumcmd%) do (
	set serverlineNum=%%i
)
echo serverlineNum=%serverlineNum%
setlocal enabledelayedexpansion
set numindex=0
for /F "tokens=1* delims=:" %%i in ('findstr /n .* %filepath%') do (
	set /a numindex+=1
	if %serverlineNum%==!numindex! (
		echo 当前时间戳=%CURRENT_TIME%
	)else (
		echo.%%j
	)
)>>#
MOVE /y # %filepath%
echo !numindex!
ENDLOCAL
::打包开始———————————————
@ECHO start build...
cd C:\软件安装目录\InnoSetup6
REM cmd中输入ISCC.exe /? 命令查看更多InnoSetup使用iscc的帮助,/D为定义参数变量并传递到test.iss里使用(注意:使用外部传递参数时原文件里的BuildTimeStr定义则需要去掉)
ISCC.exe /DBuildTimeStr=%CURRENT_TIME% "C:\test\test.iss"
::打包结束———————————————
@ECHO end build...
PAUSE

Content