Autor Beitrag
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: So 15.09.19 15:26 
Ich habe hier grade ein komisches Problem über "Ferndebugging" lösen dürfen (also mehrfaches Abändern des Codes mit anschließender Zusendung des MadExcept-Bugreports.

Ich hoffe, ich breche den Code nicht zu stark herunter. Folgendes.

Im OnCreate der Form erstelle ich ein paar Objekte.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.FormCreate(Sender: TObject);
begin
   Foo := TFoo.Create;
   // Foo.stuff := Gedöns; // Variablen-Initialisierung 

   Bar := TBar.Create;
   Bar.foo := Foo;
end;


Diese Objekte brauche ich dann z.B., um passend auf das Resize eines Panels auf der Form1 zu reagieren.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.Panel1Resize(Sender: TObject);
begin
   if Foo.Bool1 then  
       Foo.DoSomething;
   // das "if" knallt beim Start.
   // Abhilfe:
   // if assigned(Foo) and Foo.Bool1 then   
end;


Das finde ich schonmal merkwürdig, dass das Panel.OnResize aufgerufen wird, bevor das FormCreate fertig ist. Aber gut. Noch seltsamer wird es dann beim nächsten Panel-Resize:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TForm1.Panel2Resize(Sender: TObject);
begin
   if Bar.Bool2 then   // läuft erstmal
      Bar.DoStuff;
end;

// in der Klasse TBar:
procedure TBar.DoStuff;
begin
    if foo.Bool3 then // knallt
       DoSomeWork;
end;

Abhilfe ist wieder die gleiche.

Ich frage mich nun, wie es passieren kann, dass Zugriff auf Foo fehlschlägt, aber der Zugriff auf Bar, das nach Foo erzeugt wird, erst einmal keine Fehlermeldung verursacht. Und das ganze natürlich nur auf einem System (oder einigen?). Bei mir unter Win10, 64 Bit läuft das durch. Der gemeldete Fall war wohl ein Windows 10 (32 Bit) auf einem Tablet-PC.

Klingt nach einem klassischen Race-Condition-Bug, aber wie kommt der hier zustande? Macht die VCL hier auf einmal Multithreading und arbeitet schonmal weiter, während das Foo.Create und die Variablenzuweisung noch läuft?

Und wie kann ich das sauber verhindern? Beim Start des FormCreate alle Resize-Handler auf Nil setzen und am Ende wieder passend? Oder muss ich im Form-Designer schon die Resize-Handler austragen, und darf sie nur manuell nach dem Create setzen?

Hat der wer einen Denkanstoß für mich? :gruebel:

_________________
We are, we were and will not be.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 15.09.19 17:24 
Du kannst erstmal testen ob es deine Objekte schon gibt.
Also sauber initialisierte Variablen und dann auf foo <> nil oder via Assigned(foo).
Auch Bar natürlich. Es kann sein das hier einfach beim Zugriff die Adresse nicht in die Ferne führt.
Ist schon ein interessanter Fehler. Ereignisse werden via Windowsbotschaften erzeugt / geparkt.
Das kann auf unterschiedlichen System in unterschiedlicher Reihenfolge passieren.
Generell würde ich mit dem arbeiten in OnResize warten bis OnActivated/OnShow gekommen ist.
Und zwar nicht via abhängen von Ereignishandlern, sondern einer Variable die Du in OnActivated setzt.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?

Für diesen Beitrag haben gedankt: Gausi
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: So 15.09.19 20:46 
Den Test auf Assigned habe ich ja schon eingebaut, und es funktioniert.

Das mit der "ReadyForResize"-Variable, die im OnActivate/OnShow passend gesetzt wird, finde ich eine schöne Lösung. Denn das ist dann später eher nachvollziehbar als der Test auf Assigned dieser Objekte. Das werde ich wohl so einbauen. :zustimm:

Ich finde die "Unordnung", die da manchmal entsteht, aber trotzdem nicht schön - hauptsächlich, weil ich das noch nicht verstehe ... :lol:

_________________
We are, we were and will not be.
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Mo 16.09.19 16:49 
Überschreib doch den echten Konstruktor der Basisklasse des Formulars und nutze nicht das Event FormCreate. Wenn Du Deine Instanzen dann sogar noch vorm Inherited erzeugst, dann kannst Du absolut sicher sein, dass das als allererstes passiert.

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Di 17.09.19 09:10 
Das setzt aber vorraus das man nicht mit TForm arbeitet sondern mit einer eigenen Ableitung TFormFoo.
Das macht durchaus Sinn. Erst recht dann wenn man all seinen Fenstern weiteres Verhalten beibringen will. Wie zum Beispiel automatisches laden und speichern von Position und Größe.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8535
Erhaltene Danke: 473

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Di 17.09.19 17:58 
Das mit der eigenen Formklasse ginge natürlich auch. Aber ich werde wohl den Weg gehen, die Resize-Handler erst dann zu "aktivieren", wenn es auch was bringt. :D

_________________
We are, we were and will not be.