Autor Beitrag
JJ
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 100

Windows XP 64 bit!
delphi 5
BeitragVerfasst: Di 26.08.08 15:00 
Hallo Leute!
Ich habe ein Riesenproblem. Ich möchte mehrere Downloads gleichzeitig realiseren.
Im Internet habe ich 2 Möglichkeiten gefunden Downloads zu realisieren (URLDownloadToFile und per Wininet)
Beide Funktionieren auch gut nur leider legen sie das Programm total lahm, wenn ich den Downloadbefehl aufrufe.
Da die Dateien größer sind dauert der Download mehrere Minuten und ich möchte eben, dass ich meine Programmoberfläche trotz Download im Hintergrund weiter laufen lassen kann (um vielleicht noch einen Download zu Starten oderso).

Ich habe es mal mit DownloadStatusCallBack für URLDownloadToFile versucht, aber leider bringt es die Anwendung so zum Ruckeln, dass sie unbenutzbar wird.

Vorab: Ich weiß wie groß die Datei ist, die ich herunterladen möchte. Ich könnte also durch Abfrage der aktuellen Größe der gerade herunterladenden Datei auch feststellen, ob der Download komplett ist.

Ich möchte also mehrere Downloads parallel neben der Anwendung laufen lassen ...

Wie kann ich das am besten (kürzesten ;-) realisieren? Mit Threads? Wenn ja wie?

danke im Voraus

Gruß Jonas

---Moderiert von user profile iconNarses: Beiträge zusammengefasst---

Ok... ich bin an einem Punkt der Verzweiflung angelangt an dem ich mich entschlossen habe die Indykomponenten zu installieren und es damit zu versuchen. Mein Projekt ist zwar kommerziell, aber laut der License sollte das kein Problem sein. Trotz langjähriger Delphierfahrung isses mir aber jetzt nicht mmöglich Indy9 für mein Delphi 5 zu installieren.
Ich Kompiliere und installiere dkp und er fügt die Komponenten uach hinzu! Aber wenn ich sie benutzen will, kann delphi die installierten Klassen von Indy nicht finden .... Ich hänge mich hier bald buchstäblich auf, da ich schon die ganzen letzten 2 Tage ohne unterbrechung an dem Problem hänge! Wäre wirklich super wenn mir jemand helfen könnte...

_________________
Hallo!
huuuuuh
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 665
Erhaltene Danke: 19

win xp, (win vista), win 7
VS 2008 Express Edition, VS 2010 Express Edition, VS 2010 Professionell
BeitragVerfasst: Di 26.08.08 19:23 
gibs die indys überhaupt für d5?
ansonsten: besorg dir doch turbodelphi... is kostenlos und indy is schon dabei, kommerzielle projekte gehn damit auch...
außerdem kannst du da einen thread über einen eigenen menüpunkt recht einfach erstellenn...
j.klugmann
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 26.08.08 19:36 
Erstell doch für jeden Download ein Thread.
Guck mal hier:www.michael-puff.de/...er/Delphi/Tutorials/
Sind echt super!Wird alles ausführlich erklärt.
@Luckie: :zustimm: :zustimm: :zustimm:
JJ Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 100

Windows XP 64 bit!
delphi 5
BeitragVerfasst: Mi 27.08.08 01:10 
Danke für die schnellen und qualifizierten Antworten. Habe mich für die threadlösung entschieden, die auch ganz gut funktioniert. Allerdings wäre es super wenn ihr mir noch ein paar kleine Fragen zu der threadlösung beantworten könntet.

Wird der Thread automatisch terminiert, wenn der Download (siehe Code) abgeschlossen ist?

Warum kann cDownloadStatusCallback auf die Public Viriables des Threads nicht zugreifen?

Kann ich irgendwie einsehen, wie viele Threads ich erstellt habe und wie ich die nachträglich noch ansprechen kann, bevor sie sich selbst terminieren? (oder das Terminieren ALLER Threads erzwingen?)

In meinem GUI mache ich bei einem Doppelklick auf eine Datei eben den Downloadthread auf. Da ich davon ausgehe ,dass er sich selbst termniniert wenn der Download abgeschlossen ist, mache ich nichts weiter mit ihm. Er ist dann aber irgendwie verloren für mich, weil ich keine Ahnung hab, wie ich nachträglich noch auf ihn zugreifen kann.
(Oder kann ich dem Thread eventuell auch variable Namen geben? Ich wüsste nicht wie....)




Vielleicht mögen euch die Fragen ein bisschen Doof erscheinen, aber ich habe wirklich noch nicht so viel mit Threads gemacht, deswegen habt bitte Verständnis.




ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
unit mDownload;

interface        

uses
  Windows, Messages, SysUtils, Classes, Forms, Dialogs, URLmon, ActiveX;

type
  cDownloadStatusCallback = class(TObject,IUnknown,IBindStatusCallback)
  private
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    function OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult; stdcall;
    function GetPriority(out nPriority): HResult; stdcall;
    function OnLowResource(reserved: DWORD): HResult; stdcall;
    function OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult; stdcall;
    function OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult; stdcall;
    function GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult; stdcall;
    function OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc; stgmed: PStgMedium): HResult; stdcall;
    function OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult; stdcall;
  end;

  type
   Download = CLASS(TThread)

     private
          DownloadURL : string//URL von der heruntergeladen wird
          DownloadLocation : string//In dieses Verzeichnis wird geladen
     public
          UserCancel : boolean;


     // weitere Methoden
     protected
        procedure execute; override;
     public
        constructor create; virtual;
        procedure SetURL(URL : String); virtual;
        procedure SetLocation(Location : String); virtual;
   end;


implementation

function cDownloadStatusCallback._AddRef: Integer;
begin
  Result := 0;
end;

function cDownloadStatusCallback._Release: Integer;
begin
  Result := 0;
end;

function cDownloadStatusCallback.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if(GetInterface(IID,Obj)) then
  begin
    Result := 0
  end else
  begin
    Result := E_NOINTERFACE;
  end
end;

function cDownloadStatusCallback.OnStartBinding(dwReserved: DWORD; pib: IBinding): HResult;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.GetPriority(out nPriority): HResult;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.OnLowResource(reserved: DWORD): HResult;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.OnStopBinding(hresult: HResult; szError: LPCWSTR): HResult; stdcall;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.GetBindInfo(out grfBINDF: DWORD; var bindinfo: TBindInfo): HResult; stdcall;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.OnDataAvailable(grfBSCF: DWORD; dwSize: DWORD; formatetc: PFormatEtc; stgmed: PStgMedium): HResult;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.OnObjectAvailable(const iid: TGUID; punk: IUnknown): HResult; stdcall;
begin
  Result := S_OK;
end;

function cDownloadStatusCallback.OnProgress(ulProgress, ulProgressMax, ulStatusCode: ULONG; szStatusText: LPCWSTR): HResult;
begin
  case ulStatusCode of
    BINDSTATUS_FINDINGRESOURCE:
    begin
    end;
    BINDSTATUS_CONNECTING:
    begin
    end;
    BINDSTATUS_BEGINDOWNLOADDATA:
    begin
    end;
    BINDSTATUS_DOWNLOADINGDATA:
    begin
    //
    end;
    BINDSTATUS_ENDDOWNLOADDATA:
    begin
    end;
  end;
  Application.ProcessMessages;
  Result := S_OK;
end;

procedure Download.execute;
var
StatusCallback : cDownloadStatusCallback;
begin
StatusCallback := cDownloadStatusCallback.Create;
URLDownloadToFile(nil,pchar(DownloadURL),pchar(DownloadLocation),0,StatusCallback);
end;

constructor Download.create;
begin
  inherited create(true); // CreateSuspended = true
  freeOnTerminate := true;
end;

procedure Download.SetURL(URL : String);
begin
  DownloadURL := URL;
end;

procedure Download.SetLocation(Location : String);
begin
  DownloadLocation := Location;
end;

end.

_________________
Hallo!
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 27.08.08 01:27 
Wenn die Thread Funktion bzw. die Execute Methode verlassen wird, terminiert auch der Thread. Allerdings ist es eine Überlegung wert, ob du den erwünschten Performance Gewinn hast. Zum einem müssen sich die Downloadthreads die Bandbreite teilen und zum anderen können die Festplattenzugrioffe zum Speichern der Daten nur synchron erfolgen, da die Festplatte immer nur einen Datenstrom gleichzeitig schreiben kann (Die Schreibköpfe hängen ja alle zusammen.). Da man das aber nicht pauschalisieren kann, müsstest du etwas mit der Anzahl der Threads rumprobieren.
JJ Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 100

Windows XP 64 bit!
delphi 5
BeitragVerfasst: Mi 27.08.08 01:58 
Hey Lucky :), cool ,dass du auch noch wach bist.

Danke für deine Antwort. Die Downloads lasten die Internetbandbreite bei weitem nicht aus, da die Server von denen ich herunterlade sehr langsam sind. Deswegen wollte ich mehrere Downloads gleichzeitig realisieren und auch den Downloadfortschritt visualisieren. Nur ich weiß eben auch nicht wie ich die Callback ausgeben kann ... aus dem Thread heraus ... oder wie ich sie aus dem GUI abfragen kann.




Ok Habe StatusCallback ganz einfach zum reden animiert .... dann konnte ichs vom Thread aus abfragen .... (kann geclosed werden, DANKE NOCHMAL!!!)

_________________
Hallo!