1

我目前正在使用 Inno Download Plugin 为我的安装程序下载文件,最大的问题是它无法正确下载文件。由于连接不良等多种原因。我想添加一种替代方法来下载文件,因此用户可以选择是常规方式还是洪流方式。我知道我可以使用aria2c.exeapp。有人可以帮我将它实现到 inno setup 的代码中吗?

我需要的是使用 torrent ( aria2.exe) 下载一个 7z 文件,然后将内容解压缩到指定{app}位置的文件夹中。

好的代码示例可能就是我所需要的。

4

1 回答 1

3

只需运行aria2c,将其输出重定向到文件并轮询文件内容以获取下载进度。

它实际上与我对此答案的解决方案非常相似:
Make Inno Setup Installer report its installation progress status to master installer


#define TorrentMagnet "magnet:..."

[Files]
Source: aria2c.exe; Flags: dontcopy

[Code]

function BufferToAnsi(const Buffer: string): AnsiString;
var
  W: Word;
  I: Integer;
begin
  SetLength(Result, Length(Buffer) * 2);
  for I := 1 to Length(Buffer) do
  begin
    W := Ord(Buffer[I]);
    Result[(I * 2)] := Chr(W shr 8); { high byte }
    Result[(I * 2) - 1] := Chr(Byte(W)); { low byte }
  end;
end;

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;
  I: Integer;
  L: Integer;
  P: Integer;
  Max: Integer;
  Progress: string;
  Buffer: string;
  Stream: TFileStream;
  Transferred: string;
  Percent: Integer;
  Found: Boolean;
begin
  Found := False;
  try
    { Need shared read as the output file is locked for writting, }
    { so we cannot use LoadStringFromFile }
    Stream := TFileStream.Create(ProgressFileName, fmOpenRead or fmShareDenyNone);
    try
      L := Stream.Size;
      Max := 100*2014;
      if L > Max then
      begin
        Stream.Position := L - Max;
        L := Max;
      end;
      SetLength(Buffer, (L div 2) + (L mod 2));
      Stream.ReadBuffer(Buffer, L);
      S := BufferToAnsi(Buffer);
    finally
      Stream.Free;
    end;
    
    if S = '' then
    begin
      Log(Format('Progress file %s is empty', [ProgressFileName]));
    end;
  except
    Log(Format('Failed to read progress from file %s', [ProgressFileName]));
  end;

  if S <> '' then
  begin
    P := Pos('[#', S);
    if P = 0 then
    begin
      Log('Not found any progress line');
    end
      else
    begin
      repeat
        Delete(S, 1, P - 1);
        P := Pos(']', S);
        Progress := Copy(S, 2, P - 2);
        Delete(S, 1, P);
        P := Pos('[#', S);
      until (P = 0);
      
      Log(Format('Found progress line: %s', [Progress]));
      P := Pos(' ', Progress);
      if P > 0 then
      begin
        Log('A');
        Delete(Progress, 1, P);
        P := Pos('(', Progress);
        if P > 0 then
        begin
          Log('b');
          Transferred := Copy(Progress, 1, P - 1);
          Delete(Progress, 1, P);
          P := Pos('%)', Progress);
          if P > 0 then
          begin
            Log('c');
            Percent := StrToIntDef(Copy(Progress, 1, P - 1), -1);
            if Percent >= 0 then
            begin
              Log(Format('Transferred: %s, Percent: %d', [Transferred, Percent]));
              ProgressPage.SetProgress(Percent, 100);
              ProgressPage.SetText(Format('Transferred: %s', [Transferred]), '');
              Found := True;
            end;
          end;      
        end;
      end;
    end;
  end;
  
  if not Found then
  begin
    Log('No new data found');
    { no new progress data, at least pump the message queue }
    ProgressPage.SetProgress(ProgressPage.ProgressBar.Position, 100);
  end;
end;

function PrepareToInstall(var NeedsRestart: Boolean): String;
var
  TorrentDownloaderPath: string;
  TempPath: string;
  CommandLine: string;
  Timer: LongWord;
  InstallError: string;
  ResultCode: Integer;
  S: AnsiString;
begin
  ExtractTemporaryFile('aria2c.exe');

  ProgressPage :=
    CreateOutputProgressPage('Torrent download', 'Downloading torrent...');
  ProgressPage.SetProgress(0, 100);
  ProgressPage.Show;
  try
    Timer := SetTimer(0, 0, 250, CreateCallback(@UpdateProgressProc));

    TempPath := ExpandConstant('{tmp}');
    TorrentDownloaderPath := TempPath + '\aria2c.exe';
    ProgressFileName := ExpandConstant('{tmp}\progress.txt');
    Log(Format('Expecting progress in %s', [ProgressFileName]));
    CommandLine :=
      Format('"%s" "%s" > "%s"', [
        TorrentDownloaderPath, '{#TorrentMagnet}', ProgressFileName]);
    Log(Format('Executing: %s', [CommandLine]));
    CommandLine := Format('/C "%s"', [CommandLine]);
    if not Exec(ExpandConstant('{cmd}'), CommandLine, TempPath, SW_HIDE,
                ewWaitUntilTerminated, ResultCode) then
    begin
      Result := 'Cannot start torrent download';
    end
      else
    if ResultCode <> 0 then
    begin
      LoadStringFromFile(ProgressFileName, S);
      Result := Format('Torrent download failed with code %d', [ResultCode]);
      Log(Result);
      Log('Output: ' + S);
    end;
  finally
    { Clean up }
    KillTimer(0, Timer);
    ProgressPage.Hide;
    DeleteFile(ProgressFileName);
  end;
end;

对于CreateCallback函数,您需要 Inno Setup 6。如果您被 Inno Setup 5 卡住,您可以使用InnoTools InnoCallback库中WrapCallback的函数。


及其使用BufferToAnsi基于:
Inno Setup LoadStringFromFile failed when file is open in another process


Torrent 下载进度

于 2017-02-05T18:24:57.747 回答