gpt4 book ai didi

installation - 让 Inno Setup Installer 向主安装程序报告其安装进度状态

转载 作者:行者123 更新时间:2023-12-04 04:49:15 30 4
gpt4 key购买 nike

我目前有两个 Inno Setup 安装程序在工作。我需要其中一个将其作为子安装程序的状态报告给另一个安装程序,即使它使用 VERYSILENT 命令运行。

我需要它根据子安装程序的安装进度在我的主安装程序中显示进度条,因为我不希望为此使用任何无限(选取框)进度条。

我还阅读了 IPC Mechanism in Delphi .我怎样才能将这种像泵这样的通信能力添加到 Inno Setup 源代码中?有什么入门技巧吗?

提前致谢。

最佳答案

我认为您不需要为此编写花哨的 IPC 代码。只需通过临时文件交换信息。

子安装程序代码:

[Code]

function SetTimer(
Wnd: LongWord; IDEvent, Elapse: LongWord; TimerFunc: LongWord): LongWord;
external 'SetTimer@user32.dll stdcall';

var
ProgressFileName: string;
PrevProgress: Integer;

procedure ReportProgressProc(
H: LongWord; Msg: LongWord; Event: LongWord; Time: LongWord);
var
Progress: Integer;
begin
try
Progress :=
(WizardForm.ProgressGauge.Position * 100) div WizardForm.ProgressGauge.Max;
if PrevProgress <> Progress then
begin
if not SaveStringToFile(ProgressFileName, IntToStr(Progress), False) then
begin
Log(Format('Failed to save progress %d', [Progress]));
end
else
begin
Log(Format('Saved progress %d', [Progress]));
PrevProgress := Progress;
end;
end;
except
Log('Exception saving progress');
end;
end;

procedure InitializeWizard();
begin
{ When run with /progress=<path> switch, will report progress to that file }
ProgressFileName := ExpandConstant('{param:progress}');
if ProgressFileName <> '' then
begin
Log(Format('Will write progress to: %s', [ProgressFileName]));
PrevProgress := -1;
SetTimer(0, 0, 250, CreateCallback(@ReportProgressProc));
end;
end;

主安装程序代码:

#define ChildInstaller "mysetup.exe"

[Files]
Source: {#ChildInstaller}; Flags: dontcopy

[Code]

function SetTimer(
Wnd: LongWord; IDEvent, Elapse: LongWord; TimerFunc: LongWord): LongWord;
external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: LongWord; uIDEvent: LongWord): BOOL;
external 'KillTimer@user32.dll stdcall';

var
ProgressPage: TOutputProgressWizardPage;
ProgressFileName: string;

procedure UpdateProgressProc(
H: LongWord; Msg: LongWord; Event: LongWord; Time: LongWord);
var
S: AnsiString;
Progress: Integer;
begin
try
if not LoadStringFromFile(ProgressFileName, S) then
begin
Log(Format('Failed to read progress from file %s', [ProgressFileName]));
end
else
begin
Progress := StrToIntDef(S, -1);
if (Progress < 0) or (Progress > 100) then
begin
Log(Format('Read invalid progress %s', [S]));
end
else
begin
Log(Format('Read progress %d', [Progress]));
ProgressPage.SetProgress(Progress, 100);
end;
end;
except
Log('Exception updating progress');
end;
end;

procedure InstallChild;
var
ChildInstallerPath: string;
ChildInstallerParams: string;
Timer: LongWord;
InstallError: string;
ResultCode: Integer;
begin
ExtractTemporaryFile('{#ChildInstaller}');

ProgressPage := CreateOutputProgressPage('Running child installer', '');
ProgressPage.SetProgress(0, 100);
ProgressPage.Show;
try
Timer := SetTimer(0, 0, 250, CreateCallback(@UpdateProgressProc));

ChildInstallerPath := ExpandConstant('{tmp}\{#ChildInstaller}');
ProgressFileName := ExpandConstant('{tmp}\progress.txt');
Log(Format('Expecting progress in %s', [ProgressFileName]));
ChildInstallerParams :=
Format('/verysilent /progress="%s"', [ProgressFileName]);
if not Exec(ChildInstallerPath, ChildInstallerParams, '', SW_SHOW,
ewWaitUntilTerminated, ResultCode) then
begin
InstallError := 'Cannot start child installer';
end
else
if ResultCode <> 0 then
begin
InstallError :=
Format('Child installer failed with code %d', [ResultCode]);
end;
finally
{ Clean up }
KillTimer(0, Timer);
ProgressPage.Hide;
DeleteFile(ProgressFileName);
end;

if InstallError <> '' then
begin
// RaiseException does not work properly,
// while TOutputProgressWizardPage is shown
RaiseException(InstallError);
end;
end;

您可以像下面那样使用 InstallChild,或者在安装程序进程的任何其他地方使用:

function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;

if CurPageID = wpReady then
begin
try
InstallChild;
except
MsgBox(GetExceptionMessage, mbError, MB_OK);
Result := False;
end;
end;
end;

另一个好的解决方案是使用 PrepareToInstall event function .例如,请参阅我对 Inno Setup torrent download implementation 的回答.


CreateCallback function ,您需要 Inno Setup 6。如果您坚持使用 Inno Setup 5,您可以使用 InnoTools InnoCallback 中的 WrapCallback 函数图书馆。


最好使用 TFileStream 而不是 LoadStringFromFileSaveStringToFileTFileStream 支持读取共享。使用 LoadStringFromFileSaveStringToFile,如果双方碰巧同时尝试读取和写入,进度报告可能偶尔会暂时失败。

参见 Inno Setup LoadStringFromFile fails when file is open in another process .


这显示了子安装程序和主安装程序的进度是如何关联的(如果子安装程序未使用 /verysilent 开关运行,而是仅使用 /silent 运行):

Linked progress


如果您需要使用独立的进度条,您可以使用以下主安装程序代码:

#define ChildInstaller "mysetup.exe"

[Files]
Source: {#ChildInstaller}; Flags: dontcopy

[Code]

function SetTimer(
Wnd: LongWord; IDEvent, Elapse: LongWord; TimerFunc: LongWord): LongWord;
external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: LongWord; uIDEvent: LongWord): BOOL;
external 'KillTimer@user32.dll stdcall';

var
ProgressFileName: string;

procedure UpdateProgressProc(
H: LongWord; Msg: LongWord; Event: LongWord; Time: LongWord);
var
S: AnsiString;
Progress: Integer;
begin
try
if not LoadStringFromFile(ProgressFileName, S) then
begin
Log(Format('Failed to read progress from file %s', [ProgressFileName]));
end
else
begin
Progress := StrToIntDef(S, -1);
if (Progress < 0) or (Progress > 100) then
begin
Log(Format('Read invalid progress %s', [S]));
end
else
begin
Log(Format('Read progress %d', [Progress]));
WizardForm.ProgressGauge.Position :=
Progress * WizardForm.ProgressGauge.Max div 100;
end;
end;
except
Log('Exception updating progress');
end;
end;

procedure InstallChild;
var
ChildInstallerPath: string;
ChildInstallerParams: string;
Timer: LongWord;
ResultCode: Integer;
begin
ExtractTemporaryFile('{#ChildInstaller}');

try
Timer := SetTimer(0, 0, 250, CreateCallback(@UpdateProgressProc));

ChildInstallerPath := ExpandConstant('{tmp}\{#ChildInstaller}');
ProgressFileName := ExpandConstant('{tmp}\progress.txt');
Log(Format('Expecting progress in %s', [ProgressFileName]));
ChildInstallerParams :=
Format('/verysilent /progress="%s"', [ProgressFileName]);
if not Exec(ChildInstallerPath, ChildInstallerParams, '', SW_SHOW,
ewWaitUntilTerminated, ResultCode) then
begin
MsgBox('Cannot start child installer', mbError, MB_OK);
end
else
if ResultCode <> 0 then
begin
MsgBox(Format(
'Child installer failed with code %d', [ResultCode]), mbError, MB_OK);
end;
finally
{ Clean up }
KillTimer(0, Timer);
DeleteFile(ProgressFileName);
end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
InstallChild;
end;
end;

关于installation - 让 Inno Setup Installer 向主安装程序报告其安装进度状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40947436/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com