Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Fehler bei Form.ShowModal (https://www.delphipraxis.net/197629-fehler-bei-form-showmodal.html)

Ykcim 23. Aug 2018 08:54

Fehler bei Form.ShowModal
 
Hallo Zusammen,

ich habe eine Fehlermeldung, die ich nicht verstehe.
Ich habe ein kleines Eingabe-Form erstellt, in dem Informationen, die nachher in eine Textdatei geschrieben werden erfasst werden.
Wenn ich das dieses Form mit ShowModal von meinem Hauptprogramm aus öffne, dann funktioniert alles wie es soll.

Jetzt habe ich aber eine Klasse in einer eigenen Unit definiert und ich möchte, dass sich das Form öffnen, wen keine Textdatei gefunden wurde. Aber dabei wird mir leider immer ein Fehler ausgeworfen...

Unit:
Delphi-Quellcode:
unit TDatenbankUnit;

interface

uses Uni, UniProvider, MySQLUniProvider, Codes, SysUtils, Vcl.Forms, Data.DB, Vcl.StdCtrls,
      System.Classes, ODBCUniProvider, CREncryption, Form_DBZugriffsdatenUnit;

Type
   TEvent = procedure(Sender: TObject) of object;
   TMySQLDB=class
      strict protected
         FMySQLConnection: TUniConnection;
         FMySQLProvider: TMySQLUniProvider;
         //Querys
         FMySelectQuery: TUniQuery;
         FMyWriteQuery: TUniQuery;
         FMyQuery_Signature: TUniQuery;
         FMyQuery_Einstellungen: TUniQuery;
         FMyQuery_Ansprechpartner: TUniQuery;
         FMyQuery_Sprache: TUniQuery;
und so weiter...


Procedure, in der der Fehler auftritt:
Delphi-Quellcode:
procedure TMySQLDB.Connect (Connection: TUniConnection);
var Datei: TextFile;
    MyString: String;
    ResultDBZugriff: integer;
begin
   ResultDBZugriff:=0;
   if not FileExists(ExtractFilePath(Application.ExeName) + 'SQL.set') then begin
      ResultDBZugriff:=Form_DBZugriffsdaten.ShowModal;  //Hier tritt der Fehler auf!
      if ResultDBZugriff>1 then begin
         Exit;
      end;
   end;
   AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
   Reset(Datei);
   try
      ReadLn(Datei, MyString);
      Connection.Server := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Username := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Password := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Database := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.ProviderName := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Port := strtoint(copy(MyString, pos(':', MyString)+1, length(MyString)));
   finally
      CloseFile(Datei);
   end;
   Connection.Connected:=true;
end;
Fehlermeldung:
Delphi-Quellcode:
Eine Exception in der Klasse $C0000005 mit der Meldung 'access violation at 0x00b31be0: read of adress 0x00000000' aufgetreten.
Sieht jemand was ich falsch mache?

Vielen Dank
Patrick

Uwe Raabe 23. Aug 2018 09:06

AW: Fehler bei Form.ShowModal
 
Ist an der betreffenden Stelle das Form_DBZugriffsdaten auch initialisiert?

KodeZwerg 23. Aug 2018 09:15

AW: Fehler bei Form.ShowModal
 
Um Uwes Aussage zu verfeinern:
Schau mal unter " Projekt -> Optionen -> Forms " rein ob Form_DBZugriffsdaten im Auto-Create drinnen steht.
Dafür sollte Visible = False auf dem Form_DBZugriffsdaten Formular gesetzt sein.

Ykcim 23. Aug 2018 09:25

AW: Fehler bei Form.ShowModal
 
UPS, hatte den einen Beitrag übersehen...
Das Form steht unter Automatisch erzeugen mit drin. Ich vermute, dass etwas in der Unit, von der ich es aufrufen möchte, falsch ist, weil es ja vom HauptForm aus funktioniert...
Ich hatte deshalb meinen "USES-Teil" mit in die Frage geschrieben.

Irgendwo fehlt ein Verweis... Aber der Fehler entsteht nicht beim compilieren, sondern erst zur Laufzeit...

Ich habe keine Idee...

Patrick

Uwe Raabe 23. Aug 2018 09:34

AW: Fehler bei Form.ShowModal
 
Aber ist das Form zum Zeitpunkt des fehlschlagenden Aufrufs auch schon erstellt worden?

Sherlock 23. Aug 2018 09:34

AW: Fehler bei Form.ShowModal
 
Ist sie erzeugt? Also entweder per vom KodeZwerg geshilderten Automatismus oder durch ein simples
Delphi-Quellcode:
Form_DBZugriffsdaten := TForm.Create
.

Sherlock

Ykcim 23. Aug 2018 09:50

AW: Fehler bei Form.ShowModal
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1411391)
Aber ist das Form zum Zeitpunkt des fehlschlagenden Aufrufs auch schon erstellt worden?

Das könnte der Grund sein... Die Prüfung, ob die Datei vorhanden ist oder nicht findet im CREATE von TDatenbankUnit statt. Bis Gerade stand das Form_DBZugriffsdatenUnit ganz unten. Ich habe es jetzt nach oben gesetzt, aber das hat nicht den gewünschten Erfolg gebracht...

Delphi-Quellcode:
program iVisitor;

uses
  Vcl.Forms,
  Form_MainUnit in 'Form_MainUnit.pas' {Form_Main},
  Form_DBZugriffsdatenUnit in 'Form_DBZugriffsdatenUnit.pas' {Form_DBZugriffsdaten},
  TMultiLanguageUnit in 'TMultiLanguageUnit.pas',
  TDatenbankUnit in 'TDatenbankUnit.pas',
  TExcelExportUnit in 'TExcelExportUnit.pas',
  TGridDesignUnit in 'TGridDesignUnit.pas',
  TBitMapUnit in 'TBitMapUnit.pas',
  Form_PasswortUnit in 'Form_PasswortUnit.pas' {Form_Passwort},
  Frame_SQLUnit in 'Frame_SQLUnit.pas' {Frame_SQL: TFrame};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm_Main, Form_Main);
  Application.CreateForm(TForm_Passwort, Form_Passwort);
  Application.CreateForm(TForm_DBZugriffsdaten, Form_DBZugriffsdaten);
  Application.Run;
end.

Ykcim 23. Aug 2018 10:01

AW: Fehler bei Form.ShowModal
 
GELÖST!

Delphi-Quellcode:
if not FileExists(ExtractFilePath(Application.ExeName) + 'SQL.set') then begin
      if (Form_DBZugriffsdaten = nil) then
         Form_DBZugriffsdaten:= TForm_DBZugriffsdaten.Create(nil);
      ResultDBZugriff:=Form_DBZugriffsdatenUnit.Form_DBZugriffsdaten.ShowModal;
      if ResultDBZugriff>1 then begin
         Exit;
      end;
   end;
Zitat:

Zitat von Uwe Raabe (Beitrag 1411391)
Aber ist das Form zum Zeitpunkt des fehlschlagenden Aufrufs auch schon erstellt worden?

Zitat:

Zitat von Sherlock (Beitrag 1411392)
Ist sie erzeugt? Also entweder per vom KodeZwerg geshilderten Automatismus oder durch ein simples
Delphi-Quellcode:
Form_DBZugriffsdaten := TForm.Create
.

Sherlock

Vielen Dank für die Hilfe - die Kombination war es...

Patrick

KodeZwerg 23. Aug 2018 10:19

AW: Fehler bei Form.ShowModal
 
Das verstehe wer will, ich tu es gerade nicht.

Wenn in .dpr es automatisch erzeugt wird aber bei Aufruf nicht vorhanden ist, da stimmt doch was nicht.
Das es forciert funktioniert mag ja schön und gut sein, aber normal ist so ein Verhalten nicht.

Delphi.Narium 23. Aug 2018 10:31

AW: Fehler bei Form.ShowModal
 
Zitat:

Zitat von Ykcim (Beitrag 1411395)
Zitat:

Zitat von Uwe Raabe (Beitrag 1411391)
Aber ist das Form zum Zeitpunkt des fehlschlagenden Aufrufs auch schon erstellt worden?

Das könnte der Grund sein... Die Prüfung, ob die Datei vorhanden ist oder nicht findet im CREATE von TDatenbankUnit statt. Bis Gerade stand das Form_DBZugriffsdatenUnit ganz unten. Ich habe es jetzt nach oben gesetzt, aber das hat nicht den gewünschten Erfolg gebracht...

Delphi-Quellcode:
program iVisitor;

uses
  Vcl.Forms,
  Form_MainUnit in 'Form_MainUnit.pas' {Form_Main},
  Form_DBZugriffsdatenUnit in 'Form_DBZugriffsdatenUnit.pas' {Form_DBZugriffsdaten},
  TMultiLanguageUnit in 'TMultiLanguageUnit.pas',
  TDatenbankUnit in 'TDatenbankUnit.pas',
  TExcelExportUnit in 'TExcelExportUnit.pas',
  TGridDesignUnit in 'TGridDesignUnit.pas',
  TBitMapUnit in 'TBitMapUnit.pas',
  Form_PasswortUnit in 'Form_PasswortUnit.pas' {Form_Passwort},
  Frame_SQLUnit in 'Frame_SQLUnit.pas' {Frame_SQL: TFrame};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm_Main, Form_Main);
  Application.CreateForm(TForm_Passwort, Form_Passwort);
  Application.CreateForm(TForm_DBZugriffsdaten, Form_DBZugriffsdaten);
  Application.Run;
end.

Die Reihgenfolge im Uses ist irrelevant.

Wenn, dann muss man die Reihenfolge bei den Application.CreateForm ändern. Dann kann sich aber auch das Hauptformular der Anwendung ändern, was nicht zwingend zielführend ist.

Sinnvoller wäre es meiner Meinung nach, das Formular, das ja nur in bestimmten Fällen, aber nicht immer, benötigt wird, aus dem Erstellautomatismus rauszunehmen und nur bei Bedarf zu erstellen und nach der Nutzung freizugeben.

Also die Zeile
Delphi-Quellcode:
Application.CreateForm(TForm_DBZugriffsdaten, Form_DBZugriffsdaten);
aus der DPR entfernen und den Aufruf des Formulares anpassen:
Delphi-Quellcode:
if not FileExists(ExtractFilePath(Application.ExeName) + 'SQL.set') then begin
  Form_DBZugriffsdaten := TForm_DBZugriffsdaten.Create(nil);
  ResultDBZugriff := Form_DBZugriffsdatenUnit.Form_DBZugriffsdaten.ShowModal;
  Form_DBZugriffsdaten.Free;
  if ResultDBZugriff > 1 then Exit;
end;
Und wenn man das dann noch in eine eigene Methode, mit 'ner vernünftigen Fehlerbehandlung packt, die sicherstellt, dass auch garantiert eine Freigabe des Formulares erfolgt, dann könnte das was werden.

Sherlock 23. Aug 2018 10:45

AW: Fehler bei Form.ShowModal
 
Die Reihenfolge in der dpr ist nicht irrelevant sondern wird genauso aus dem Formulare-Abschnitt der Projektoptionen gesteuert bzw. vorgegeben.

Dennoch ist der Einwand gut, daß man Formulare erst dann erzeugen sollte, wenn man sie braucht, das beschleunigt ja auch den Anwendungsstart.

Eventuell wird das fragliche Formular irgendwann vorher freigegeben?

Sherlock

Schokohase 23. Aug 2018 11:09

AW: Fehler bei Form.ShowModal
 
Zitat:

Zitat von KodeZwerg (Beitrag 1411398)
Das verstehe wer will, ich tu es gerade nicht.

Wenn in .dpr es automatisch erzeugt wird aber bei Aufruf nicht vorhanden ist, da stimmt doch was nicht.
Das es forciert funktioniert mag ja schön und gut sein, aber normal ist so ein Verhalten nicht.

Das hat was mit dem Timing zu tun.

Die Form wird in der dpr definitiv erzeugt, allerdings zu spät für den entsprechenden Codeteil. Und nur wenn es erzeugt wurde kann man es verwenden nicht wenn es erzeugt werden würde (wenn da nicht vorher die Exception fliegt)

KodeZwerg 23. Aug 2018 11:37

AW: Fehler bei Form.ShowModal
 
Eventuell Offtopic, wer weiß das schon
Zitat:

Zitat von Schokohase (Beitrag 1411410)
Zitat:

Zitat von KodeZwerg (Beitrag 1411398)
Das verstehe wer will, ich tu es gerade nicht.

Wenn in .dpr es automatisch erzeugt wird aber bei Aufruf nicht vorhanden ist, da stimmt doch was nicht.
Das es forciert funktioniert mag ja schön und gut sein, aber normal ist so ein Verhalten nicht.

Das hat was mit dem Timing zu tun.

Die Form wird in der dpr definitiv erzeugt, allerdings zu spät für den entsprechenden Codeteil. Und nur wenn es erzeugt wurde kann man es verwenden nicht wenn es erzeugt werden würde (wenn da nicht vorher die Exception fliegt)

Ich Danke Ihnen für diese gute Erklärung.
Es war mir schon bewusst aufgrund der Fehlermeldung das dieses Objekt noch nicht existiert.
Nur kann ich es gerade nicht nachvollziehen. Ich führe mal ein paar selbst-Tests durch mit .DPR und langsamen Formularen.
Bis jetzt habe ich so ein Verhalten noch nicht erlebt, dass das Laden lange dauern kann schon.
Das ein Objekt, obwohl man es explizit Created nicht erstellt wird erscheint mir im Moment unlogisch.

Was mir einfällt wäre, wenn ich das Hauptformular Visible=True setze, kann es sein das es da schon angezeigt wird bevor Application.Run einsetzt? Sonst ist es für mich unlogisch.

Delphi.Narium 23. Aug 2018 11:49

AW: Fehler bei Form.ShowModal
 
Zitat:

Zitat von Sherlock (Beitrag 1411404)
Die Reihenfolge in der dpr ist nicht irrelevant sondern wird genauso aus dem Formulare-Abschnitt der Projektoptionen gesteuert bzw. vorgegeben.

Dennoch ist der Einwand gut, daß man Formulare erst dann erzeugen sollte, wenn man sie braucht, das beschleunigt ja auch den Anwendungsstart.

Eventuell wird das fragliche Formular irgendwann vorher freigegeben?

Sherlock

Sorry, habe mich unpräzise geäußert.

Irrelevant in Bezug auf die Erstellungsreihenfolge.

Wenn Form_DBZugriffsdaten bereits im Form_Main angezeigt werden soll, dann muss sein Application.CreateForm in der dpr auch vor dem der Form_Main stehen.

Pech: In dem Fall wird dann Form_DBZugriffsdaten zur MainForm des Programmes.

Für diese Reihenfolge ist die Reihenfolge im Uses "egal".

Schokohase 23. Aug 2018 11:50

AW: Fehler bei Form.ShowModal
 
Es ist doch ganz einfach
Delphi-Quellcode:
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm_Main, Form_Main); // ruft den Konstruktor auf
  Application.CreateForm(TForm_Passwort, Form_Passwort);
  Application.CreateForm(TForm_DBZugriffsdaten, Form_DBZugriffsdaten); // der auf das hier zugreifen möchte
  Application.Run;
end.
Also wenn im Konstruktor von
Delphi-Quellcode:
TForm_Main
eine Instanz von
Delphi-Quellcode:
TMYSQLDB
erzeugt wird, wo dann
Delphi-Quellcode:
Form_DBZugriffsdaten
verwendet wird, dann passiert das eben.

Jumpy 23. Aug 2018 11:51

AW: Fehler bei Form.ShowModal
 
Ich versuche mal ein Scenario zu skizzieren:

MainForm wird erzeugt,
darin im OnCreate wird die TDatenbankunit erzegut,
die wiederum im Create in der Connect-Funktion auf die zu diesem Zeitpunkt noch nicht existierende TForm_DBZugriffsdaten zugreift.

Mit dem Workarround wird sie nun bei Bedarf erzeugt und dann nochmal später automatisch aus der dpr? Kann das nicht auch Probleme machen?

Delphi.Narium 23. Aug 2018 11:56

AW: Fehler bei Form.ShowModal
 
Zitat:

Zitat von KodeZwerg (Beitrag 1411411)
Eventuell Offtopic, wer weiß das schon
Zitat:

Zitat von Schokohase (Beitrag 1411410)
Zitat:

Zitat von KodeZwerg (Beitrag 1411398)
Das verstehe wer will, ich tu es gerade nicht.

Wenn in .dpr es automatisch erzeugt wird aber bei Aufruf nicht vorhanden ist, da stimmt doch was nicht.
Das es forciert funktioniert mag ja schön und gut sein, aber normal ist so ein Verhalten nicht.

Das hat was mit dem Timing zu tun.

Die Form wird in der dpr definitiv erzeugt, allerdings zu spät für den entsprechenden Codeteil. Und nur wenn es erzeugt wurde kann man es verwenden nicht wenn es erzeugt werden würde (wenn da nicht vorher die Exception fliegt)

Ich Danke Ihnen für diese gute Erklärung.
Es war mir schon bewusst aufgrund der Fehlermeldung das dieses Objekt noch nicht existiert.
Nur kann ich es gerade nicht nachvollziehen. Ich führe mal ein paar selbst-Tests durch mit .DPR und langsamen Formularen.
Bis jetzt habe ich so ein Verhalten noch nicht erlebt, dass das Laden lange dauern kann schon.
Das ein Objekt, obwohl man es explizit Created nicht erstellt wird erscheint mir im Moment unlogisch.

Was mir einfällt wäre, wenn ich das Hauptformular Visible=True setze, kann es sein das es da schon angezeigt wird bevor Application.Run einsetzt? Sonst ist es für mich unlogisch.

Wenn ich im FormCreate von Form_Main eine Routine aufrufe, die Form_DBZugriffsdaten benötigt, dann existiert es noch nicht, da es in der dpr erst später erstellt wird.

Mach Dir mal ein Programm mit ein paar Formularen, steck jeweils ins FormCreate was rein, um dort 'nen Breakpoint setzen zu können. Setze in der dpr vor das Application.Initialize einen Breakpoint und gehe dann schrittweise durch.

Was wird zuerst aufgerufen? Der Breakpoint im FormCreate des ersten Formulares oder das letzte Application.CreateForm in der dpr?

KodeZwerg 23. Aug 2018 12:14

AW: Fehler bei Form.ShowModal
 
Habe es mehr als Verstanden, Danke nochmal für Hinweise diesbezüglich. :thumb:

Ich wünsche Euch einen tollen Tag!

Zitat:

Zitat von Delphi.Narium (Beitrag 1411416)
Mach Dir mal ein Programm mit ein paar Formularen, steck jeweils ins FormCreate was rein, um dort 'nen Breakpoint setzen zu können. Setze in der dpr vor das Application.Initialize einen Breakpoint und gehe dann schrittweise durch.

Was wird zuerst aufgerufen? Der Breakpoint im FormCreate des ersten Formulares oder das letzte Application.CreateForm in der dpr?

Zuerst der vor Application.Initialize ^_^, ich weiß worauf Du hinaus wolltest, Danke auch dafür!

himitsu 23. Aug 2018 13:40

AW: Fehler bei Form.ShowModal
 
Zitat:

Zitat von Schokohase (Beitrag 1411413)
Es ist doch ganz einfach
Delphi-Quellcode:
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm_Main, Form_Main); // ruft den Konstruktor auf
  Application.CreateForm(TForm_Passwort, Form_Passwort);
  Application.CreateForm(TForm_DBZugriffsdaten, Form_DBZugriffsdaten); // der auf das hier zugreifen möchte
  Application.Run;
end.
Also wenn im Konstruktor von
Delphi-Quellcode:
TForm_Main
eine Instanz von
Delphi-Quellcode:
TMYSQLDB
erzeugt wird, wo dann
Delphi-Quellcode:
Form_DBZugriffsdaten
verwendet wird, dann passiert das eben.

Die reihenfolge zu ändern ist aber nicht unbedingt eine gute Lösung,
denn die erste so erstellte Form wird zur MainForm,
was bei einer anderen Reihenfolge zu komischen Ergebnissen führt.

Tja, besser wäre es, wenn die Letzte die MainForm würde, aber das wird nicht passieren.
Lösungen: nicht im Konstruktor sowas machen, sondern erst nachdem alles erstellt wurde. (mein Tipp: Delphi könnte ein OnStartup in den TForm bekommen, was im Run als Erstes aufgerufen würde)
oder man muß eben weiterhin mit Messages/Timern sowas manuell machen.

Oder man lässt die abhängigen Forms nicht automatisch erstellen, sondern erstellt sie selber, vor dem Zugriff darauf (es ist eh nicht immer schön, wenn "alles" automatisch erstellt wird, vor allem wenn es dann fast niemals verwendet wird)


Zitat:

Zitat von Ykcim (Beitrag 1411385)
Delphi-Quellcode:
   AssignFile(Datei, ExtractFilePath(Application.ExeName) + 'SQL.set');
   Reset(Datei);
   try
      ReadLn(Datei, MyString);
      Connection.Server := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Username := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Password := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Database := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.ProviderName := copy(MyString, pos(':', MyString)+1, length(MyString));
      ReadLn(Datei, MyString);
      Connection.Port := strtoint(copy(MyString, pos(':', MyString)+1, length(MyString)));
   finally
      CloseFile(Datei);
   end;

Du kennst schon Delphi-Referenz durchsuchenTStrings.NameValueSeparator?
Eine TStringList, jenes auf
Delphi-Quellcode:
':'
gesetzt und schon könntest du Delphi-Referenz durchsuchenTStrings.ValueFromIndex verwenden, anstatt diesem rumgeCOPYe.
Und vorher vielleicht auch noch Count proüfen, ob die Anzahl passt, mit einer netteren Fehlermeldung, anstatt deinem grauenhaften "Lesefehler". (beim Zuriff über den Index, anstatt über die Namen)

Aber da ich vermute, dass vor dem
Delphi-Quellcode:
:
jeweils ein "Name" steht, würde ich eher zu Delphi-Referenz durchsuchenTStrings.Values raten. :roll:


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:51 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz