Inno Setup torrent下载实施 [英] Inno Setup torrent download implementation

查看:109
本文介绍了Inno Setup torrent下载实施的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我当前正在使用Inno Download Plugin为我的安装程序下载文件,最大的问题是无法正确下载文件.由于许多原因,例如连接不良.我想添加一种下载文件的替代方法,因此用户可以选择常规方式还是洪流方式.我知道我可以使用aria2c.exe应用程序( https://aria2.github.io/),有人可以帮助我将其实现为inno setup代码吗?

I am currently using Inno Download Plugin to download files for my installer, the biggest problem with this is that it faila to download the file correctly. Because of many reasons like bad connection. I would like to add an alternative method to download files, so the user may chose if he want regular way, or a torrent way. I know that I can use aria2c.exe app (https://aria2.github.io/), can someone help me with implementing it to the code of inno setup?

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

What I need is to download a 7z file using torrent (aria2.exe) and then unpack the contents to defined folder in {{app}} location.

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

Good code example is probably all I need.

推荐答案

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

Just run the aria2c, redirect its output to a file and poll the file contents for progress of the download.

实际上,这个答案与我的解决方案非常相似:
Inno Setup-使Inno Setup Installer向主安装程序报告其安装进度状态

It's actually very similar to my solution for this answer:
Inno Setup - 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设置6.如果您对Inno Setup 5感到困惑,可以使用 InnoTools中的WrapCallback函数InnoCallback 库.

For CreateCallback function, you need Inno Setup 6. If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library.

BufferToAnsi及其使用基于:
在另一个进程中打开文件时,Inno Setup LoadStringFromFile失败

The BufferToAnsi and its use is based on:
Inno Setup LoadStringFromFile fails when file is open in another process

这篇关于Inno Setup torrent下载实施的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆