Einzelnen Beitrag anzeigen

berens

Registriert seit: 3. Sep 2004
431 Beiträge
 
Delphi 2010 Professional
 
#1

OnFinish --> FreeAndNil --> Exception

  Alt 16. Okt 2018, 11:03
Hallo,
ich versuche mich soweit es geht mittlerweile an der asynchronen Programmierung. D.h. nicht mehr "Tue etwas - *warten* - Auswerten" sondern "Tue etwas, und wenn Du fertig bist, rufe die-und-die Prozedur zurück".

Ich habe einen ClientSocket der mit einem Netzwerkgerät kommuniziert. Sobald er eine Antwort erhalten hat, speichert er das Ergebnis, trennt die Verbindung und kann dann freigegeben werden (ich habe ja jetzt meine Infos und brauche den ClientSocket nun nicht mehr).

Delphi-Quellcode:
procedure TFoo.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  ResultText := 'Getrennt von ' + Socket.RemoteAddress;
  NotifyFinish;
end;

procedure TFoo.NotifyFinish;
begin
  if assigned(OnFinish) then begin
    OnFinish(Self);
  end;
end;
Delphi-Quellcode:
procedure TForm2.SendFinished(Sender: TObject);
var
  cs: TFoo;
begin
  if Sender.InheritsFrom(TFoo) then begin
    cs := TFoo(Sender);
    Memo1.Lines.Add('ResultText: ' + cs.ResultText);
    Memo1.Lines.Add('ResultData: ' + cs.ResultData);
    Memo1.Lines.Add('Result: ' + BoolToStr(cs.Success, True));
    FreeAndNil(cs);
  end;
end;
Der ClientSocket agiert also unabhängig vom Hauptprogramm (bzw. "form2"), und löst auch brav TForm2.SendFinished aus, die Infos werden korrekt im Memo angezeigt.

Im Step-By-Step Debugging bin ich nun nach dem Disconnect mit der Zeile "NotifyFinish" durch, und IN der "end;" Zeile von ClientSocket1Disconnect schmeißt er mir nun die Exception um die Ohren. Die Fehlermeldung Socket 10038 die ich erhalte bedeutet letzt endlich, dass Ich/Windows auf einen Socket zugreife, den es nicht mehr im RAM gibt. Ist ja eigentlich auch klar, ich habe den kompletten ClientSocket ja auch eben mit FreeAndNil freigegeben...

Die Ursache für dieses eigentliche Problem ist mit ja generell bekannt. In der ParameterListe von ClientSocket1Disconnect steht ja ein Verweis auf "Socket: TCustomWinSocket", und nach Ende dieser Prozedur wird entweder mein Hauptobjekt, oder zumindest der übergebene Socket nochmal(?) von der Garbage-Collection oder sonstweshalb freigegeben oder was auch immer.

Die Frage ist nun, wie macht man es richtig? Ich einem früheren Thema von mir habe ich ja beigebracht bekommen, dass ein Objekt sich nicht selbst freigeben kann/darf/soll. Also muss ich über ein Event der übergeordneten Komponente mitteilen, dass diese Komponente nun ihre Arbeit beendet hat und freigegeben werden kann. Aus Prozeduren heraus, die mehr als nur "Sender: TObject;" als Parameter haben, darf man das scheinbar nicht? Eine andere private Prozedur aufrufen, die die übergeordnete Komponente zum freigeben benachrichtigt bringt ja auch nichts, weil ich nach Abwicklung dieser Prozedur ja wieder bzw. immernoch in ClientSocket1Disconnect bin, und das selbe Problem gerade wieder besteht. Wie rufe ich nun die Benachrichtigung auf, ohne noch einen auf den Stack draufzulegen?

Die einzige Möglichkeit die mir einfällt, wäre bei ClientSocket1Disconnect einen Timer der selben Komponente zu stellen, der nach 1ms triggert und dann das OnFinish auslöst. Dann wäre zumindest das Problem mit der Socket-Exception gelöst (falls es klappt). Aber ist das die richtige und/oder elegante Weise? Kann ich mir nicht vorstellen...
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit
  Mit Zitat antworten Zitat