2025-08-15 11:47:44 +08:00
;iss
#define MyAppName "基础环境"
2025-08-26 16:15:34 +08:00
#define MyAppVersion "1.0.14"
2025-08-15 11:47:44 +08:00
#define MyAppPublisher "X"
#define MyAppURL "~"
#define MyAppExeName "command"
2025-08-17 18:52:13 +08:00
#define MyAppExeNameHump "Command"
#define MyAppExeNameUpper "COMMAND"
2025-08-15 11:47:44 +08:00
#define MyAppAssocName MyAppName + " File"
#define MyAppAssocExt ".myp"
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
2025-08-18 14:32:39 +08:00
#define MyAppFirstPath "XManage"
#define MyAppResources "Resources"
#define InstallPassword GetDateTimeString('yyyymmdd', '', '')
2025-08-19 18:15:31 +08:00
#define BuildTime GetDateTimeString('yyyymmddhhnnss', '', '')
2025-08-15 11:47:44 +08:00
; 默认配置
[Setup]
2025-08-15 15:43:00 +08:00
; 不得复用, 每个应用必须有唯一AppId
2025-08-19 11:26:23 +08:00
AppId={{517C2278-C7C9-43D0-8E94-BFD2039C1690}
2025-08-15 11:47:44 +08:00
; 默认安装路径
2025-08-19 14:41:10 +08:00
DefaultDirName={localappdata}\{#MyAppFirstPath}
2025-08-15 11:47:44 +08:00
; 是否加密
;Encryption=yes
; 安装密码
2025-08-18 14:32:39 +08:00
;Password={#InstallPassword}
2025-08-15 11:47:44 +08:00
; ICO图标
; SetupIconFile=Resources\startup.ico
UninstallFilesDir={app}
UninstallDisplayIcon={app}\{#MyAppExeName}.exe
VersionInfoCompany=
VersionInfoCopyright=CopyRight © 2025
2025-08-19 18:15:31 +08:00
VersionInfoDescription=构建于 {#BuildTime}, 装配DB、IO、MQ、Command等
2025-08-18 17:18:54 +08:00
VersionInfoProductVersion={#MyAppVersion}
2025-08-15 11:47:44 +08:00
VersionInfoProductName=基础环境( 支持Windows7及以上)
; 默认配置
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
ChangesAssociations=yes
DisableDirPage=no
2025-08-15 15:37:52 +08:00
DisableProgramGroupPage=yes
2025-08-15 11:47:44 +08:00
Compression=lzma2
SolidCompression=yes
WizardStyle=modern
ChangesEnvironment=yes
PrivilegesRequired=admin
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
OutputDir=Release\
2025-08-26 13:15:18 +08:00
OutputBaseFilename=RuntimeSetup-{#MyAppVersion}
2025-08-15 11:47:44 +08:00
; 语言选择
[Languages]
2025-08-15 15:37:52 +08:00
Name: "Chinese"; MessagesFile: "compiler:Languages\Chinese.isl";
;; 任务
[Tasks]
; 是否创建桌面图标
2025-08-18 14:32:39 +08:00
; checkablealone 默认选中
; unchecked 默认不选中
2025-08-19 18:15:31 +08:00
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone
2025-08-15 11:47:44 +08:00
2025-08-17 12:37:05 +08:00
;; 程序 ICO
[Icons]
;Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}.exe"
2025-08-26 13:15:18 +08:00
Name: "{autodesktop}\Quick Start Environment"; Filename: "{app}\quick.bat"; Comment: "一键启动 Redis、MinIO、Home、RocketMQ 服务"; Tasks: desktopicon
2025-08-17 12:37:05 +08:00
2025-08-15 11:47:44 +08:00
;; 组件安装方式
[Types]
2025-08-15 15:37:52 +08:00
Name: "full"; Description: "完整组件安装";
Name: "mini"; Description: "最小安装";
2025-08-17 12:37:05 +08:00
;; ============================================== 自定义组件 必须启用 iscustom 作为 Flags ==============================================
2025-08-15 15:37:52 +08:00
; iscustom 开启自定义选项
Name: "custom"; Description: "自定义组件安装"; Flags: iscustom;
2025-08-15 11:47:44 +08:00
;; 组件列表选择项
[Components]
2025-08-17 12:37:05 +08:00
;; ============================================== 自定义组件的 Types 可以不参与任何固定式 ==============================================
2025-08-15 15:37:52 +08:00
Name: "MainApp"; Description: "{#MyAppName}主程序"; Types: full mini; Flags: checkablealone;
2025-08-19 11:26:23 +08:00
Name: "JDK"; Description: "JDK"; Types: full; Flags: checkablealone;
Name: "Redis"; Description: "Redis"; Types: full; Flags: checkablealone;
Name: "MinIO"; Description: "MinIO"; Types: full; Flags: checkablealone;
Name: "RocketMQ"; Description: "RocketMQ"; Types: full; Flags: checkablealone;
Name: "Nginx"; Description: "Nginx"; Types: full; Flags: checkablealone;
Name: "MySQL"; Description: "MySQL"; Types: full; Flags: checkablealone;
2025-08-15 11:47:44 +08:00
;; 引入文件列表
[Files]
2025-08-17 12:37:05 +08:00
;; ============================================== 共享文件 禁止使用 ignoreversion 作为 Flags ==============================================
2025-08-15 11:47:44 +08:00
;; Readme
2025-08-15 15:37:52 +08:00
; 安装完的 readme 信息
2025-08-18 14:32:39 +08:00
;Source: "{#MyAppResources}\Readme.md"; DestDir: "{app}"; Flags: isreadme;
2025-08-15 11:47:44 +08:00
;; 文件
2025-08-18 14:32:39 +08:00
Source: "{#MyAppResources}\grep.exe"; DestDir: "{app}\usr"; DestName: "grep.exe"; Flags: ignoreversion; Components: MainApp;
2025-08-19 18:15:31 +08:00
Source: "{#MyAppResources}\quick.bat"; DestDir: "{app}"; DestName: "quick.bat"; Flags: ignoreversion; Components: MainApp;
2025-08-15 11:47:44 +08:00
;; 文件夹
2025-08-15 15:37:52 +08:00
; recursesubdirs createallsubdirs 递归复制整个目录
2025-08-18 14:32:39 +08:00
Source: "{#MyAppResources}\usr\*"; DestDir: "{app}\usr\"; Flags: ignoreversion recursesubdirs createallsubdirs; Components: MainApp;
2025-08-15 15:37:52 +08:00
; onlyifdoesntexist 当文件不存在时安装
2025-08-18 14:32:39 +08:00
Source: "{#MyAppResources}\jdk\*"; DestDir: "{app}\jdk\"; Flags: ignoreversion recursesubdirs createallsubdirs onlyifdoesntexist; Components: JDK;
Source: "{#MyAppResources}\redis\*"; DestDir: "{app}\redis\"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs; Components: Redis;
Source: "{#MyAppResources}\io\*"; DestDir: "{app}\io\"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs; Components: MinIO;
Source: "{#MyAppResources}\rocketmq\*"; DestDir: "{app}\rocketmq\"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs; Components: RocketMQ;
Source: "{#MyAppResources}\nginx\*"; DestDir: "{app}\nginx\"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs; Components: Nginx;
Source: "{#MyAppResources}\mysql\*"; DestDir: "{app}\mysql\"; Flags: onlyifdoesntexist recursesubdirs createallsubdirs; Components: MySQL;
2025-08-15 11:47:44 +08:00
;; 创建必要目录
[Dirs]
2025-08-17 12:56:44 +08:00
Name: "{app}\nginx\logs"; Permissions: users-modify; Components: Nginx;
2025-08-15 15:37:52 +08:00
Name: "{app}\nginx\dist"; Permissions: users-modify; Components: Nginx;
2025-08-15 11:47:44 +08:00
2025-08-26 13:15:18 +08:00
;; 安装前后删除文件(存在不生效的可能,转为 code 实现)
2025-08-15 11:47:44 +08:00
[InstallDelete]
2025-08-17 12:37:05 +08:00
;Type: files; Name: "{app}\mysql\template.ini";
;Type: files; Name: "{app}\mysql\template-initialize-and-start-mysql.bat";
;Type: files; Name: "{app}\mysql\template-register-mysql-with-data.bat";
2025-08-15 11:47:44 +08:00
;; 安装时注册表与环境变量列表
[Registry]
2025-08-15 15:37:52 +08:00
; uninsdeletevalue 卸载时删除值
; uninsdeletekey 卸载时删除键
; preservestringtype 保留原值类型
2025-08-17 04:32:18 +08:00
;; ============================================== Path 禁止使用任何 *delete*、*remove* 作为 Flags 运行 ==============================================
;; 写入普通注册表项
2025-08-15 15:37:52 +08:00
Root: HKLM; Subkey: "Software\X\Command"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletevalue ;
Root: HKLM; Subkey: "Software\X\Command"; ValueType: string; ValueName: "Version"; ValueData: "{#SetupSetting("AppVersion")}"; Flags: uninsdeletevalue ;
2025-08-15 11:47:44 +08:00
2025-08-15 15:37:52 +08:00
;; 默认注册信息
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue;
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletevalue;
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName}.exe,0"; Flags: uninsdeletevalue;
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}.exe"" ""%1"""; Flags: uninsdeletevalue;
2025-08-15 11:47:44 +08:00
2025-08-18 14:32:39 +08:00
2025-08-19 18:15:31 +08:00
;; 【grep、awk、sed、head、sort、ls、rm、xargs、rar、zip、tar、md5sum、sha1sum...】
2025-08-18 14:32:39 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: MainApp; Flags: uninsdeletevalue; \
ValueName: "X_COMMAND"; ValueData: "{app}";
2025-08-19 18:15:31 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: MainApp; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
ValueName: "Path"; ValueData: "{olddata};%X_COMMAND%\usr"; Check: NeedsAddPath('%X_COMMAND%\usr');
2025-08-15 11:47:44 +08:00
2025-08-15 15:37:52 +08:00
;; 【Java】追加到 PATH 变量
2025-08-18 14:32:39 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: JDK; \
2025-08-15 15:37:52 +08:00
ValueName: "JAVA_HOME"; ValueData: "{app}\jdk"; Flags: uninsdeletevalue ;
2025-08-18 14:32:39 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: JDK; \
2025-08-15 15:37:52 +08:00
ValueName: "JDK_21"; ValueData: "{app}\jdk"; Flags: uninsdeletevalue ;
2025-08-26 13:15:18 +08:00
; 为了启用 java、jps、jar 命令
2025-08-18 14:32:39 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: JDK; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
ValueName: "Path"; ValueData: "{olddata};%JAVA_HOME%\bin"; Check: NeedsAddPath('%JAVA_HOME%\bin');
2025-08-15 11:47:44 +08:00
2025-08-26 13:15:18 +08:00
2025-08-15 15:37:52 +08:00
;; 【Redis】追加到 PATH 变量
2025-08-26 13:15:18 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: Redis; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
2025-08-18 14:32:39 +08:00
ValueName: "Path"; ValueData: "{olddata};%X_COMMAND%\redis"; Check: NeedsAddPath('%X_COMMAND%\redis');
2025-08-26 13:15:18 +08:00
;
; 关闭注册到环境变量,整体由一键启动脚本代为执行
2025-08-15 11:47:44 +08:00
2025-08-15 15:37:52 +08:00
;; 【MinIO】追加到 PATH 变量
2025-08-26 13:15:18 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: MinIO; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
2025-08-18 14:32:39 +08:00
ValueName: "Path"; ValueData: "{olddata};%X_COMMAND%\io"; Check: NeedsAddPath('%X_COMMAND%\io');
2025-08-26 13:15:18 +08:00
;
; 关闭注册到环境变量,整体由一键启动脚本代为执行
2025-08-15 11:47:44 +08:00
2025-08-15 15:37:52 +08:00
;; 【Nginx】追加到 PATH 变量
2025-08-26 13:15:18 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: Nginx; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
2025-08-18 14:32:39 +08:00
ValueName: "Path"; ValueData: "{olddata};%X_COMMAND%\nginx"; Check: NeedsAddPath('%X_COMMAND%\nginx');
2025-08-26 13:15:18 +08:00
;
; 关闭注册到环境变量,整体由一键启动脚本代为执行
2025-08-15 11:47:44 +08:00
2025-08-19 18:15:31 +08:00
;; 【RocketMQ】追加到 PATH 变量
2025-08-26 13:15:18 +08:00
; rocketmq 脚本必要参数
2025-08-19 18:15:31 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: RocketMQ; Flags: uninsdeletevalue; \
ValueName: "ROCKETMQ_HOME"; ValueData: "{app}\rocketmq"; Check: CheckRegistryPath('{app}\rocketmq');
2025-08-26 13:15:18 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: RocketMQ; Flags: uninsdeletevalue; \
2025-08-19 18:15:31 +08:00
ValueName: "ROCKETMQ_SBIN"; ValueData: "{app}\rocketmq\sbin";
2025-08-26 13:15:18 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: RocketMQ; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
2025-08-19 18:15:31 +08:00
ValueName: "Path"; ValueData: "{olddata};%ROCKETMQ_SBIN%"; Check: NeedsAddPath('%ROCKETMQ_SBIN%');
2025-08-26 13:15:18 +08:00
;
; 关闭注册到环境变量,整体由一键启动脚本代为执行
2025-08-19 18:15:31 +08:00
2025-08-15 15:37:52 +08:00
;; 【MySQL】环境变量【注册服务使用】
2025-08-15 11:47:44 +08:00
; 数据库服务注册后服务名
2025-08-18 14:32:39 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: MySQL; Flags: uninsdeletevalue; AfterInstall: RefreshEnvironment; \
ValueName: "X_MANAGE_DB_SC"; ValueData: "x_database";
2025-08-15 11:47:44 +08:00
; 这两个值,将作为后续判断程序是否已经安装做依据
2025-08-18 14:32:39 +08:00
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: MySQL; Flags: uninsdeletevalue; AfterInstall: RefreshEnvironment; \
ValueName: "X_MANAGE_DB_EXE"; ValueData: "{app}\mysql\bin\mysqld.exe";
;Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: MySQL; Flags: uninsdeletevalue ; AfterInstall: RefreshEnvironment; \
ValueName: "X_MANAGE_DB_COF"; ValueData: "{app}\mysql\my.ini";
2025-08-26 13:15:18 +08:00
;
; 暂时关闭注册到环境变量,暂时由 bat 启动或直接注册到服务
; 上述环境变量是 ps1 启动时所需的必要参数,状态暂停,等待整理
2025-08-15 15:37:52 +08:00
; MySQL【通用服务】, 导入脚本数据使用
2025-08-18 14:32:39 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; Components: MySQL; Flags: uninsdeletevalue; \
ValueName: "X_COMMAND_MYSQL"; ValueData: "{app}\mysql\";
2025-08-26 13:15:18 +08:00
; 追加到 PATH 变量, where mysql 语法判定使用
2025-08-18 14:32:39 +08:00
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; Components: MySQL; Flags: preservestringtype; AfterInstall: RefreshEnvironment; \
ValueName: "Path"; ValueData: "{olddata};%X_COMMAND_MYSQL%\bin"; Check: NeedsAddPath('%X_COMMAND_MYSQL%\bin');
2025-08-15 15:37:52 +08:00
2025-08-15 11:47:44 +08:00
2025-08-19 18:15:31 +08:00
2025-08-15 11:47:44 +08:00
;; 自定义函数
[Code]
const
2025-08-26 13:15:18 +08:00
// 系统环境变量
2025-08-15 11:47:44 +08:00
WM_SETTINGCHANGE = 26; // 0x001A 的十进制
SMTO_ABORTIFHUNG = 2; // 0x0002 的十进制
2025-08-15 15:37:52 +08:00
// 定义 VC++ 2019 运行时的注册表检查路径
VC2019_REDIST_X64 = '{FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4}';
VC2019_REDIST_X86 = '{422B21A3-06FA-3F2F-A6C6-21BCC9B8E2F3}';
2025-08-26 13:15:18 +08:00
// 服务
SC_MANAGER_CONNECT = $0001;
SERVICE_STOP = $0020;
SERVICE_QUERY_STATUS = $0004;
SERVICE_CONTROL_STOP = $00000001;
2025-08-18 14:32:39 +08:00
// 获取安装密码
function GetInstallPassword(): string;
begin
Result := GetDateTimeString('yyyymmdd', '', '');
end;
2025-08-19 18:15:31 +08:00
// 获取当前时间
function GetDateTime(): String;
begin
// Result := GetDateTimeString('yyyy/mm/dd hh:nn:ss', '-', ':');
Result := GetDateTimeString('yyyymmddhhnnss', '', '');
end;
2025-08-26 13:15:18 +08:00
// 导入 Windows API 函数,作用于 延迟函数
function GetTickCount: DWord;
external 'GetTickCount@kernel32.dll stdcall';
// 导入 Windows API 函数,作用于 环境变量更新
2025-08-15 11:47:44 +08:00
function SendMessageTimeout(
hWnd: Integer;
Msg: Integer;
wParam: Integer;
lParamStr: String;
fuFlags: Integer;
uTimeout: Integer;
var lpdwResult: Integer
): Integer;
external 'SendMessageTimeoutW@user32.dll stdcall';
2025-08-26 13:15:18 +08:00
// 导入必要的 Windows API 函数,作用于 服务
function OpenService(
hSCManager: Longword;
lpServiceName: string;
dwDesiredAccess: Longword
): Longword;
external 'OpenServiceW@advapi32.dll stdcall';
// 导入必要的 Windows API 函数,作用于 服务
function ControlService(
hService: Longword;
dwControl: Longword;
var lpServiceStatus: Longword
): Integer;
external 'ControlService@advapi32.dll stdcall';
// 导入必要的 Windows API 函数,作用于 服务
function CloseServiceHandle(
hSCObject: Longword
): Integer;
external 'CloseServiceHandle@advapi32.dll stdcall';
// 导入必要的 Windows API 函数,作用于 服务
function OpenSCManager(
lpMachineName: string;
lpDatabaseName: string;
dwDesiredAccess: Longword
): Longword;
external 'OpenSCManagerW@advapi32.dll stdcall';
2025-08-15 11:47:44 +08:00
// 给 Path 系统环境变量追加环境
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
begin
if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
'SYSTEM\CurrentControlSet\Control\Session Manager\Environment',
'Path', OrigPath)
then begin
Result := True;
exit;
end;
// 检查路径是否已存在
Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
if Result = True then
Result := Pos(';' + Param + '\;', ';' + OrigPath + ';') = 0;
end;
// 刷新系统环境
procedure RefreshEnvironment;
var
Res: Integer;
begin
SendMessageTimeout(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
'Environment',
SMTO_ABORTIFHUNG,
5000,
Res
);
end;
// 检查环境变量,路径是否存在空格
function CheckRegistryPath(Path: string): Boolean;
begin
if Pos(' ', Path) > 0 then
begin
SuppressibleMsgBox('安装程序错误: 检测到无效的注册表路径 "' + Path + '"。路径不能包含空格。', mbCriticalError, MB_OK, IDOK);
Abort;
Result := False;
Exit;
end;
Result := True;
end;
// 以 UTF-8 写入文件
function SaveStringToUTF8File(const FileName, Content: String; Append: Boolean): Boolean;
var
UTF8Content: AnsiString;
begin
UTF8Content := UTF8Encode(Content);
Result := SaveStringToFile(FileName, UTF8Content, Append);
end;
2025-08-15 15:37:52 +08:00
// 检查是否已安装 VC++ 2019 运行时
function IsVC2019Installed: Boolean;
var
Version: String;
begin
// 检查64位版本
Result := RegQueryStringValue(
HKLM,
'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64',
'Version',
Version
) or RegKeyExists(
HKLM,
'SOFTWARE\Classes\Installer\Dependencies\' + VC2019_REDIST_X64
);
// 如果是32位系统或需要检查32位运行时
if not Result and (not IsWin64) then
Result := RegQueryStringValue(
HKLM,
'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86',
'Version',
Version
) or RegKeyExists(
HKLM,
'SOFTWARE\Classes\Installer\Dependencies\' + VC2019_REDIST_X86
);
end;
2025-08-26 13:15:18 +08:00
// 延迟n秒
procedure Delay(Seconds: Integer);
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{cmd}'), '/C timeout /t ' + IntToStr(Seconds) + ' /nobreak > nul', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
// 延迟n毫秒
procedure DelayMS(MS: Cardinal);
var
T: Cardinal;
begin
T := GetTickCount;
while (GetTickCount - T) < MS do
begin
// 处理消息队列,防止界面冻结
Sleep(10);
WizardForm.Refresh;
end;
end;
2025-08-15 15:37:52 +08:00
2025-08-26 13:15:18 +08:00
// InitializeSetup 安装程序初始化时 检查系统环境、前置条件
// InitializeWizard 向导初始化时 自定义界面、预设置
// CurStepChanged 安装步骤改变时 在特定步骤(如安装前、后)执行自定义操作
// DeinitializeSetup 安装结束时(无论成功与否) 清理临时文件、最终配置
2025-08-15 11:47:44 +08:00
// 从模板创建配置文件
procedure CreateConfigFromTemplate;
var
// ini
TemplateIniPath: String;
TargetIniPath: String;
// initial
TemplateInitialPath: String;
TargetInitialPath: String;
// register
TemplateRegisterPath: String;
TargetRegisterPath: String;
// handle params
ConfigLines: TArrayOfString;
I: Integer;
ReplaceCount: Integer;
begin
2025-08-26 13:15:18 +08:00
// 生成 my.ini
2025-08-15 11:47:44 +08:00
TemplateIniPath := ExpandConstant('{app}\mysql\template.ini');
TargetIniPath := ExpandConstant('{app}\mysql\my.ini');
if LoadStringsFromFile(TemplateIniPath, ConfigLines) then
begin
for I := 0 to GetArrayLength(ConfigLines)-1 do
begin
StringChangeEx(ConfigLines[I], '%INSTALLPATH%', ExpandConstant('{app}\mysql'), True);
StringChangeEx(ConfigLines[I], '%DATAPATH%', ExpandConstant('{app}\mysql\data'), True);
StringChangeEx(ConfigLines[I], '\', '\\', True);
end;
SaveStringsToFile(TargetIniPath, ConfigLines, False);
end;
2025-08-26 13:15:18 +08:00
// 生成 initialize-and-start-mysql.bat
2025-08-15 11:47:44 +08:00
TemplateInitialPath := ExpandConstant('{app}\mysql\template-initialize-and-start-mysql.bat');
TargetInitialPath := ExpandConstant('{app}\mysql\initialize-and-start-mysql.bat');
if LoadStringsFromFile(TemplateInitialPath, ConfigLines) then
begin
for I := 0 to GetArrayLength(ConfigLines)-1 do
begin
StringChangeEx(ConfigLines[I], '%INSTALLPATH%', ExpandConstant('{app}\mysql'), True);
end;
SaveStringsToFile(TargetInitialPath, ConfigLines, False);
end;
2025-08-26 13:15:18 +08:00
// 生成 register-mysql-with-data.bat
2025-08-15 11:47:44 +08:00
TemplateRegisterPath := ExpandConstant('{app}\mysql\template-register-mysql-with-data.bat');
TargetRegisterPath := ExpandConstant('{app}\mysql\register-mysql-with-data.bat');
if LoadStringsFromFile(TemplateRegisterPath, ConfigLines) then
begin
for I := 0 to GetArrayLength(ConfigLines)-1 do
begin
StringChangeEx(ConfigLines[I], '%INSTALLPATH%', ExpandConstant('{app}\mysql'), True);
end;
SaveStringsToFile(TargetRegisterPath, ConfigLines, False);
end;
end;
2025-08-15 15:37:52 +08:00
2025-08-26 16:15:34 +08:00
// 删除过程文件
procedure RemoveTempFile;
begin
// DeleteFile
// DelTree
// 删除模版文件
if FileExists(ExpandConstant('{app}\mysql\template.ini')) then
DeleteFile(ExpandConstant('{app}\mysql\template.ini'));
if FileExists(ExpandConstant('{app}\mysql\template-initialize-and-start-mysql.bat')) then
DelTree(ExpandConstant('{app}\mysql\template-initialize-and-start-mysql.bat'), False, True, False);
if FileExists(ExpandConstant('{app}\mysql\template-register-mysql-with-data.bat')) then
DelTree(ExpandConstant('{app}\mysql\template-register-mysql-with-data.bat'), False, True, False);
if FileExists(ExpandConstant('{app}\mysql\import-data-into-mysql-v2.bat')) then
DelTree(ExpandConstant('{app}\mysql\import-data-into-mysql-v2.bat'), False, True, False);
// 删除默认 Readme.md
if FileExists(ExpandConstant('{app}\io\Readme.md')) then
DeleteFile(ExpandConstant('{app}\io\Readme.md'));
if FileExists(ExpandConstant('{app}\jdk\Readme.md')) then
DeleteFile(ExpandConstant('{app}\jdk\Readme.md'));
if FileExists(ExpandConstant('{app}\mysql\Readme.md')) then
DeleteFile(ExpandConstant('{app}\mysql\Readme.md'));
if FileExists(ExpandConstant('{app}\nginx\Readme.md')) then
DeleteFile(ExpandConstant('{app}\nginx\Readme.md'));
end;
// 初始化并启动MySQL
procedure InitializeAndStartMySQL;
var
ResultCode: Integer;
Cmd: string;
begin
// 通过 mysql 初始化生成的唯一 uuid 判断 mysql 是否已经完成初始化
if not FileExists(ExpandConstant('{app}\mysql\data\auto.cnf')) then
begin
// 如果没有完成初始化,则判断是否存在 readme.md 文件 即完全没有初始化
if FileExists(ExpandConstant('{app}\mysql\data\Readme.md')) then
begin
// 如果没有初始化,则删除 readme
DelTree(ExpandConstant('{app}\mysql\data\Readme.md'), False, True, False);
DelayMS(200);
end;
// 存在默认库SQL压缩包
if FileExists(ExpandConstant('{app}\mysql\database.rar')) then
begin
// 解压
if not Exec('cmd.exe', '/C " cd ' + ExpandConstant('{app}') + '\mysql && %cd%\..\usr\unrar.exe x database.rar script\demo\"', '', SW_HIDE, ewNoWait, ResultCode) then
begin
MsgBox('解压 MySQL 默认库失败', mbError, MB_OK);
end;
// 删除 database.rar 默认库SQL压缩包
DelayMS(1000);
DelTree(ExpandConstant('{app}\mysql\database.rar'), False, True, False);
end;
DelayMS(1000);
// 初始化
// 同步 ewWaitUntilTerminated
// 异步 ewNoWait
// 初始化并启动 MySQL
// Cmd := '/C "' + ExpandConstant('{app}') + '\mysql\initialize-and-start-mysql.bat"';
Cmd := '/C " cd ' + ExpandConstant('{app}') + '\mysql && initialize.bat"';
if not Exec('cmd.exe', Cmd, '', SW_HIDE, ewNoWait, ResultCode) then
begin
MsgBox('初始化 MySQL 脚本失败', mbError, MB_OK);
end else begin
DelayMS(3000);
// DeleteFile(ExpandConstant('{app}\mysql\initialize-and-start-mysql.bat'));
DeleteFile(ExpandConstant('{app}\mysql\register-mysql-with-data.bat'));
// DeleteFile(ExpandConstant('{app}\mysql\initialize.bat'));
end;
DelayMS(1000);
end; // mysql auto.conf 初始化判定
end;
// 导入默认数据库到 MySQL
// procedure ImportDefaultDatabase2MySQL;
// var
// ResultCode: Integer;
// Cmd: string;
// MySQLPath: string;
// UsrPath: string;
// begin
//
// // 判断是否安装了 usr 基础环境
// if FileExists(ExpandConstant('{app}\usr\rar.exe')) then
// begin
//
// // 等待 MySQL 服务启动完成
// DelayMS(3000);
// // 这个时候 `环境变量` 还没开始注册,所以 bat 导入脚本不生效, 因此需要指定临时Path环境变量
// // 导出默认库和用户
// if FileExists(ExpandConstant('{app}\mysql\import-data-into-mysql.bat')) then
// begin
//
// // 临时设置 PATH 并执行脚本
// MySQLPath := ExpandConstant('{app}') + '\mysql\bin';
// UsrPath := ExpandConstant('{app}') + '\usr';
// Cmd := '/C "set PATH=' + MySQLPath + '; ' + UsrPath + ';%PATH%' +
// ' && cd ' + ExpandConstant('{app}') + '\mysql' +
// ' && import-data-into-mysql.bat"' +
// ' && exit"';
//
// if not Exec('cmd.exe', Cmd, '', SW_HIDE, ewNoWait, ResultCode) then
// begin
// MsgBox('初始化默认库脚本失败', mbError, MB_OK);
// end;
// DelayMS(1000);
// end;
// end; // 是否安装了 usr 环境
//
// end;
2025-08-15 15:37:52 +08:00
// 在安装前检查
function InitializeSetup: Boolean;
begin
// 默认允许安装继续
Result := True;
2025-08-26 13:15:18 +08:00
2025-08-15 15:37:52 +08:00
// 如果 VC++ 2019 未安装
if not IsVC2019Installed then
begin
MsgBox('本程序需要 Microsoft Visual C++ 2019 运行时才能继续( 1001) ', mbError, MB_OK)
// 中止安装
Result := False;
end;
2025-08-26 13:15:18 +08:00
2025-08-15 15:37:52 +08:00
end;
2025-08-15 11:47:44 +08:00
// 在安装完成后执行
procedure CurStepChanged(CurStep: TSetupStep);
2025-08-17 12:37:05 +08:00
begin
2025-08-26 13:15:18 +08:00
2025-08-17 12:37:05 +08:00
// 仅在安装完成后执行
2025-08-15 11:47:44 +08:00
if CurStep = ssPostInstall then
begin
2025-08-26 16:15:34 +08:00
// 创建配置文件
CreateConfigFromTemplate;
2025-08-19 18:15:31 +08:00
2025-08-26 16:15:34 +08:00
// 删除过程文件
RemoveTempFile;
2025-08-26 13:15:18 +08:00
2025-08-26 16:15:34 +08:00
// 初始化并启动 MySQL
InitializeAndStartMySQL;
2025-08-26 13:15:18 +08:00
2025-08-26 16:15:34 +08:00
// 导入默认数据库到 MySQL
// ImportDefaultDatabase2MySQL;
2025-08-26 13:15:18 +08:00
end; // 安装完成后的执行
2025-08-15 11:47:44 +08:00
end;
// 卸载前先停止程序运行
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
2025-08-26 13:15:18 +08:00
var
hSCManager, hService: Longword;
ServiceStatus: Longword;
ResultCode: Integer;
DataDir: string;
2025-08-15 11:47:44 +08:00
begin
if CurUninstallStep = usUninstall then begin
// 在这里执行你的脚本或程序
// Exec(ExpandConstant('{cmd}'), '/C "uninstall_script.bat"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
2025-08-26 13:15:18 +08:00
2025-08-15 11:47:44 +08:00
end;
end;
[UninstallRun]
;; 卸载前运行
Filename: "sc"; Parameters: "stop redis"; Flags: runascurrentuser runhidden waituntilterminated
Filename: "sc"; Parameters: "delete redis"; Flags: runascurrentuser runhidden waituntilterminated
Filename: "sc"; Parameters: "stop x_database"; Flags: runascurrentuser runhidden waituntilterminated
Filename: "sc"; Parameters: "delete x_database"; Flags: runascurrentuser runhidden waituntilterminated
2025-08-26 13:15:18 +08:00
Filename: "taskkill"; Parameters: "-f -im home-web.exe"; Flags: runascurrentuser runhidden waituntilterminated
2025-08-15 11:47:44 +08:00
;; 卸载时删除的文件
[UninstallDelete]
2025-08-26 13:15:18 +08:00
; 删除 mysql 相关内容( 停止服务可能需要一定时间, 因此删除mysql时可能存在占用问题导致删除失败, 需要转到 code 实现)
2025-08-15 11:47:44 +08:00
Type: files; Name: "{app}\mysql\my.ini"
Type: files; Name: "{app}\mysql\*.bat"
Type: filesandordirs; Name: "{app}\mysql\data"
2025-08-26 13:15:18 +08:00
Type: filesandordirs; Name: "{app}\mysql\lib"
Type: filesandordirs; Name: "{app}\mysql\bin"
; 删除 minio 数据
Type: filesandordirs; Name: "{app}\io"
2025-08-19 18:15:31 +08:00
Type: filesandordirs; Name: "{app}\io\data"
2025-08-26 13:15:18 +08:00
; 删除 nginx log
Type: filesandordirs; Name: "{app}\nginx\logs"
; 删除 rocketmq 数据
Type: filesandordirs; Name: "{app}\rocketmq\sbin\store"