Newsgroup: it.comp.lang.delphi
Titolo: Download via http con Delphi

Qualcuno ha idea di come si fa il download di un file via http (non ftp) 
con Delphi?
Magari usando le Indy?
Io ho trovato sul web un riferimento a TDownloadURL, e mi sono fatto la 
mia classe in un thread a parte (Di seguito posto il codice).
Il problema ï¿œ che nonostante sia in un thread a se stante, tutto funzia 
ma tiene bloccato il thread principale finchï¿œ non ha finito.
Accetto suggerimenti
Roberto
unit HTTPDownload;
interface
uses
   SysUtils, Classes, ExtActns;
type
   TStopState = (ssOK, ssAbort, ssError);
   TOnStop = procedure (const StopState: TStopState; const ErrMsg: 
String) of object;
   TOnStep = procedure (const Progress: Cardinal) of object;
   TOnStart = procedure (const MaxValue: Cardinal) of object;
   ExcAborted = class(Exception);
   THTTPDownload = class(TThread)
     constructor Create(AOwner: TComponent); reintroduce; virtual;
   private
     FOwner: TComponent;
     FStarted: Boolean;
     FAborted: Boolean;
     FOnStep: TOnStep;
     FOnStop: TOnStop;
     FOnStart: TOnStart;
     FURL: String;
     FFileOut: String;
     FLastErr: String;
     procedure URL_OnDownloadProgress(Sender: TDownLoadURL;
       Progress, ProgressMax: Cardinal;
       StatusCode: TURLDownloadStatus;
       StatusText: String; var Cancel: Boolean);
     procedure SetFileOut(const Value: String);
     procedure SetURL(const Value: String);
   public
     property URL: String read FURL write SetURL;
     property FileOut: String read FFileOut write SetFileOut;
     property LastError: String read FLastErr;
     property OnStart: TOnStart read FOnStart write FOnStart;
     property OnStep: TOnStep read FOnStep write FOnStep;
     property OnStop: TOnStop read FOnStop write FOnStop;
     procedure Abort;
     procedure Execute; override;
   end;
implementation
uses
   Forms;
{ THTTPDownload }
procedure THTTPDownload.Abort;
begin
   FAborted := True;
end;
constructor THTTPDownload.Create(AOwner: TComponent);
begin
   inherited Create(True);
   FOwner := AOwner;
   Priority := tpLower;
   FStarted := False;
   FAborted := False;
   FLastErr := '';
end;
procedure THTTPDownload.Execute;
begin
   try
     if FURL = '' then
       raise Exception.Create('Invalid value for URL');
     if FFileOut = '' then
       raise Exception.Create('Invalid value for FileOut');
     with TDownloadURL.Create(FOwner) do
     try
       URL := FURL;
       FileName := FileOut;
       OnDownloadProgress := URL_OnDownloadProgress;
       try
         ExecuteTarget(nil);
       except
         raise ExcAborted.Create('Aborted by user');
       end;
     finally
       Free;
     end;
     if Assigned(FOnStop) then
       FOnStop(ssOK, '');
   except
     on E: ExcAborted do
     begin
       if Assigned(FOnStop) then
         FOnStop(ssAbort, '');
     end;
     on E: Exception do
     begin
       FLastErr := E.Message;
       if Assigned(FOnStop) then
         FOnStop(ssError, FLastErr);
     end;
   end;
end;
procedure THTTPDownload.SetFileOut(const Value: String);
begin
   FFileOut := Value;
end;
procedure THTTPDownload.SetURL(const Value: String);
begin
   FURL := Value;
end;
procedure THTTPDownload.URL_OnDownloadProgress(Sender: TDownLoadURL; 
Progress,
   ProgressMax: Cardinal; StatusCode: TURLDownloadStatus; StatusText: 
String;
   var Cancel: Boolean);
begin
   Cancel := FAborted;
   if Assigned(FOwner) and (FOwner is TForm) then
     TForm(FOwner).Refresh;
   if (not FStarted) and (ProgressMax > 0) then
   begin
     FStarted := True;
     if Assigned(FOnStart) then
       FOnStart(ProgressMax);
   end;
   if Assigned(FOnStep) then
     FOnStep(Progress);
end;
end.

la butto li: cosa succede se commenti l'assegnazione di
OnDownLoadProgress?
A.

 A.
Eh no.
La mia classe � praticamente un wrapper della classe TDownloadURL 
definita nella unit ExtActns.
OnDownLoadProgress � l'evento della classe TDownloadURL che io utilizzo 
per verificare lo stato del mio download.
Peraltro TDownloadURL � a sua volta il wrapper della funzione 
URLDownloadToFile della urlmon.dll.
Comunque per risponderti se blocco OnDownloadProgress, il thread 
principale rimane bloccato lo stesso e in pi� non ho informazioni sullo 
stato del processo.

 URLDownloadToFile della urlmon.dll.
speravo che il problema fosse la gui.
non riesci a usare direttamente la funzione mandando a quel paese la
classe almeno x fare un test  e vedere se fa lo stesso?
A.

 Magari usando le Indy?
Roberto, usa comunque le indy che sono thread safe. Di seguito codice 
provato con indy9 e delphi7. Ho provato a scaricare un exe e funziona 
molto bene. Non ci vuole molto ad inserirla in un thread.
procedure TForm1.Button1Click(Sender: TObject);
begin
   T:=TMemoryStream.create;
   try
     idHTTP1.Get('
http://www.giovelug.org/tuofile.exe
',T);
     T.SaveToFile('tuofile.exe');
   finally
    ....
   end;
end;
Antonio

 end;
Questa ï¿œ uno dei primi tentativo che ho fatto, ma a me compare un 
criptico warning con scritto "HTTP:/1.1 302 Found".
Io uso Delphi 2009 e il link di prova che uso ï¿œ questo:
http://www.avs4you.com/download_product_direct.aspx?product=AVSDVDPlayer&sct=aff&ct=regnow&cid=77225
che praticamente ï¿œ un programma lettore dvd gratuito.
Ciao

 che praticamente ï¿œ un programma lettore dvd gratuito.
Qui non ho windows e sto provando con Lazarus/FPC e Synapse Ararat come 
libreria, ma il concetto credo sia lo stesso. Usando il codice di 
seguito con il TUO indirizzo ottengo questo stream:
<html><head><title>Object moved</title>
<script language='javascript' 
src='
http://stat.avs4you.com/javascript/SiteTracking.js
' 
type='text/javascript'> </script>
<script language='javascript' 
type='text/javascript'>document.write(generatedScript('ygcskc45zxosrc55ruxp2c45',false));</script>
</head><body>
<h2>Object moved to <a href="/downloads/AVSDVDPlayer.exe">here</a>.</h2>
</body></html>
Il link dell'oggetto sembra essere stato mosso. Per cui, ho provato 
usando questo link diretto:
http://www.avs4you.com/downloads/AVSDVDPlayer.exe
con questo codice:
procedure TForm1.Button1Click(Sender: TObject);
begin
   with THTTPSend.Create do
   begin
     if 
HTTPMethod('GET','
http://www.avs4you.com/downloads/AVSDVDPlayer.exe
') then
     try
       Document.SaveToFile('AVSDVDPlayer.exe');
     except
       Application.MessageBox('Cannot display','Error', 0);
     end;
     Free;
   end;
end;
e funziona piuttosto bene. Il file ï¿œ stato scaricato ed ho provato a 
lanciarlo con wine (wine AVSDVDPlayer.exe) ed ï¿œ partita l'installazione 
sotto wine (anche se non ï¿œ un emulatore, diciamo emulata per intenderci).
Antonio

 seguito con il TUO indirizzo ottengo questo stream:
Un curiositï¿œ: come lo ottieni lo stream del link?

 Un curiositï¿œ: come lo ottieni lo stream del link?
Sempre con lo stesso codice, ma passandogli il primo indirizzo. 
SaveToStream ha scritto quel codice html file che ti ho postato qui e 
tramite il quale mi sono reso conto del nuovo indirizzo per il download. 
  Se devi implementare qualcosa di automatico puoi fare il parsing di 
quel codice html e poi far ripartire il download verso il giusto indirizzo.
Synapse ï¿œ una libreria non visuale, blocking come indy e quindi semplice 
da usare anche nei thread, con un altissimo grado di compatibilitï¿œ 
cross-platform. Per semplici operazioni internet io la consiglio 
vivamente, anche se indy ï¿œ incredibilmente piï¿œ potente e flessibile !
Antonio