首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使Inno安装安装程序将其安装进度状态报告给主安装程序

使Inno安装安装程序将其安装进度状态报告给主安装程序
EN

Stack Overflow用户
提问于 2016-12-03 11:52:00
回答 1查看 2.2K关注 0票数 2

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

我需要这个显示进度条在我的主要安装程序根据子安装程序的安装进度,因为我不想要任何无限(大块)进度条。

我还读到了关于Delphi中的IPC机制的文章。如何向Inno安装程序源代码添加像水泵这样的通信功能?开始有什么建议吗?

提前谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-12-03 17:05:34

我不认为你需要为这个编码花哨的IPC东西。只需通过一个临时文件交换信息。

子安装程序代码:

代码语言:javascript
运行
复制
[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;

主安装程序代码:

代码语言:javascript
运行
复制
#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,也可以在安装程序进程的任何其他地方使用:

代码语言:javascript
运行
复制
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;

另一个好的解决方案是使用事件函数。有关示例,请参见我对Inno安装程序急流下载实现的回答。

对于,您需要Inno安装程序6。如果您使用Inno安装程序5,可以使用http://www.sherlocksoftware.org/page.php?id=54库中的WrapCallback函数。

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

当文件在另一个进程中打开时,LoadStringFromFile失败

这显示了如何链接子安装程序和主安装程序(如果子安装程序不是与/verysilent开关一起运行,而是仅与/silent一起运行):

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

代码语言:javascript
运行
复制
#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;
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40947436

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档