![]() |
TTimer und Abarbeitung der Messages
Hi,
ich habe mal eine kleine Frage zu der TTimer Umsetzung. Ich habe auf dem Hauptformular die TTimer Komponente gesetzt. Somit wird sich um die Freigabe automatisch gekümmert. Jetzt kam es beim beenden des Programm zu einer Exception.
Delphi-Quellcode:
Der Debugger hat nun gezeigt das innerhalb des FormDestroy nach der Freigabe von myObject1 noch ein TimerEvent ausgelöst und abgearbeitet wird wenn myObject1 bereits freigegeben ist.
var
myObject1: TMyObject; myObject2: TMyObject; myObject3: TMyObject; procedure FormX.FormCreate(Sender: TObject); begin myObject1:= TMyObject.Create; myObject2:= TMyObject.Create; myObject3:= TMyObject.Create; end; procedure FormX.Timer(Sender: TObject); begin Button.Caption = myObject1.Status; end; procedure FormX.FormDestroy(Sender: TObject); begin myObject1.Free; // <-- Exception myObject2.Free; myObject3.Free; end; Das macht ja soweit bis zu einem gewissen Punkt auch Sinn. Allerdings bin ich bisher davon ausgegangen das die Messages im Programm lediglich im IdleState abgarbeitet werden. Das obige Verhalten widerspricht meiner Annahme. Wann werden die Messages nun wirklich abgarbeitet ? Ein weiteres Problem. Theoretisch könnte man die Exception ja umgehen indem man im TimerEvent prüft ob myObject1 noch existiert. Alternativ dazu könnte man im FormDestroy bevor die Objekte freigegeben werden Timer.Enable := False setzen. Allerdings befürchte ich das letzteres auch nicht wirklich zielführend ist. Wenn in einem unglücklichen Fall gerade eine Timer-Message in die Queue gelegt wurde und ich anschließend Timer.Enable := False setze könnte es dennoch passieren das ein Event nach dem Timer.Enable := false ausgeführt wird. Der von TTimer intern verwendete KillTimer() Befehl sorgt ja nicht dafür das bereits in der Queue stehende Messages entfernt werden. Somit ist durch ein Timer.Enable := false nicht sichergestellt das nach dem Befehl keine Timer Events mehr ausgelöst werden. Gibt es da eine saubere Möglichkeit um das Problem zu umgehen ? |
AW: TTimer und Abarbeitung der Messages
In FormDestroy:
Code:
In Timer:
FreeAndNil(MyObject1);
Code:
Aber wahrscheinlich gibt es noch was eleganteres?
If Assigned(MyObject) Then...
|
AW: TTimer und Abarbeitung der Messages
Warum nimmst du einen Timer und nicht
![]() Und ein
Delphi-Quellcode:
verbunden mit einem
Assigned
Delphi-Quellcode:
wirkt Wunder
FreeAndNil
|
AW: TTimer und Abarbeitung der Messages
Hi,
vielen Dank für die schnellen Antworten :) Der Weg über FreeAndNil() inkl Assigned() Prüfung ist mir bekannt. Allerdings ging es mit primär darum zu verstehen wie und wann die Window Messages abgerarbeitet werden das muss doch in irgendeiner Form deterministisch sein. Ich war immer der Auffassung das Messages im Gegensatz zu Threads nicht den Programmfluss unterbrechen und daher im Gegensatz zu Threads auch keine Synchronisation benötigen. Desweiteren kommt mir die Nutzbarkeit des TTimer etwas arge eingeschränkt vor wenn man sich nicht darauf verlassen kann das nach einem .Enable := False; auch keine Events mehr ausgelöst werden. Der Tipp mit dem IdleEvent ist super das muss ich mir merken :) Nochmal zum TTimer:
Delphi-Quellcode:
Das obige ist der Originalcode aus der ExtCtrls.pas würde ich mit folgender Änderung erreichen können das nach dem Disable wirklich keine Events mehr ausgelöst werden ? (oder übersehe ich da was ?)
procedure TTimer.SetEnabled(Value: Boolean);
begin if Value <> FEnabled then begin FEnabled := Value; UpdateTimer; end; end; procedure TTimer.UpdateTimer; begin KillTimer(FWindowHandle, 1); if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then if SetTimer(FWindowHandle, 1, FInterval, nil) = 0 then raise EOutOfResources.Create(SNoTimers); end; procedure TTimer.WndProc(var Msg: TMessage); begin with Msg do if Msg = WM_TIMER then try Timer; except Application.HandleException(Self); end else Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam); end;
Delphi-Quellcode:
procedure TTimer.WndProc(var Msg: TMessage);
begin with Msg do if Msg = WM_TIMER then try if FEnabled then Timer; // FEnable check to avoid Events after disable except Application.HandleException(Self); end else Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam); end; |
AW: TTimer und Abarbeitung der Messages
Zitat:
Wenn der Timer Disabled wird, dann wird sofort ![]() [add] Und da man auf solche Komponenten niemals aus anderen Threads zugreift, kann es auch nicht zu Problemen kommen. Auch nicht bezüglich des nachfolgend genannten
Delphi-Quellcode:
, denn auch dabei wird sofort KillTimer aufgerufen. :stupid:
Timer.OnTimer := nil
|
AW: TTimer und Abarbeitung der Messages
Und warum nicht einfach zuerst
Timer.OnTimer := nil und dann erst Timer.Enabled := false; dann kann doch eigentlich nichts mehr passieren, oder? |
AW: TTimer und Abarbeitung der Messages
@himitsu
Genau das hätte ich für logisch empfunden. Zitat aus der Windows Api Zitat:
@mm1256 So sollte es natürlich auch klappen und man muss dafür das TTimer Objekt nicht anpassen perfekt. |
AW: TTimer und Abarbeitung der Messages
Bist du sicher, daß die Hilfe da stimmt?
Ich kann mich nicht erinnern jemals ein TimerEvent nach dem deaktivieren eines Timers bekommen zu haben. Da wäre es doch statistisch eigenartig, wenn das niemals passiert wäre. :gruebel: Hab mal schnell einen Test gemacht: > zwei Timer und Memo auf der Form
Delphi-Quellcode:
procedure TForm2.FormCreate(Sender: TObject);
begin Timer1.Interval := 500; Timer2.Interval := 5000; end; procedure TForm2.Timer1Timer(Sender: TObject); begin Memo1.Tag := Memo1.Tag + 1; Memo1.Lines.Add('OnTimer: ' + IntToStr(Memo1.Tag)); end; procedure TForm2.Timer2Timer(Sender: TObject); begin Timer2.Enabled := False; Memo1.Lines.Add('Disable 1'); //Timer1.Enabled := False; // disablen vor dem Event Sleep(1500); Timer1.Enabled := False; // disablen nach dem Event Memo1.Lines.Add('Disable 2'); end;
Delphi-Quellcode:
In beiden Fällen müsste dann ein OnTimer eintreffen, nachdem der Timer deaktiviert wurde, aber es passiert nicht. :gruebel:
procedure TForm2.FormCreate(Sender: TObject);
begin Timer1.Interval := 500; Timer2.Enabled := False; end; procedure TForm2.Timer1Timer(Sender: TObject); begin Memo1.Lines.Add('OnTimer'); Sleep(1500); Memo1.Lines.Add('Disable'); Timer1.Enabled := False; end; procedure TForm2.Timer2Timer(Sender: TObject); begin // end; |
AW: TTimer und Abarbeitung der Messages
:shock: Wenn ich manuell was in die Queue schiebe, dann wird das nicht verworfen.
Sehr verwirrend.
Delphi-Quellcode:
Ich dachte Windows schiebt die Timer-Events asynchron in die Queue. :freak:
type
THackedTimer = class(TComponent) private FInterval: Cardinal; FWindowHandle: HWND; end; procedure TForm2.FormCreate(Sender: TObject); begin Timer1.Interval := 500; Timer2.Enabled := False; end; procedure TForm2.Timer1Timer(Sender: TObject); begin Memo1.Lines.Add('OnTimer'); if THackedTimer(Timer1).FInterval = 0 then ; PostMessage(THackedTimer(Timer1).FWindowHandle, WM_TIMER, 1, 0); Sleep(1500); Memo1.Lines.Add('Disable'); Timer1.Enabled := False; end; procedure TForm2.Timer2Timer(Sender: TObject); begin // end; |
AW: TTimer und Abarbeitung der Messages
Wirklich merkwürdig.
Was mich jetzt aber doch zusätzlich noch interessieren würde wie nun intern das abholen der Messages organisiert ist. Es muss ja irgendwo im Hintergrund sowas wie eine MessageLoop geben. Nur unter welchen Voraussetzungen arbeitet die MessageLoop, sprich wann wird Sie abgearbeitet ? Mich wundert ja noch immer das während sich das Programm im destructor befindet überhaupt noch Messages behandelt werden. Ich wäre jetzt erstmal davon ausgegangen das mit dem betreten des destructor automatisch keine weitere Messageverarbeitung mehr abgeholt werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:22 Uhr. |
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