Inno Setup torrent下载实施 [英] Inno Setup torrent download implementation
问题描述
我当前正在使用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屋!