Autor Beitrag
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8432
Erhaltene Danke: 439

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.2 CE
BeitragVerfasst: So 15.09.19 14: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:

_________________
Oel ngati kameie.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1192
Erhaltene Danke: 100

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: So 15.09.19 16: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.

_________________
Solange keine Zeile Code geschrieben ist, läuft ein Programm immer fehlerfrei.
Ich teste nicht, weil ich Angst habe Fehler zu finden.

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

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.2 CE
BeitragVerfasst: So 15.09.19 19: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:

_________________
Oel ngati kameie.
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1576
Erhaltene Danke: 277


Delphi 10 Seattle Prof.
BeitragVerfasst: Mo 16.09.19 15: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: 1192
Erhaltene Danke: 100

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: Di 17.09.19 08: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.

_________________
Solange keine Zeile Code geschrieben ist, läuft ein Programm immer fehlerfrei.
Ich teste nicht, weil ich Angst habe Fehler zu finden.
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8432
Erhaltene Danke: 439

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.2 CE
BeitragVerfasst: Di 17.09.19 16: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

_________________
Oel ngati kameie.