AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Einbinden eines Thread Downloads

Ein Thema von Stewag · begonnen am 16. Jul 2024 · letzter Beitrag vom 22. Jul 2024
Antwort Antwort
Seite 2 von 2     12   
Stewag

Registriert seit: 12. Jun 2008
175 Beiträge
 
Delphi 12 Athens
 
#11

AW: Einbinden eines Thread Downloads

  Alt 21. Jul 2024, 19:16
Danke jaenicke, aber so einfach ist es nicht.

Es fehlt schon mal der Deklarationsteil und auch der Constructor.

Habe mal versucht, das nach den Angaben von Himitsu zu ergänzen.
So bekomme ich zumindest schon mal keinen Laufzeitfehler:

Code:
unit SyncThreadedDownload;

interface

uses
  System.RTLConsts, System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.URLClient;

type
  TDownloadCompleteEvent = reference to procedure(const URL: String; Stream: TStream; Error: Exception);

  TFileDownloader = class(TThread)
    procedure ThreadedDownloadFile(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);

  private
    FStream: TStream;
    FOnDownloadComplete: TDownloadCompleteEvent;

  public
    constructor Create(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);
    property OnDownloadComplete: TDownloadCompleteEvent read FOnDownloadComplete write FOnDownloadComplete;

  end;

implementation

{ TFileDownloader }
constructor TFileDownloader.Create(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);
begin
  if not Assigned(OnDownloadComplete) then
    raise Exception.Create('peng');
  inherited Create(False); // Himitsu: "und jetzt außen kein Start mehr, da es am Ende des Create von selbst startet" -> Äääh, wie bitte?
  FreeOnTerminate := True;
  FOnDownloadComplete := OnDownloadComplete; // Himitsu: "und der Rest im Execute/DownloadFile" -> ich glaube der Rest steckt jetzt in ThreadedDownloadFile, oder ??? 
end;

procedure TFileDownloader.ThreadedDownloadFile(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);
begin
  if (URL = '') or not Assigned(OnDownloadComplete) then
    raise EArgumentException.CreateRes(@SArgumentNil);
  TThread.CreateAnonymousThread(
    procedure
    var
      HTTP: THTTPClient;
      Stream: TMemorystream;
      DError: Exception;
    begin
      TThread.NameThreadForDebugging('ThreadedDownloadFile');
      DError := nil;
      HTTP := THTTPClient.Create;
      Stream := TMemorystream.Create;
      try
        HTTP.CustomHeaders['Pragma'] := 'no-cache';
        try
          HTTP.Get(URL, Stream);
          { TThread.Synchronize(nil,
            procedure
            begin
            OnDownloadComplete(URL, Stream, nil);
            end); }
        except
          { on E: Exception do begin
            TempErr := E; // durch einen Bug muß es kopiert werden, auch wenn der Compiler sich bei OnDownloadComplete(URL, nil, E); nicht beschwert ... E ist im Sync leider NIL
            TThread.Synchronize(nil,
            procedure
            begin
            //OnDownloadComplete(URL, nil, E); // siehe Bugreport im alten QualityPotal
            OnDownloadComplete(URL, nil, TempErr);
            end);
            end; }
          FreeAndNil(Stream);
          // für das if-Assigned im OnDownloadComplete ... oder einfach lassen, auch wenn es eh nichts sinnvolles enthält, und nur auf Assigned(Error) prüfen
          DError := AcquireExceptionObject as Exception;
        end;
        TThread.Synchronize(nil,
          procedure
          begin
            OnDownloadComplete(URL, Stream, DError);
          end);
      finally
        DError.Free;
        Stream.Free;
        HTTP.Free;
      end;
    end).Start;
end;

end.
Leider klappt aber der Aufruf mit keiner der beiden angegebenen Methoden. Beide mal erhalte ich den Fehler "[dcc32 Fehler] Unit1.pas(43): E2076 Diese Form des Methodenaufrufs ist nur für Klassenmethoden oder Konstruktoren zulässig"

Code:
type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure DownloadComplete(const URL: String; stream: TStream; Error: Exception);

  private
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  {Methode 1:
  TFileDownloader.ThreadedDownloadFile('https://www.example.de/test',
    procedure(const URL: String; stream: TStream; Error: Exception)
    begin
      if Assigned(stream) then
      begin // if not Assigned(Error) then
        begin
          Memo1.lines.LoadFromStream(stream);
          ShowMessage('Download complete: ' + URL);
        end;
      end;
    end);
    }
// Methode 2
   TFileDownloader.ThreadedDownloadFile('https://www.example.de/test', DownloadComplete);
end;

procedure TForm1.DownloadComplete(const URL: String; stream: TStream; Error: Exception);
begin

//Wie kann ich hier abfragen, ob eine Exception vorliegt?

    Memo1.lines.LoadFromStream(stream)
  // else
  // Label1.Text := 'Download failed';
end;
Steffen

Geändert von Stewag (21. Jul 2024 um 19:18 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#12

AW: Einbinden eines Thread Downloads

  Alt 21. Jul 2024, 22:21
Danke jaenicke, aber so einfach ist es nicht.
Doch, wäre es, wenn du nicht selbst noch etwas dazu schreiben würdest. Das Beispiel war vollständig. Ich hatte nur den Inhalt der Prozedur weggelassen, weil der oben eh schon stand. Komplett sieht es dementsprechend so aus:
Delphi-Quellcode:
unit SyncThreadedDownload;

interface

uses
  System.RTLConsts, System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.URLClient;

type
  TDownloadCompleteEvent = reference to procedure(const URL: String; Stream: TStream; Error: Exception);

procedure ThreadedDownloadFile(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);

implementation

procedure ThreadedDownloadFile(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);
begin
  if (URL = '') or not Assigned(OnDownloadComplete) then
    raise EArgumentException.CreateRes(@SArgumentNil);
  TThread.CreateAnonymousThread(
    procedure
    var
      HTTP: THTTPClient;
      Stream: TMemorystream;
      Success: Boolean;
      DError: Exception;
    begin
      TThread.NameThreadForDebugging('ThreadedDownloadFile');
      DError := nil;
      HTTP := THTTPClient.Create;
      Stream := TMemoryStream.Create;
      try
        HTTP.CustomHeaders['Pragma'] := 'no-cache';
        try
          HTTP.Get(URL, Stream);
          {TThread.Synchronize(nil,
            procedure
            begin
              OnDownloadComplete(URL, Stream, nil);
            end);}

        except
          {on E: Exception do begin
            TempErr := E;  // durch einen Bug muß es kopiert werden, auch wenn der Compiler sich bei OnDownloadComplete(URL, nil, E); nicht beschwert ... E ist im Sync leider NIL
            TThread.Synchronize(nil,
              procedure
              begin
                //OnDownloadComplete(URL, nil, E);  // siehe Bugreport im alten QualityPotal
                OnDownloadComplete(URL, nil, TempErr);
              end);
          end;}

          FreeAndNil(Stream); // für das if-Assigned im OnDownloadComplete ... oder einfach lassen, auch wenn es eh nichts sinnvolles enthält, und nur auf Assigned(Error) prüfen
          DError := AcquireExceptionObject as Exception;
        end;
        TThread.Synchronize(nil,
          procedure
          begin
            OnDownloadComplete(URL, Stream, DError);
          end);
      finally
        DError.Free;
        Stream.Free;
        HTTP.Free;
      end;
    end).Start;
end;

end.
Wenn du es als Klasse nutzen möchtest, kannst du das natürlich tun (finde ich auch besser), aber dann brauchst du eine Klassenmethode:
Delphi-Quellcode:
unit SyncThreadedDownload;

interface

uses
  System.RTLConsts, System.SysUtils, System.Classes, System.Net.HttpClient, System.Net.URLClient;

type
  TFileDownloader = class
  private
    type
      TDownloadCompleteEvent = reference to procedure(const URL: String; Stream: TStream; Error: Exception);
  public
    class procedure ThreadedDownloadFile(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);
  end;

implementation

class procedure TFileDownloader.ThreadedDownloadFile(const URL: String; OnDownloadComplete: TDownloadCompleteEvent);
begin
  if (URL = '') or not Assigned(OnDownloadComplete) then
    raise EArgumentException.CreateRes(@SArgumentNil);
  TThread.CreateAnonymousThread(
    procedure
    var
      HTTP: THTTPClient;
      Stream: TMemorystream;
      Success: Boolean;
      DError: Exception;
    begin
      TThread.NameThreadForDebugging('ThreadedDownloadFile');
      DError := nil;
      HTTP := THTTPClient.Create;
      Stream := TMemoryStream.Create;
      try
        HTTP.CustomHeaders['Pragma'] := 'no-cache';
        try
          HTTP.Get(URL, Stream);
          {TThread.Synchronize(nil,
            procedure
            begin
              OnDownloadComplete(URL, Stream, nil);
            end);}

        except
          {on E: Exception do begin
            TempErr := E;  // durch einen Bug muß es kopiert werden, auch wenn der Compiler sich bei OnDownloadComplete(URL, nil, E); nicht beschwert ... E ist im Sync leider NIL
            TThread.Synchronize(nil,
              procedure
              begin
                //OnDownloadComplete(URL, nil, E);  // siehe Bugreport im alten QualityPotal
                OnDownloadComplete(URL, nil, TempErr);
              end);
          end;}

          FreeAndNil(Stream); // für das if-Assigned im OnDownloadComplete ... oder einfach lassen, auch wenn es eh nichts sinnvolles enthält, und nur auf Assigned(Error) prüfen
          DError := AcquireExceptionObject as Exception;
        end;
        TThread.Synchronize(nil,
          procedure
          begin
            OnDownloadComplete(URL, Stream, DError);
          end);
      finally
        DError.Free;
        Stream.Free;
        HTTP.Free;
      end;
    end).Start;
end;

end.
Wie kann ich hier abfragen, ob eine Exception vorliegt?
Das stand oben im Quelltext als Kommentar drin:
Zitat:
if not Assigned(Error) then
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Stewag

Registriert seit: 12. Jun 2008
175 Beiträge
 
Delphi 12 Athens
 
#13

AW: Einbinden eines Thread Downloads

  Alt 22. Jul 2024, 07:13
D-A-N-K-E Himitsu und jaenicke!!!

"Manchmal ist es gar nicht kaputt, man ist nur zu blöd!"
Steffen
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:45 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz