download multiple files lazarus / 21-General ---------------------------------------------------------------------- Ericktux · 2022-09-25 18:17 hello brothers good day, I am using the project of the friend "getmem" of the following link: https://forum.lazarus.freepascal.org/index.php/topic,52773.0.html it works perfect, download all files at once, but i have 2 questions: 1. how to detect when each download is finished and show in the virtualtreeview 2. how to download one at a time, then the next one and show it in the virtualtreeview Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  uDownload,  //opensslsockets,  Dialogs, StdCtrls,  VirtualTrees; type  PData = ^TData;  TData = record    FUrl: String;    FName: String;    FState: String;  end;    { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    VST: TVirtualStringTree;    procedure Button1Click(Sender: TObject);    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);    procedure FormCreate(Sender: TObject);    procedure VSTGetNodeDataSize(Sender: TBaseVirtualTree;      var NodeDataSize: Integer);    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;      Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);  private    FDownload: TDownload;    procedure DoOnDownloadProgress(Sender: TObject; {%H-}AFrom, ATo: String; APos, ASize, AElapsed, ARemaining, ASpeed: LongInt);    procedure DoOnDownloadCompleted(Sender: TObject);  public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var  Data: Pdata;  Node: PVirtualNode;begin  VST.Clear;  VST.NodeDataSize := SizeOf(TData);   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://d.winrar.es/d/103z1663045159/zqnGYe1hSuxmWneHCTGQ9Q/winrar -x64-611es.exe';  Data^.FName := 'winrar.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://download.mozilla.org/?product=firefox- latest&os=win64&lang=es-MX';  Data^.FName := 'firefox.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://ardownload2.adobe.com/p ub/adobe/acrobat/win/AcrobatDC/2200220191/AcroRdrDCx642200220191_MUI.e xe';  Data^.FName := 'adobe_reader.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := ' https://mirror.netcologne.de/videolan.org/vlc/3.0.17.4/win64/vlc- 3.0.17.4-win64.exe';  Data^.FName := 'vlc.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://www.avast.com/es-ww/download-thank-you.php?product=FAV- AVAST&locale=es-ww&direct=1';  Data^.FName := 'avast.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://mirrors.ucr.ac.cr/tdf/l ibreoffice/stable/7.4.1/win/x86_64/LibreOffice_7.4.1_Win_x64.msi';  Data^.FName := 'libre_office.msi';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://data-cdn.mbamupdates.com/web/mb4-setup- consumer/offline/mb4-setup- consumer-4.5.14.210-1.0.1751-1.0.59171.exe';  Data^.FName := 'malwarebytes.exe';  Data^.FState := '';   FDownload := nil;end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);begin    if Assigned(FDownload) then    FDownload.CancelDownoad;end; procedure TForm1.Button1Click(Sender: TObject);var   node : PVirtualNode ;   Data: PData;begin  // ShowMessage(ExtractFilePath(Application.ExeName));  node := VST.GetFirst ;  while assigned (node) do      begin      Data := VST.GetNodeData(Node);       {      ShowMessage(Data^.FUrl);      ShowMessage(Data^.FName);      ShowMessage(Data^.FState);      }     Data^.FState:='downloading';      FDownload := TDownload.Create;      FDownload.OnDownloadProgress := @DoOnDownloadProgress;      FDownload.OnDownloadCompleted := @DoOnDownloadCompleted;      FDownload.DownloadFile(Data^.FUrl, ExtractFilePath(Application.ExeName)+Data^.FName);        node := VST.GetNext(node) ;      end;      vst.setfocus;      vst.Refresh;end; procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree;  var NodeDataSize: Integer);begin  NodeDataSize := SizeOf(TData);end; procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;  Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);var  Data: PData;begin  // si no existen estos codes, el resultado sera el texto    "NODE"  Data := VST.GetNodeData(Node);  case Column of    0: CellText := Data^.FUrl;  1: CellText := Data^.FName;    2: CellText := Data^.FState;  end;End; procedure TForm1.DoOnDownloadProgress(Sender: TObject; AFrom, ATo: String;  APos, ASize, AElapsed, ARemaining, ASpeed: LongInt);begin end; procedure TForm1.DoOnDownloadCompleted(Sender: TObject);begin     ShowMessage('Download completed!');end; end. PD: I am using lazarus + virtualtreeview on win10x64 attached project example and image DLL SSL 32 bit: https://packages.lazarus- ide.org/openssl-1.0.2j-i386-win32.zip DLL SSL 64 bit: https://packages.lazarus- ide.org/openssl-1.0.2j-x64_86-win64.zip ---------------------------------------------------------------------- paweld · 2022-09-25 19:00 Something like this - in the FDownload class add the OriginalURL property (without fix the protocol), and in OnProgress and OnCopleted we only update the node for the compatible URL ---------------------------------------------------------------------- Ericktux · 2022-09-25 19:30 hello friend thanks for answering, I have tried it and in the first click of the button it downloads only the first one, but if I give it a second click it downloads all ---------------------------------------------------------------------- paweld · 2022-09-25 22:28 Try changing the line Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Data^.FState := Format('downloading (%f %%)', [APos * 100 / ASize]); to:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Data^.FState := Format('downloading (%d bytes)', [APos]);I didn't add checking if the size is different from 0 ---------------------------------------------------------------------- Ericktux · 2022-09-25 23:19 hello friend, now it works thanks.  One question, to be able to use the percentage "%" of the download, the variable "ASize" is used, which is the total file size, but it only appears for the first download? is there a way to get the "ASize" value for all downloads?? Thanks for your time. ---------------------------------------------------------------------- Ericktux · 2022-09-26 04:54 I found a solution for now  , I had to modify the file "udownload.pas" adding the unit "openssl" and below the code "InitSSLInterface;" At the beginning of "procedure TDownload.Execute" I share the project. ---------------------------------------------------------------------- Ericktux · 2024-02-05 14:34 Hello friends, a question, following the same code how can I cancel several downloads ---------------------------------------------------------------------- Zvoni · 2024-02-05 14:52 Quote from: Ericktux on February 05, 2024, 03:34:00 pmHello friends, a question, following the same code how can I cancel several downloads  You do realize that "TDownload" has a "CancelDownload" Method, as you wrote in your first Post in Line 112, incl. a Typo there? And FWIW: That code must be leaking.... i see TDownload.Create, but nowhere a FDownload.Free; which, at the latest, i would expect in OnDownloadComplete ---------------------------------------------------------------------- Ericktux · 2024-02-06 13:46 Hello friends, thanks for the advice, here I still have the error, I cannot cancel the selected downloads  , I share the project and code with you Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  uDownload,  //opensslsockets,  Dialogs,  StdCtrls, Menus,  VirtualTrees; type  PData = ^TData;   TData = record    FUrl: String;    FName: String;    FState: String;  end;    { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    MenuItem1: TMenuItem;    MenuItem2: TMenuItem;    PopupMenu1: TPopupMenu;    VST: TVirtualStringTree;    procedure Button1Click(Sender: TObject);    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);    procedure FormCreate(Sender: TObject);    procedure MenuItem1Click(Sender: TObject);    procedure PopupMenu1Popup(Sender: TObject);    procedure VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);  private    FDownload: TDownload;    procedure DoOnDownloadProgress(Sender: TObject; {%H-}AFrom, ATo: String; APos, ASize, AElapsed, ARemaining, ASpeed: Longint);    procedure DoOnDownloadCompleted(Sender: TObject);    function GetSelectedNodeData3(var AData: PData): Boolean;  public   end; var  Form1: TForm1;  nro_descargas_total, nro_descarga_actual: integer; implementation {$R *.lfm} { TForm1 } function TForm1.GetSelectedNodeData3(var AData: PData): Boolean;Var  Node: PVirtualNode;begin  Node := VST.GetFirstSelected;  while assigned (node) do        begin        if Node <> nil then              begin              AData := VST.GetNodeData(Node);                 if TDownload(self).OriginalURL = aData^.FUrl then                begin              FDownload.CancelDownoad;   // trying to cancel download              aData^.FState := 'cancelled';                end;               Result := True;              end                  else                      begin                          MessageDlg('Please select a node first!', mtInformation, [mbOk], 0);                          Result := False;                        end;        node := VST.GetNextSelected(node) ;        End;   vst.Refresh;  vst.Repaint;End; procedure TForm1.FormCreate(Sender: TObject);var  Data: Pdata;  Node: PVirtualNode;begin  {nro_descargas_total:=0;  nro_descarga_actual:=0;}   VST.Clear;  VST.NodeDataSize := SizeOf(TData);   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://videolan.ip- connect.info/vlc/3.0.20/win64/vlc-3.0.20-win64.exe';  Data^.FName := 'vlc.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://files2.codecguide.com/K-Lite_Codec_Pack_1805_Mega.exe';  Data^.FName := 'klite codec pack.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'htt ps://raw.githubusercontent.com/ericktux/software_terceros/main/cccp.ex e';  Data^.FName := 'Combined codec pack.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://www.aimp.ru/files/windows/builds/aimp_5.30.2533_w64.exe';  Data^.FName := 'aimp.exe';  Data^.FState := '';   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://download.winamp.com/winamp/winamp_latest_full.exe';  Data^.FName := 'winamp.exe';  Data^.FState := '';   FDownload := nil;end; procedure TForm1.MenuItem1Click(Sender: TObject);Var  Data: Pdata;  Node: PVirtualNode;begin  GetSelectedNodeData3(Data);End; procedure TForm1.PopupMenu1Popup(Sender: TObject);begin End; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);begin  if Assigned(FDownload) then    FDownload.CancelDownoad;end; procedure TForm1.Button1Click(Sender: TObject);var  node: PVirtualNode;  Data: PData;begin  // ShowMessage(ExtractFilePath(Application.ExeName));  nro_descargas_total:=0;  nro_descarga_actual:=0;   node := VST.GetFirst;  while assigned(node) do  begin    if Node <> nil then    begin    Data := VST.GetNodeData(Node);       {      ShowMessage(Data^.FUrl);      ShowMessage(Data^.FName);      ShowMessage(Data^.FState);      }     nro_descargas_total:=nro_descargas_total+1;    Data^.FState := 'downloading';    FDownload := TDownload.Create;    FDownload.OnDownloadProgress := @DoOnDownloadProgress;    FDownload.OnDownloadCompleted := @DoOnDownloadCompleted;    FDownload.DownloadFile(Data^.FUrl, ExtractFilePath(Application.ExeName) + Data^.FName);      end;    node := VST.GetNext(node);  end;  vst.SetFocus;  vst.Refresh;end; procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);begin  NodeDataSize := SizeOf(TData);end; procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);var  Data: PData;begin  // si no existen estos codes, el resultado sera el texto    "NODE"  Data := VST.GetNodeData(Node);  case Column of    0: CellText := Data^.FUrl;    1: CellText := Data^.FName;    2: CellText := Data^.FState;  end;end; procedure TForm1.DoOnDownloadProgress(Sender: TObject; AFrom, ATo: String; APos, ASize, AElapsed, ARemaining, ASpeed: Longint);var  node: PVirtualNode;  Data: PData;begin  node := VST.GetFirst;  while assigned(node) do  begin    Data := VST.GetNodeData(Node);     if TDownload(Sender).OriginalURL = Data^.FUrl then    begin     {  // trabaja bien    if ASize > 0 then    Data^.FState := 'Received: ' + '  ' + FormatSize(APos) + ' / ' + FormatSize(ASize)    else    Data^.FState := 'Received: ' + '  ' + FormatSize(APos) + ' / ' + 'Unknown';    }     if ASize > 0 then    begin    Data^.FState :='Downloading '+inttostr(Round((APos/ASize) * 100))+'%';    //vst.Refresh;    end;       //Data^.FState := Format('downloading (%f %%)', [APos * 100 / ASize]);  // original      vst.InvalidateNode(node);      //vst.Refresh;      break;    end    else      node := VST.GetNext(node);  end;end; procedure TForm1.DoOnDownloadCompleted(Sender: TObject);var  node: PVirtualNode;  Data: PData;begin  node := VST.GetFirst;  while assigned(node) do  begin    Data := VST.GetNodeData(Node);     if TDownload(Sender).OriginalURL = Data^.FUrl then    begin    nro_descarga_actual:=nro_descarga_actual+1;      Data^.FState := 'finalized';      vst.InvalidateNode(node);      //vst.Refresh;      break;    end    else      node := VST.GetNext(node);  end;  if nro_descarga_actual=nro_descargas_total then ShowMessage('ALL DOWNLOADS COMPLETED');end;end. DLL SSL 64 bit: https://packages.lazarus- ide.org/openssl-1.0.2j-x64_86-win64.zip ---------------------------------------------------------------------- Zvoni · 2024-02-06 14:32 Seriously? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i FDownload.CancelDownoad;   // trying to cancel download Is your code even entering MenuItem1Click-Routine (and subsequently the GetSelectedNodeData3-Routine)? ---------------------------------------------------------------------- Ericktux · 2024-02-06 17:02 Yes friend indeed, can you help me?? ---------------------------------------------------------------------- rvk · 2024-02-06 18:29 You have just one FDownload: TDownload You use that same variable to initiate multiple downloads. Only the last download is kept in FDownload. After that you do FDownload.CanelDownoad (which has a type but that isn't the problem). So only your last download will be cancelled. If you want the other downloads to cancel you need to save the FDownload instance of all downloads or save it in the node and use that instance to cancel. ---------------------------------------------------------------------- Ericktux · 2024-02-06 19:28 I understand friend, I will do some tests and let you know how it goes. ---------------------------------------------------------------------- rvk · 2024-02-06 19:32 If you didn't find it yet... You can save the FDownload instance in the Data^ which you connect to the node. (In line 180/181) In the right click of the node you can use that instance to cancel. I didn't look at TDownload itself but if it's not self freeing you also need to free those instances. ---------------------------------------------------------------------- Ericktux · 2024-02-07 14:38 Hello friend, good morning, you are right "Download.Cancel Download" only applies to the last download. Please how can I save an instance of "FDownload" an example ---------------------------------------------------------------------- Zvoni · 2024-02-07 14:45 Quote from: Ericktux on February 07, 2024, 03:38:41 pmHello friend, good morning, you are right "Download.Cancel Download" only applies to the last download. Please how can I save an instance of "FDownload" an example  Make it a Member of your TData-Record instead of a Property of your Form ---------------------------------------------------------------------- rvk · 2024-02-07 15:03 Quote from: Ericktux on February 07, 2024, 03:38:41 pmHello friend, good morning, you are right "Download.Cancel Download" only applies to the last download. Please how can I save an instance of "FDownload" an example  As said here Quote from: rvk on February 06, 2024, 08:32:37 pmIf you didn't find it yet... You can save the FDownload instance in the Data^ which you connect to the node. (In line 180/181) In the right click of the node you can use that instance to cancel. I didn't look at TDownload itself but if it's not self freeing you also need to free those instances. ---------------------------------------------------------------------- Ericktux · 2024-02-07 16:05 I have tried to use a flag to cancel downloads in the "DoOnDownloadProgress" event Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.DoOnDownloadProgress(Sender: TObject; AFrom, ATo: String; APos, ASize, AElapsed, ARemaining, ASpeed: Longint);var  node: PVirtualNode;  Data: PData;begin  node := VST.GetFirst;  while assigned(node) do  begin    Data := VST.GetNodeData(Node);    if TDownload(Sender).OriginalURL = Data^.FUrl then    begin     if Data^.FFlag1 = '1' then    begin    if ASize > 0 then    begin    Data^.FState :='Downloading '+inttostr(Round((APos/ASize) * 100))+'%';    //vst.Refresh;    end;     end    else        if Data^.FFlag1 = '0' then        begin             FDownload.CancelDownoad;             //FDownload.Free;             Data^.FState := 'cancelled';             //ShowMessage(Data^.FName+ ' bb');        end;     vst.InvalidateNode(node);      //vst.Refresh;    break;    end    else      node := VST.GetNext(node);  end;end; but it keeps canceling only the last download ---------------------------------------------------------------------- rvk · 2024-02-07 16:21 Quote from: Ericktux on February 07, 2024, 05:05:58 pmI have tried to use a flag to cancel downloads in the "DoOnDownloadProgress" event I still see the global FDownload variable there. Remove it. Period. I said you needed to change line 180/181 to put the result of TDownload.Create into the Data^. Did you do that? I also see TDownload(Sender).OriginalURL = Data^.FUrl But if you have put the TDownload in Data^ you don't even need to do that. So first start to do this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TData = record    FDownload: TDownload;    FUrl: String;    FName: String;    FState: String;  end;Then... change lines from 180: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     Data^.FState := 'downloading';    Data^.FDownload := TDownload.Create;    Data^.FDownload.OnDownloadProgress := @DoOnDownloadProgress;    Data^.FDownload.OnDownloadCompleted := @DoOnDownloadCompleted;    Data^.FDownload.DownloadFile(Data^.FUrl, ExtractFilePath(Application.ExeName) + Data^.FName);After that... you can redesign the DoOnDownloadProgress to just take Data^.FDownload. So you don't even need to check the FUrl anymore because FDowload is in Data^ and you have the right one directly. ---------------------------------------------------------------------- Ericktux · 2024-02-07 21:47 I'm going to try it and tell you ---------------------------------------------------------------------- Ericktux · 2024-02-08 12:05 Hello friends, I have made these small modifications and it works fine for now, thanks for your advice  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes,  SysUtils,  Forms,  Controls,  Graphics,  uDownload,  //opensslsockets,  Dialogs,  StdCtrls, Menus,  VirtualTrees; type  PData = ^TData;   TData = record    FDownload: TDownload;    FUrl: String;    FName: String;    FState: String;    FFlag1: String;  end;    { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    MenuItem1: TMenuItem;    MenuItem2: TMenuItem;    PopupMenu1: TPopupMenu;    VST: TVirtualStringTree;    procedure Button1Click(Sender: TObject);    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);    procedure FormCreate(Sender: TObject);    procedure MenuItem1Click(Sender: TObject);    procedure PopupMenu1Popup(Sender: TObject);    procedure VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);  private     procedure DoOnDownloadProgress(Sender: TObject; {%H-}AFrom, ATo: String; APos, ASize, AElapsed, ARemaining, ASpeed: Longint);    procedure DoOnDownloadCompleted(Sender: TObject);    function GetSelectedNodeData3(var AData: PData): Boolean;  public   end; var  Form1: TForm1;  nro_descargas_total, nro_descarga_actual: integer; implementation {$R *.lfm} { TForm1 } function TForm1.GetSelectedNodeData3(var AData: PData): Boolean;Var  Node: PVirtualNode;begin  Node := VST.GetFirstSelected;  while assigned (node) do        begin        if Node <> nil then              begin              AData := VST.GetNodeData(Node);                 //aData^.FState := 'cancelled';                aData^.FFlag1 := '0';              aData^.FState := 'cancelled';                {              if TDownload(self).OriginalURL = aData^.FUrl then                begin                FDownload.CancelDownoad;   // trying to cancel download                aData^.FState := 'cancelled';                end;                }                 Result := True;              end                  else                        begin                        MessageDlg('Please select a node first!', mtInformation, [mbOk], 0);                          Result := False;                      end;        node := VST.GetNextSelected(node) ;        End;   vst.Refresh;  vst.Repaint;End; procedure TForm1.FormCreate(Sender: TObject);var  Data: Pdata;  Node: PVirtualNode;begin  {nro_descargas_total:=0;  nro_descarga_actual:=0;}   VST.Clear;  VST.NodeDataSize := SizeOf(TData);  Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://videolan.ip- connect.info/vlc/3.0.20/win64/vlc-3.0.20-win64.exe';  Data^.FName := 'vlc.exe';  Data^.FState := '';  Data^.FFlag1 := '1';  Data^.FDownload:= nil;   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://raw.githubusercontent.c om/ericktux/software_terceros/main/cccp.exe';  Data^.FName := 'Combined codec pack.exe';  Data^.FState := '';  Data^.FFlag1 := '1';  Data^.FDownload:= nil;   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://files2.codecguide.com/K-Lite_Codec_Pack_1805_Mega.exe';  Data^.FName := 'klite codec pack.exe';  Data^.FState := '';  Data^.FFlag1 := '1';  Data^.FDownload:= nil;   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://www.aimp.ru/files/windows/builds/aimp_5.30.2533_w64.exe';  Data^.FName := 'aimp.exe';  Data^.FState := '';  Data^.FFlag1 := '1';  Data^.FDownload:= nil;   Node := VST.AddChild(nil);  Data := VST.GetNodeData(Node);  Data^.FUrl := 'https://download.winamp.com/winamp/winamp_latest_full.exe';  Data^.FName := 'winamp.exe';  Data^.FState := '';  Data^.FFlag1 := '1';  Data^.FDownload:= nil;   //FDownload := nil;end; procedure TForm1.MenuItem1Click(Sender: TObject);Var  Data: Pdata;  Node: PVirtualNode;begin  GetSelectedNodeData3(Data);End; procedure TForm1.PopupMenu1Popup(Sender: TObject);begin End; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);var  node: PVirtualNode;  Data: PData;begin  {  if Assigned(Data^.FDownload) then    Data^.FDownload.CancelDownoad;  }   CanClose:=false;   node := VST.GetFirst;  while assigned(node) do  begin    if Node <> nil then      begin    Data := VST.GetNodeData(Node);       if Assigned(Data^.FDownload) then        Data^.FDownload.CancelDownoad;      end;    node := VST.GetNext(node);  end;   //ShowMessage('hh');  Sleep(2000); // le damos un poco de tiempo para que cierre bien, funciona  CanClose:=true; end;  procedure TForm1.Button1Click(Sender: TObject);var  node: PVirtualNode;  Data: PData;begin  // ShowMessage(ExtractFilePath(Application.ExeName));  nro_descargas_total:=0;  nro_descarga_actual:=0;   node := VST.GetFirst;  while assigned(node) do  begin    if Node <> nil then    begin    Data := VST.GetNodeData(Node);       {      ShowMessage(Data^.FUrl);      ShowMessage(Data^.FName);      ShowMessage(Data^.FState);      }     nro_descargas_total:=nro_descargas_total+1;    Data^.FState := 'downloading';    Data^.FDownload:= TDownload.Create;    Data^.FDownload.OnDownloadProgress := @DoOnDownloadProgress;    Data^.FDownload.OnDownloadCompleted := @DoOnDownloadCompleted;    Data^.FDownload.DownloadFile(Data^.FUrl, ExtractFilePath(Application.ExeName) + Data^.FName);      end;    node := VST.GetNext(node);  end;  vst.SetFocus;  vst.Refresh;end; procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);begin  NodeDataSize := SizeOf(TData);end; procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);var  Data: PData;begin  // si no existen estos codes, el resultado sera el texto    "NODE"  Data := VST.GetNodeData(Node);  case Column of    0: CellText := Data^.FUrl;    1: CellText := Data^.FName;    2: CellText := Data^.FState;    3: CellText := Data^.FFlag1;  end;end; procedure TForm1.DoOnDownloadProgress(Sender: TObject; AFrom, ATo: String; APos, ASize, AElapsed, ARemaining, ASpeed: Longint);var  node: PVirtualNode;  Data: PData;begin  node := VST.GetFirst;  while assigned(node) do  begin    Data := VST.GetNodeData(Node);    if TDownload(Sender).OriginalURL = Data^.FUrl then    begin     if Data^.FFlag1 = '1' then    begin    if ASize > 0 then    begin    Data^.FState :='Downloading '+inttostr(Round((APos/ASize) * 100))+'%';    //vst.Refresh;    end;     end    else        if Data^.FFlag1 = '0' then        begin           Data^.FDownload.CancelDownoad;             //FDownload.Free;           Data^.FState := 'cancelled';             //ShowMessage(Data^.FName+ ' bb');        end;     vst.InvalidateNode(node);      //vst.Refresh;      break;    end    else      node := VST.GetNext(node);  end;end; procedure TForm1.DoOnDownloadCompleted(Sender: TObject);var  node: PVirtualNode;  Data: PData;begin  node := VST.GetFirst;  while assigned(node) do  begin    Data := VST.GetNodeData(Node);     if TDownload(Sender).OriginalURL = Data^.FUrl then    begin    nro_descarga_actual:=nro_descarga_actual+1;      Data^.FState := 'finalized';      vst.InvalidateNode(node);      //vst.Refresh;      break;    end    else      node := VST.GetNext(node);  end;  if nro_descarga_actual=nro_descargas_total then ShowMessage('ALL DOWNLOADS COMPLETED');end;end. I will continue doing tests and I will tell you ---------------------------------------------------------------------- rvk · 2024-02-08 13:16 Quote from: Ericktux on February 08, 2024, 01:05:54 pmI will continue doing tests and I will tell you Don't forget to check the box in Project > Project Options > Compiler Options > Debugging > "Use heaptrc unit" It will tell you, when exiting your program, if there are any leaks. I suspect you have major leaks because you never free the TDownloads you create.