我目前有两个Inno Setup安装程序正在解决。我需要其中一个将其作为子安装程序的状态报告给另一个安装程序,即使它使用eventDrop: function(event, delta, revertFunc) {
$(this).trigger('click');
},
eventClick: function(calEvent, jsEvent, view) {
console.log('event clicked');
}
命令运行。
我需要根据子安装程序的安装进度在我的主安装程序中显示进度条,因为我不想要任何无限(选取框)进度条。
我还读到了IPC Mechanism in Delphi。如何将此通信功能(如泵)添加到Inno Setup源代码中?任何启动提示?
提前致谢。
答案 0 :(得分:3)
我认为您不需要为此编写花哨的IPC内容。只需通过临时文件交换信息。
儿童安装程序代码:
[Files]
Source: InnoCallback.dll; Flags: dontcopy
[Code]
type
TTimerProc = procedure(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
function SetTimer(
Wnd: LongWord; IDEvent, Elapse: LongWord; TimerFunc: LongWord): LongWord;
external 'SetTimer@user32.dll stdcall';
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:innocallback.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, WrapTimerProc(@ReportProgressProc, 4));
end;
end;
主安装程序代码:
#define ChildInstaller "mysetup.exe"
[Files]
Source: {#ChildInstaller}; Flags: dontcopy
Source: InnoCallback.dll; Flags: dontcopy
[Code]
type
TTimerProc = procedure(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
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';
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:innocallback.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, WrapTimerProc(@UpdateProgressProc, 4));
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的回答。
代码正在使用InnoTools InnoCallback library来安排计时器。
最好使用TFileStream
代替LoadStringFromFile
和SaveStringToFile
。 TFileStream
支持读取共享。对于LoadStringFromFile
和SaveStringToFile
,如果双方碰巧同时尝试读写,则进度报告可能偶尔会暂时失败。
请参阅Inno Setup LoadStringFromFile fails when file is open in another process。
这显示了子安装程序和主安装程序进程的链接方式(如果子安装程序未使用/verysilent
开关运行,但仅使用/silent
):
如果您需要使用独立进度条,则可以使用以下主安装程序代码:
#define ChildInstaller "mysetup.exe"
[Files]
Source: {#ChildInstaller}; Flags: dontcopy
Source: InnoCallback.dll; Flags: dontcopy
[Code]
type
TTimerProc = procedure(H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
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';
function WrapTimerProc(Callback: TTimerProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:innocallback.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, WrapTimerProc(@UpdateProgressProc, 4));
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;