Inno Setup - 如何添加取消按钮来解压缩页面?

时间:2017-03-21 11:23:13

标签: inno-setup compression

我正在使用此代码:How to add .arc decompression to Inno Setup?(Martin Prikryl的回答)。我想在解压缩页面添加一个取消按钮,并为其他功能激活此页面(当解压缩处于活动状态时,此页面处于非活动状态,例如,我无法按下音乐实现的开/关按钮。)

如何在解压缩页面添加取消按钮?以及如何将此页面用于其他功能?

2 个答案:

答案 0 :(得分:1)

我使用unarc.dll(来自FreeArc + InnoSetup包ISFreeArcExtract v.4.0.rar)重新实现了How to add .arc decompression to Inno Setup?的解决方案。

它极大地简化了代码,并且更容易添加取消解压缩的功能。

#define ArcArchive "test.arc"

[Files]
Source: unarc.dll; Flags: dontcopy
Source: InnoCallback.dll; Flags: dontcopy

[Code]

type
  TFreeArcCallback =
    function(What: PAnsiChar; Int1, Int2: Integer; Str: PAnsiChar): Integer;

function WrapFreeArcCallback(Callback: TFreeArcCallback; ParamCount: Integer): LongWord;
  external 'wrapcallback@files:innocallback.dll stdcall';

const
  ArcCancelCode = -10;

function FreeArcExtract(
  Callback: LongWord;
  Cmd1, Cmd2, Cmd3, Cmd4, Cmd5, Cmd6, Cmd7, Cmd8, Cmd9, Cmd10: PAnsiChar): Integer;
  external 'FreeArcExtract@files:unarc.dll cdecl';

const
  CP_UTF8 = 65001;

function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD;
  lpWideCharStr: string; cchWideChar: Integer; lpMultiByteStr: AnsiString;
  cchMultiByte: Integer; lpDefaultCharFake: Integer;
  lpUsedDefaultCharFake: Integer): Integer;
  external 'WideCharToMultiByte@kernel32.dll stdcall';

function GetStringAsUtf8(S: string): AnsiString;
var
  Len: Integer;
begin
  Len := WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, 0, 0, 0);
  SetLength(Result, Len);
  WideCharToMultiByte(CP_UTF8, 0, S, Length(S), Result, Len, 0, 0);
end;

var
  ArcTotalSize: Integer;
  ArcCancel: Boolean;
  ArcProgressPage: TOutputProgressWizardPage;

function FreeArcCallback(AWhat: PAnsiChar; Int1, Int2: Integer; Str: PAnsiChar): Integer;
var
  What: string;
begin
  What := AWhat;
  if What = 'origsize' then
  begin
    ArcTotalSize := Int1;
    Log(Format('Total size of files to be extracted is %d MB', [ArcTotalSize]));
  end
    else
  if What = 'write' then
  begin
    if ArcTotalSize > 0 then
    begin
      ArcProgressPage.SetProgress(Int1, ArcTotalSize);
    end;
  end
    else
  begin
    { Just to pump message queue more often (particularly for 'read' callbacks), }
    { to get more smooth progress bar }
    if (ArcExtracted > 0) and (ArcTotalSize > 0) then
    begin
      ArcProgressPage.SetProgress(ArcTotalExtracted + ArcExtracted, ArcTotalSize);
    end;
  end;

  if ArcCancel then Result := ArcCancelCode
    else Result := 0;
end;

function FreeArcCmd(
  Cmd1, Cmd2, Cmd3, Cmd4, Cmd5, Cmd6, Cmd7, Cmd8, Cmd9, Cmd10: string): Integer;
begin
  ArcCancel := False;
  try
    Result :=
      FreeArcExtract(
        WrapFreeArcCallback(@FreeArcCallback, 4),
        GetStringAsUtf8(Cmd1), GetStringAsUtf8(Cmd2), GetStringAsUtf8(Cmd3),
        GetStringAsUtf8(Cmd4), GetStringAsUtf8(Cmd5), GetStringAsUtf8(Cmd6),
        GetStringAsUtf8(Cmd7), GetStringAsUtf8(Cmd8), GetStringAsUtf8(Cmd9),
        GetStringAsUtf8(Cmd10));

    Log(Format('Arc command "%s" result %d', [Cmd1, Result]));
  except
    Result := -63;
  end;
end;

function UnPackArchive(ArchivePath: string; DestPath: string): Integer;
begin
  { Find out length of files to be extracted - origsize }
  Result := FreeArcCmd('l', '--', ArchivePath, '', '', '', '', '', '', '');

  if Result = 0 then
  begin
    { Actually extract }
    Result :=
      FreeArcCmd('x', '-o+', '-dp' + DestPath, '-w' + DestPath, '--', ArchivePath,
                 '', '', '', '');
  end;
end;

procedure UnpackCancelButtonClick(Sender: TObject);
begin
  ArcCancel := True;
end;

procedure ExtractArc;
var
  ArcArchivePath: string;
  UnpackResult: Integer;
  PrevCancelButtonClick: TNotifyEvent;
  Error: string;
begin
  ArcProgressPage := CreateOutputProgressPage('Decompression', 'Decompressing archive...');
  ArcProgressPage.SetProgress(0, 100);
  ArcProgressPage.Show;
  try
    WizardForm.CancelButton.Visible := True;
    WizardForm.CancelButton.Enabled := True;
    PrevCancelButtonClick := WizardForm.CancelButton.OnClick;
    WizardForm.CancelButton.OnClick := @UnpackCancelButtonClick;

    ArcArchivePath := ExpandConstant('{src}\{#ArcArchive}');
    Log(Format('Arc extraction starting - %s', [ArcArchivePath]));

    UnpackResult := UnPackArchive(ArcArchivePath, ExpandConstant('{app}'));

    if UnpackResult <> 0 then
    begin
      if ArcCancel then
      begin
        Error := 'Extraction cancelled';
      end
        else
      begin
        Error := Format('Extraction failed with code %d', [UnpackResult]);
      end;

      MsgBox(Error, mbError, MB_OK);
    end;
  finally
    Log('Arc extraction cleanup');
    ArcProgressPage.Hide;
    WizardForm.CancelButton.OnClick := PrevCancelButtonClick;
  end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep = ssPostInstall then
  begin
    ExtractArc;
  end;
end;

代码使用InnoTools InnoCallback库并需要Unicode Inno Setup。

Extraction cancelled

代码提取单独的.arc文件。如果要将存档嵌入安装程序,可以使用

[Files]
Source: {#ArcArchive}; DestDir: "{tmp}"; Flags: nocompression deleteafterinstall

{tmp}

中提取档案
ArcArchivePath := ExpandConstant('{tmp}\{#ArcArchive}');

请注意,unarc.dll中的ISFreeArcExtract v.4.0.rar似乎不支持受密码保护的存档。来自ISFreeArcExtract v.4.2.rar的版本可以,但我不知道值得信赖的下载链接。

如果要提取多个档案,请参阅Inno Setup - How to add multiple arc files to decompress?

答案 1 :(得分:0)

你需要的只是这个 http://fileforums.com/showthread.php?t=96619

此程序具有与inno设置的最新兼容性,并且还支持具有多个扩展名的基于密码的文件。