Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Einbinden eines Thread Downloads (https://www.delphipraxis.net/215508-einbinden-eines-thread-downloads.html)

Stewag 21. Jul 2024 18:16

AW: Einbinden eines Thread Downloads
 
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;

jaenicke 21. Jul 2024 21:21

AW: Einbinden eines Thread Downloads
 
Zitat:

Zitat von Stewag (Beitrag 1539088)
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.
Zitat:

Zitat von Stewag (Beitrag 1539088)
Wie kann ich hier abfragen, ob eine Exception vorliegt?

Das stand oben im Quelltext als Kommentar drin:
Zitat:

Delphi-Quellcode:
if not Assigned(Error) then


Stewag 22. Jul 2024 06:13

AW: Einbinden eines Thread Downloads
 
D-A-N-K-E Himitsu und jaenicke!!! :-D

"Manchmal ist es gar nicht kaputt, man ist nur zu blöd!"


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:05 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz