Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   TObject in DLL: Zugriffsverletzung beim Schließen (https://www.delphipraxis.net/210247-tobject-dll-zugriffsverletzung-beim-schliessen.html)

hsg 23. Mär 2022 13:42

TObject in DLL: Zugriffsverletzung beim Schließen
 
Moin,

ich habe eine DLL geschrieben, auf die gleichzeitig von Delphi- und VBA-Programmen zugegriffen wird. Der Zugriff geschieht dabei grundsätzlich über exportierte Funktionen und Prozeduren.

Innerhalb dieser DLL habe ich eine Klasse von TObject abgeleitet, die für die Datenbankzugriffe zuständig ist. Dafür sind zwei Prozeduren zuständig: eine für die Anmeldung an der Datenbank, die andere für die Abmeldung.

Delphi-Quellcode:
procedure ConnectDB(cPServer, cPUser : PAnsiChar); stdcall;
var
  cServer: AnsiString;
  cDBUser : AnsiString;
begin
  cServer                          := AnsiString(cPServer);
  cDBUser                          := AnsiString(cPUser);
  try
    if not Assigned(dmDLLPenta) then begin
      dmDLLPenta                   := TdmPenta.Create();
    end;
    dmDLLPenta.ConnectDB(String(cServer), String(cDBUser));

  except on E : Exception do begin
      Warning('Fehler bei Verbindungsaufbau: ' + E.Message);
    end;
  end;
end;

procedure DisConnectDB( ); stdcall;
begin
  if Assigned(dmDLLPenta) then begin
    dmDLLPenta.DisConnectDB();
    FreeAndNil(dmDLLPenta);
  end;
end;
Die beiden Methoden ConnectDB und DisConnectDB sowie die Klasse sehen wie folgt aus:
Delphi-Quellcode:
  TdmPenta = class(TObject)
  private

    oPS      : TPentaSettings;
    cDBUser  : String;
    oPenta   : TPenta;

  public
    osnPenta : TOraSession;
    qryAbf   : TOraQuery;

    constructor Create(); reintroduce;
    destructor Destroy(); override;

    procedure ConnectDB(cServer, cUser : String);
    procedure DisConnectDB();

  end;

constructor TdmPenta.Create();
begin
  inherited;
  oPenta         := TPenta.Create();
  oPS            := TPentaSettings.Create();
  osnPenta       := TOraSession.Create(nil);
  qryAbf         := TOraQuery.Create(nil);
  qryAbf.Session := osnPenta;
end;

destructor TdmPenta.Destroy;
begin
  try
    FreeAndNil(qryAbf);
    FreeAndNil(osnPenta); // <==== Problemstelle
    FreeAndNil(oPS);
    if Assigned(oPenta) then begin
      FreeAndNil(oPenta);
    end;
  except on E : Exception do begin
      dbg('FSGVBA - Destroy Fehler aufgetreten: ' + E.Message);
    end;
  end;
  inherited;

end;

procedure TdmPenta.ConnectDB(cServer, cUser: String);
begin
  if not Assigned(oPenta) then begin
    oPenta := TPenta.Create();
  end;
  if not Assigned(osnPenta) then begin
    osnPenta          := TOraSession.Create(nil);
  end;
  if not Assigned(qryAbf) then begin
    qryAbf            := TOraQuery.Create(nil);
    qryAbf.Session    := osnPenta;
  end;
  DBUser              := cUser;
  osnPenta.Server     := cServer;
  osnPenta.Username   := cUser;
  osnPenta.Password   := 'xxxx';
  Settings.GetSettings(cUser);
  osnPenta.Connected  := true;
  if Assigned(oPenta) then begin
    oPenta.DBSession   := osnPenta;
  end;
end;
In den Delphi-Programmen habe ich jetzt das Problem, dass beim Beenden des Programmes im Debugger eine Exception (Access Violation at adress ....) am Ende der DLL-Freigabe geworfen wird, die im Aufrufstack bei System.Halt() anfängt und irgendwo weiter oben tatsächlich auch Adressen im Oracle-Client aufweist.
Wird die Problemstelle auskommentiert, beendet sich das Programm ohne jeglichen Fehler.

Es ist keine Exception zu sehen, wenn das Programm ohne Debugger gestartet wird!

Die Datenbankconnection wird in beiden Fällen trotzdem geschlossen.

1) Sowohl Create als auch Destroy der dmDLLPenta werden nur 1x aufgerufen!
2) Die Session ist während des Programmlaufs vollkommen i.O. Datenbankabfragen werden ohne jegliche Probleme ausgeführt. Der Ärger fängt erst an, wenn das Programm (im Debugger!) geschlossen wird.
3) Ich habe u.a. auch eine DllProc hinterlegt, die mir den DLL_PROCESS_DETACH meldet. Diese Meldung kommt vor der Exception
4) Verwendet werden die ODAC-Komponenten von Devart in Version 11.1.3 für Delphi 10.3 und 12.0.2 für Delphi 11.0, es passiert dasselbe in beiden Versionen.

Ich bin inzwischen ziemlich ratlos, was da schief geht. Irgendjemand Hinweise?

Gruß
hsg

Incocnito 23. Mär 2022 16:16

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Moin,

ohne Ahnung von irgendwas ...
In
constructor TdmPenta.Create();
setzzt du die Eigenschaft "Session" von "qryAbf".
In Destroy gibt du erst das komplette "qryAbf" frei und dann das Objekt, was du in der Eigenschaft "Session" hinterlegt hattest. Vielleciht gibt qryAbf das schon selbst frei.
Setze das vorher mal auf "nil":
Delphi-Quellcode:
destructor TdmPenta.Destroy;
begin
  try
    qryAbf.Session := nil; // <- Test
    FreeAndNil(qryAbf);
    FreeAndNil(osnPenta); // <==== Problemstelle
    FreeAndNil(oPS);
    if Assigned(oPenta) then begin
      FreeAndNil(oPenta);
    end;
  except on E : Exception do begin
      dbg('FSGVBA - Destroy Fehler aufgetreten: ' + E.Message);
    end;
  end;
  inherited;
end;
So zum Testen .. vielleicht reicht das ja schon.

LG Incocnito

BerndS 23. Mär 2022 19:04

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Um Fehler bei der Freigabe zu vermeiden könntest du auch:
Delphi-Quellcode:
TdmPenta = class(TComonent)
verwenden. Dadurch wäre es möglich den im Create erzeugten DB Komponenten als Owner Self zu übergeben. Eine Freigabe im destroy wäre damit überflüssig.

hsg 24. Mär 2022 05:12

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Moin,

habe jetzt mal die Session-Property im qryAbf auf nil gesetzt, hat aber leider nichts geändert.

Das die Klasse inzwischen von TObject abgeleitet ist, ist einer der zahlreichen Versuche, die ich inzwischen gemacht habe. Es war zuvor tatsächlich sogar ein ganz normales TDataModul und die Zerstörung der Objecte lagen in der Hand des normalen Zerstörungsprozesses von Delphi. Dort trat das Phänomen also zuerst auf.

Gruß
hsg

Incocnito 24. Mär 2022 08:05

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Hmmm ... hast du das Problem auch, wenn du nicht Connect(); aufrufst?
Ansonsten mal dein Test-Programm weiter kürzen. Das hilft meist einen besseren Überblick zu haben.
Vielleicht sehen die Kollegen hier dann auch den Fehler schneller. 😅

LG Incocnito

hsg 24. Mär 2022 09:08

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Zitat:

Zitat von Incocnito (Beitrag 1503861)
Hmmm ... hast du das Problem auch, wenn du nicht Connect(); aufrufst?
Ansonsten mal dein Test-Programm weiter kürzen. Das hilft meist einen besseren Überblick zu haben.
Vielleicht sehen die Kollegen hier dann auch den Fehler schneller. 😅

LG Incocnito

Ja, habe ich auch. Das Testsystem ist bereits soweit wie möglich eingedampft, die anderen Objekte in der Klasse habe ich jetzt auch noch auskommentiert. Passiert dennoch.

MyRealName 24. Mär 2022 10:11

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Häng Dich doch mal in die FreeNotification des session objects um zu schauen, ob diese irgendwie vorher freigegeben wird.

Incocnito 24. Mär 2022 15:44

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Ich weiß ja nicht, wie TOraQuery definiert ist, wir haben das hier nicht.
Wenn die beim Setzen des Property "Session" sich das Objekt einfach speichern (oder anderweitig weiter leiten) und das dann darüber freigegeben wird, obwohl du noch das Property "Session" auf nil setzt hast du eh verloren.
Ansonsten mal osnPenta nicht freigeben (nur auf nil setzen) und schauen, ob es ein Speicherleck gibt (ReportMemoryLeaksOnShutdown auf True). Wäre vielleicht noch interessant.


Edit:
Zitat:

Zitat von hsg (Beitrag 1503834)
...Wird die Problemstelle auskommentiert, beendet sich das Programm ohne jeglichen Fehler. ...

Never mind!

LG Incocnito

hsg 13. Apr 2022 13:49

AW: TObject in DLL: Zugriffsverletzung beim Schließen
 
Zitat:

Zitat von MyRealName (Beitrag 1503867)
Häng Dich doch mal in die FreeNotification des session objects um zu schauen, ob diese irgendwie vorher freigegeben wird.

Moin,
sorry, dass ich erst jetzt mich melde, aber ich war in den letzten Wochen leider gesundheitlich aus dem Verkehr gezogen.

Ich habe jetzt mal eine Klasse TMyOraSession um die TOraSession geschrieben und mir angesehen, wann das Destroy aufgerufen wird. Das Destroy wird nur an der gewünschten Stelle ausgelöst. Trotzdem kommt nach wie vor die Exception.

Zitat:

Zitat von Incocnito (Beitrag 1503896)
Edit:
Zitat:

Zitat von hsg (Beitrag 1503834)
...Wird die Problemstelle auskommentiert, beendet sich das Programm ohne jeglichen Fehler. ...

Never mind!

LG Incocnito

Zumindest wird mir kein Fehler angezeigt, im Gegensatz im Fall des ordnungsgemäßen Aufräumens.


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:59 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