Autor Beitrag
Christian213
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Di 20.08.13 13:55 
Hallo,

ich sende mittels WinInet einen HTTP-Post an einen Server. Dieser wertet den POST aus und gibt dann als Response einen Datenstream, welchen ich downloade.
Nun möchte ich, dass während der Server die Anfrage bearbeitet (also bevor der Response gesendet wird), dass meine Progressbar langsam weiterläuft.
Im Prinzip klappt das auch, allerdings wird beim allen von mir bisher getesteten Timer-Varianten der Timer während des Wartens auch angehalten.
Genau geschieht das bei folgendem Aufruf:
ausblenden Delphi-Quelltext
1:
HTTPSendRequest(pRequest, nil0, Pointer(POSTDaten), Length(POSTDaten))					

Im Moment erfolgt der Aufruf synchron, aber auch asynchron bringt nicht die Lösung, da während des Wartens der Callback gar nicht getriggert wird.

Gibt es eine Möglichkeit, dass ein Timer (oder was auch immer) meinen Fortschrittsbalken weiterzeichnet, egal in welchem Zustand sich das Hauptprogramm gerade befindet?

Danke!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 20.08.13 14:48 
Sende den Request einfach in einem Thread. ;-)

Für diesen Beitrag haben gedankt: Christian213
Christian213 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Di 20.08.13 14:51 
Hm, die Idee ist gut. Muss ich mich wohl mal näher mit Threads beschäftigen, da habe ich noch etwas Wissenslücken.
Gibt es ein brauchbares Tutorial zu dem Thema?
Christian213 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Do 22.08.13 11:56 
Irgendwie hänge ich gerade bei dem Thema Threads. Hier ist mein nicht-funktioneller Versuch:

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:
function MeineFunktion(A: AnsiString; B: AnsiString; C: AnsiString): AnsiString;
type
  TThreadParams = packed record
    TFunc: TMeineKlasse;
    A: AnsiString;
    B: AnsiString;
    C: AnsiString;
    Response: AnsiString;
    hasFinished : Boolean;
  end;
  PThreadParams = ^TThreadParams;
  var
    tp : TThreadParams;
    Thread : THandle;
    ThreadID : Cardinal;

function ThreadFunc(tp: PThreadParams): Integer;
var
    TFunc: TMeineKlasse;
    A: AnsiString;
    B: AnsiString;
    C: AnsiString;
    Response: AnsiString;
    hasFinished : Boolean;
begin
  A := PThreadParams(tp)^.A; // >>> Hier knallt es bereits - wieso???
  B := PThreadParams(tp)^.B; 
  C := PThreadParams(tp)^.C;
  Response := PThreadParams(tp)^.Response;
  hasFinished := PThreadParams(tp)^.hasFinished;
  Response := TFunc.ExterneFunktion(A, B, C); // Externe Funktion der Klasse "MeineKlasse" in einer anderen Unit
  hasFinished := true; // Soll eigentlich tp.hasFinished setzen, so dass die while-Schleife dies erkennen kann
  Result := 0;
end;

begin
  tp.TFunc := MeineKlasse; // Wurde außerhalb der Funktion schon global definiert
  tp.A := A; // Ebenso diese Variablen
  tp.B := C;
  tp.C := C;
  tp.hasFinished := false;
  ThreadID := 0;
  Thread := BeginThread(nil0, @ThreadFunc, @tp, 0, ThreadID);
  while not tp.hasFinished do
  begin

    // Dinge tun, während der Thread noch läuft, z.B. die Progressbar weiterzeichnen

  end;
  CloseHandle(Thread);
  Result := tp.Response;
end;


Wenn ich den Code kompiliere und starte, bekomme ich einen SIGSEGV.
Kommentiere ich die Zeilen wie "A := PThreadParams(tp)^.A;" aus, passiert dies nicht.
Allerdings komme ich dann auch nicht an die Werte des records ran...
Wo ist mein Fehler?
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Do 22.08.13 12:15 
Leite deine eigene Klasse von TThread ab, Properties zur Parameterübergabe, überschreibe "Execute".
Instanz erzeugen, Parameter zuweisen, Ereignis für Beenden zuweisen, Starten.
Falls mit der Progressbar in einer Schleife gespielt wird, ab und zu Prozessmessages aufrufen, damit das Ereignis beim Beenden des Thread durchkommt.
Im Ereignis dann nur ein Variable setzen.
In der Schleife diese Variable auswerten und fertig.

Für diesen Beitrag haben gedankt: Christian213
Christian213 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 66
Erhaltene Danke: 3

Win XP, Win 7 64Bit
Lazarus 1.0.10
BeitragVerfasst: Do 22.08.13 12:52 
Sicher könnte ich alles in eine eigene Klasse packen, aber ich wollte den Source nicht unnötig aufblähen.
Die Idee für meinen Ansatz habe ich von hier: www.michael-puff.de/...ng/Delphi/Tutorials/
In dem ZIP "Threads_mit_Delphi_Demos.zip" gibt ein ein Beispielprojekt "ParameterStack.dpr".
Der Beispielcode dort funktioniert. Nun frage ich mich, was bei meiner Umsetzung falsch ist??
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 22.08.13 13:15 
user profile iconChristian213 hat folgendes geschrieben Zum zitierten Posting springen:
Sicher könnte ich alles in eine eigene Klasse packen, aber ich wollte den Source nicht unnötig aufblähen.
Dann ist TThread genau das richtige, weil du viel weniger Code schreiben musst...
Wenn du alles selbst machst, hast du nur viel mehr Aufwand ohne jeglichen Nutzen...

In aktuellen Delphiversionen wäre auch ein anonymer Thread mit TThread.CreateAnonymousThread möglich.

Für diesen Beitrag haben gedankt: Christian213
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 174
Erhaltene Danke: 43



BeitragVerfasst: Do 22.08.13 13:44 
Dein "Threadfunc" ist keine eigenständige Funktion.
Die kann nur im Kontext der übergeordneten Funktion ausgeführt werden, z.B. um auf deren Variablen zugreifen zu können.
Der neue Thread hat natürlich seinen eigenen Stack.
Als eigenständige Funktion sollte das im Prinzip funktionieren.
ausblenden Delphi-Quelltext
1:
function ThreadFunc(tp: PThreadParams): Integer;					

Als Member einer Klasse, aber auf Self kann nicht zugegriffen werden:
ausblenden Delphi-Quelltext
1:
class function ThreadFunc(tp: PThreadParams): Integer; static;					

Für diesen Beitrag haben gedankt: Christian213