![]() |
Problem beim Beenden (DLL mit Formular und mODBC)
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen!
Ich poste diesen Thread in "Sonstige Fragen zu Delphi", weil ich mir nicht ganz sicher bin, wo das Thema einzuordnen ist. Ich möchte eine DLL erstellen, die mir Daten aus einer Datenbank (die nur per ODBC erreicht werden kann) aufbereitet und zur Verfügung stellt. Die DLL wird später dann in Verbindung mit diversen Scriptsprachen verwendet. Für den Datenzugriff verwende ich mODBC. Da der Anwender noch einige Einstellungen vornehmen muss, verwende ich in der DLL auch ein VCL-Formular, auf dem auch die Datenbankzugriffskomponenten platziert sind. Um es etwas klarer zu machen, habe ich gleich ein Beispielprojekt angehängt. Es beinhaltet den Quellcode der DLL + eine Exe-Datei, welche die exportierte Funktion aufruft (nach einem Click auf den Button). Als Datenquelle kann zum Testen eine beliebige ODBC-Datenquelle verwendet werden. Das Problem entsteht erst beim Beenden. Wenn ich Form1.free aufrufe gibt es eine Speicherschutzverletzung und es wird ein Runtime-Error angezeigt. Verzichte ich auf das free, so erhalte ich keine Fehlermeldung, das Formular wird dann aber auch nicht korrekt freigegeben. Ich vermute, dass es mit der Reihenfolge zu tun hat in der die einzelnen Bestandteile freigegeben werden. Mir ist aber weder klar, wie ich das herausfinden, noch wie ich das lösen/beeinflussen kann. Ich habe schon versucht dass Fromular zu verschiedenen Zeitpunkten frei zu geben: ohne Erfolg. Vielleicht hat jemand eine Idee dazu.... Gruß und schon mal vielen Dank, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Hat sich das schon mal jemand angeschaut? Ich wäre auch an der Info interessiert, wenn das Problem nicht nachvollzogen werden konnte. Vielleicht ist es ja ein spezielles Problem an meinem Rechner? Ich glaube aber eher, dass ich einen kleinen aber entscheidenden Fehler gemacht habe (mal wieder). Gruß, Stüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Hat keiner 'ne Idee, Anregung, einen Link, oder eine Hinweis? Momentan komme ich an der Stelle einfach nicht weiter. Ich implementiere nach und nach alle Funktionen in der DLL und hoffe, das es eine Lösung gibt. Wenn nicht bzw. wenn ich einen grundlegenden Fehler gemacht habe, sehe ich dann alt aus. Ich bin also auch dankbar, wenn mich jemand darauf hinweist, dass ich einen Anfängerfehler gemacht habe... :roll: Gruß, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
hi StTüff,
habe mir Dein Projekt nicht genauer angeschaut, aber ich hatte ähnliche Probleme mit Formularen in DLLs. Bis ich herausgefunden habe, daß DLL-Formulare geschlossen sein müssen beim Entladen der DLL ! Habe also einfach eine Procedure exportiert "CloseAllForms" oder so, welche alle DLL-Formulare schließt. Diese Procedure rufe ich auf beim Programmende vor Entladen der DLL. Hoffentlich hilft's ?! Gruß blauweiss |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo blauweiss!
Danke für die Nachricht! Ich werde mir das noch mal genau anschauen. Ich meine aber dass das so ist. Das Problem scheint zu sein, dass der finalize-Abschnitt der mODBC-Komponente erst abgearbeitet wird, nachdem ich das Formular mit free freigegeben habe. Dann "crashts" natürlich. Lasse ich das "free" weg, so gibt es keine Fehlermeldung, aber eigentlich sollte man das Formular, dass man erzeugt hat doch auch wieder freigeben.... (macht zwar unter XP - so glaube ich - nicht viel aus, aber sauber ist das nicht). Mir sind jetzt 2 Dinge nicht ganz klar: 1. Wann wird der finalize-Abschnitt aufgerufen (im Vergleich DLL zu exe). 2. Wie kann die Reihenfolge festgelegt werden bzw. wie kann ich die Formulare nach dem Ablauf des finalize-Abschnitts freigeben. Viellecht komme ich über diese Fragen zu einer möglichen Lösung :coder2: Gruß und besten Dank, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
hallo StTüff,
habe mir Dein Projekt mal auf die Schnelle angeschaut, und mir ist aufgefallen, daß Du offenbar eben gerade NICHT das Formular schließst. Die exportierte Prozedur FreeDLL gibt das nicht-modale Formular nur frei, schließt es aber zuvor nicht ! Crasht es immer noch, wenn Du das DLL-Formular zur Laufzeit schließst, und dann erst das Hauptprogramm beendest ? Gruss blauweiss |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo blauweiss!
Es ist richtig, dass dies im Programmcode nicht zu finden ist. Ich habe das Formular aber bisher immer geschlossen (mit X), bevor ich das aufrufende Programm beendet hatte. Zur Sicherheit habe ich jetzt vor dem "free" noch Form1.close eingefügt => keine Änderung. Hast Du das Programm nur angeschaut, oder auch mal getestet? Tritt der Fehler bei Dir auch auf? Gruß, StTüff. |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo,
Grundsätzlich sollte man immer nur die Türen auch schliessen, welche man selber geöffnet hat und auch nur diese. Das soll heißen, daß du Form1.Free eventuell nicht aufrufen solltest, da dass Aufräumen der Forms normalerweise automatisch passiert. Wenn du es allerdings selber "Created" hast, dann OK. Desweitern sollte in einer DLLAufräumRoutine auch nur das aufgeräumt werden, was in der DLL erzeugt wurde. Denke hier in Zonen, welche sich selber unabhängig verwalten. Du solltest auch immer in der umgekehrten Reihenfolge aufräumen (FirstIn-LastOut) Desweiteren sollte man anstelle
Delphi-Quellcode:
besser verwenden
MyObject.Free;
Delphi-Quellcode:
, Denn dabei wird die Variable MyObject auf NIL gesetzt. Das kannst du dann nutzen, indem du in deinen Methoden/Funktionen prüfst, ob das Object noch da ist, also eventuell in Finalization
FreeAndNil(MyObject);
Delphi-Quellcode:
If Assigned(MyObject)then
|
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo peschai!
Danke für Deine Nachricht! Leider möchte ich es eigentlich genau so machen, wie Du vorschlägst: Ich erzeuge das Formular und möchte es dann auch wieder freigeben. Leider ist es aber so, dass ich keinen Einfluss daruf habe, wann der finalize-Abschnitt der mODBC-Komponente aufgerufen wird (das mache ich nämlich nicht selbst). Ich gebe das Formular zum (mir) letzt möglichen Zeitpunkt (nämlich beim entladen der DLL) frei. Ich kann aber mit dem Debugger sehen, dass der Finalize-Abschnitt danach aufgerufen wird und es dann (logischer weise) zu dem Fehler kommt. Genau das ist der Punkt, den ich 1. nicht verstehe und 2. keine Ahnung habe, wie ich das verhindern kann. Warum wird der Finalize-Abschnitt erst nach dem Free des Formulars aufgerufen? Wie kann ich dafür sorgen, dass erst der Finalize-Abschnitt aufgerufen wird und dann das Formular freigegeben wird? Ich denke das sind die entscheidenden Fragen (wenn ich nicht noch was anderes komplett falsch gemach habe, was durchaus möglich ist). Gruß und noch mal vielen Dank! StTüff PS: FreeAndNil bring in diesem Fall leider keine Abhilfe, auch wenn ich Dir ansosnten natürlich diesbezüglich recht gebe. |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
Zusatzanmerkungen: Zitat:
Wenn Statisch, (also programstart, dann dll auto geladen und bei Programmende auto entladen) dann würde ich dir empfehlen:
Delphi-Quellcode:
exports
StartReport; Initialization DLLMain(DLL_PROCESS_ATTACH); ...DLLProcNext... Finalization ...DLLProcNext... DLLMain(DLL_PROCESS_DETACH); end; |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
unsere Antworten haben sich überschnitten ... Eventuell hilft dir punktuell
Delphi-Quellcode:
..Aber in deiner Programmgesamtlogic stimmt noch etwas nicht:
if Assignd(Form1) then
begin FreeAndNil(Form1) end; Für die Freigabe ist normalerweise der Owner zuständig...und eventuell passiert das bereist und du bekommet deshalb den Absturz... Wo und wie erzeugst du dass Formular ? |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Ich kann doch jetzt noch nicht wissen, wie die DLL verwendet wird. Bei meinem Beispielprojekt macht es keinen Unterschied, ob die DLL dynamisch, oder statisch geladen wird. "DLL_PROCESS_ATTACH" wird immer beim laden der DLL (egal ob staisch, oder dynamisch) aufegerufen und "DLL_PROCESS_DETACH" immer beim entladen. Vielleicht habe ich aber auch Deine Bemerkung nicht richtig verstanden. Gruß, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Aktueller Stand:
Delphi-Quellcode:
Beim Laden erzeugen, beim entladen freigeben.
procedure DLLMain(Reason: Integer);
begin case Reason of DLL_PROCESS_ATTACH: begin DisableThreadLibraryCalls(hInstance); Form1:=TForm1.Create(nil); end; DLL_THREAD_ATTACH: ; DLL_THREAD_DETACH: ; DLL_PROCESS_DETACH: begin FreeAndNil(Form1); //Problem bei mSession finalization !!!!!!!!!!!1 end; end; Gruß, StTüff Edit: Im ursprünglichen Beispiel:
Delphi-Quellcode:
In der Datei DataMain.pas.... Macht aber keinen Unterschied.
initialization
begin Form1:=TForm1.Create(nil); end; finalization begin Form1.Free; end; |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
Weitere zusatzinfo: Per defintion wird die Finalization section als letztes aufgerufen, quasi beim entladen des Moduls. Das kann nicht geändert werden und das darf auch nicht geändert werden. |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
du gibst Form1 an zwei stellen frei ohne vorherige Prüfung mit Assigned! |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Zitat:
Ich wäre jetzt davon ausgegangen, dass beim zerstören des Formulars das Modul entladen wird. Offensichtlich geschieht das aber erst später (abhängig von was?). Sollte ich beim Erzeugen des Formulars vielleicht einen Owner angeben? Aber welchen? Gruß und vielen Dank für die Hilfe! StTüff PS: In meinem aktuellen Projekt gibt es nur 1 mal "free" bzw. FreeAndNil und ich glaube im Beispiel alleine auch nicht mehrmals. Ich hatte in der Nachricht nur zwei verschiedene Möglichkeiten genannt, deshalb sieht es vielleicht so aus.... |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
Zitat:
Das Entladen des Moduls (DLL) passiert immer als letztes! Beim statischen Linken von Dll's werden diese vom Betriebssystem automatisch bei Programmstart geladen und beim Beenden des Programms (.exe) wieder entladen. Das hier ist meiner Meinung nach auch das richtige für dich. Beim dynamische Linken schreibst du Code, der die DLL lädt und must dementsprechend auch wieder Code schreiben zum Entladen (stichwort LoadLibrary, DLLReferenzZähler sollte dir hier etwas sagen, sonst bitte nachlesen) |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
und bitte als guten stil verwende ich persönlich immer FreeAndNil und das als paar mit der abfrage auf Assigned.
Delphi-Quellcode:
if Assignd(Form1) then
begin FreeAndNil(Form1) end; |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Das erklärt zwar auf der einen Seite das Verhalten, dass der Fehler erst beim Beenden des Aufrufenden Programms auftritt, die Frage ist aber, was kann ich tun um das Problem zu beseitigen. Wie im letzten Besipiel gezeigt, versuceh ich das Fromular erst beim Entladen freizugeben. Offensichtlich (wie Du ja auch geschrieben hast) ist das entladen des Moduls immer das letzte. Damit habe ich 2 neue Fragen: 1. Warum passiert das nicht wenn ich mODBC in einer normalen GUI Anwendung (EXE) verwende. 2. Ist das dann ein Fehler in mODBC? Gruß, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Ich habe mir mal den Quellcode angeschaut. Eventuell ist es ein grundsätzliches Problem, dass es kein Application-Objekt gibt?! Im Quellcode von mODBC taucht immer mal wieder "Application." auf. Kann da jemand was dazu sagen? Gruß, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo!
Ich habe jetzt noch folgendes herausgefunden: Wenn ich das Formular so
Delphi-Quellcode:
oder so
Form1:=TForm1.Create(Application);
Delphi-Quellcode:
erzeuge, dann wird beim schließen von Form1 nicht nur die DLL (bzw. das Form1) sondern auch die Anwendung, die die DLL aufgerufen hat beendet.
Application.CreateForm(TForm1, Form1);
=> Offensichtlich steht in der Variablen "Application" die Referenz, auf das Programm, dass die DLL aufgerufen hat. Scheinbar verwenden die Komponenten (inklusive mODBC) dann dieses Application-Objekt. Das scheint ein grundsätzliches Problem zu sein. Ich gehe davon aus, dass es kein Problem geben würde, wenn die DLL ein eigenes Application-Objekt hätte. Gibt es hier jemanden, der sich damit auskennt, oder soll ich einen separaten Thread in einer anderen Rubrik starten? Gruß, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
<offtopic>
Zitat:
Weniger Zeilen machen dein Programm lesbarer! </offtopic> |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Zitat:
Dann schau dir mal den Source an (Delphi2007Prof) von SysUtils.pas:
Delphi-Quellcode:
Da ist keine Abfrage nach assigend! :angel:
procedure FreeAndNil(var Obj);
var Temp: TObject; begin Temp := TObject(Obj); Pointer(Obj) := nil; Temp.Free; end; Deshalb möglicher eigener Ersatz: (aber natürlich "langsamer")
Delphi-Quellcode:
procedure MyFreeAndNil(var Obj);
var Temp: TObject; begin Temp := TObject(Obj); Pointer(Obj) := nil; if assigned(Temp) then Temp.Free; end; |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Zitat:
|
Re: Problem beim Beenden (DLL mit Formular und mODBC)
OK. Nach dem wir das geklärt haben noch mal zu meinem Problem:
Ich fasse zusammen: - Beim Starten des Programms (das die DLL aufruft; statische Bindung) wird von mODBC der Initializeabschnitt ausgeführt (nicht beim create des Formulars). - Der Finalizeabschnitt entsprechend beim Beenden und nich beim free des Formulars. - Ist das Formular bereits freigegeben gibt es eine Exception (ungültiger Speicherzugriff). Wird das Formular nicht freigegeben gibt es kein Problem (abgesehen davon dass das Formular dann nicht freigegeben ist). - Frage ich in der DLL "application.exename" ab so wird mir der Name der Aufrufenden Anwendung ausgegeben. - Bei anderen Parametern (z.B. "application.mainForm") gibt es in der DLL eine Fehlermeldung in der EXE kann zugegriffen werden. => application ist also offensichtlich nicht identisch, hat aber Einfluss auf die Komponenten auf dem DLL-Formular (Verwendung von Application in mODBC). - Gebe ich beim erzeugen des Formulars apllication als Parent an, so wird das Formular automatisch zerstört, die Fehlermeldung kommt aber trotzdem.... Alles schön zusammengefasst, aber immer noch keine Ahnung.... :pale: Kann das jemand nachvollziehen? Soll ich noch weitere Quellen (mODBC) oder sonst was hochladen? Gruß und vielen Dank für die Unterstützung, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo
@stTüff: Hast du meine Absicherung mal eingebaut? Sorry stTüff aber die Discussion mit Flocke ist auch für dich wichtig! Meiner Meinung nach kann hier Dir am schnellesten geholfen werden. @Flocke: Okay, Tobject.Free ist abgesichert, aber was ist mit den Nackommen? :twisted: In den meisten Fällen arbeiten wir mit Erben von TObject. Sobald diese etwas mehr im Free/Destroy machen könnte in manchen Situation der Vorschlag von mir helfen. Denn da fehlt meistens die Assigned oder NIL-Abfrage... Ein Beispiel original Code:
Delphi-Quellcode:
Mein grundsätzlicher Vorschlag ist, daß es EXACT eine Variable gibt, welche den Zeiger auf ein dynamisch angelegtes Object oder Speicherbereich enthält. Wenn diese Variable einen Wert<>NIL beinhaltet, dann existiert das Object/Speicherbereich. Wenn diese Variable NIL beinhaltet, dann wurde es von mir auch wieder freigegeben! Natürlich kann es Kopien dieses Zeigers geben, aber es sollte immer klar sein, was ist die Referenz und was die Kopie.
destructor TCustomForm.Destroy;
begin Application.RemovePopupForm(Self); if not (csDestroying in ComponentState) then GlobalNameSpace.BeginWrite; try if OldCreateOrder then DoDestroy; MergeMenu(False); if HandleAllocated then DestroyWindowHandle; Screen.RemoveForm(Self); FCanvas.Free; FIcon.Free; FreeAndNil(FPopupChildren); FreeAndNil(FRecreateChildren); GlassFrame.Free; FreeMem(Pointer(FPixelsPerInch)); inherited Destroy; finally GlobalNameSpace.EndWrite; end; end; |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Na klar habe ich die "Sicherung" eingebaut (war in meinem eigentlichen Projekt übrigens schon immer so, nur eben in dem vereinfachten Beispiel nicht).
Leider macht das keinen Unterschied. Es ist auch nicht so, dass der Fehler beim Destroy des Objektes auftritt. Vielmehr passiert beim finalize von mODBC irgendwas, was ich noch nicht näher eingrenzen konnte. Momentan geht meine Vermutung wie oben erwähnt dahin, dass es etwas mit dem application-Objekt (bzw. mit den Unterschieden bei dem Objekt zwischen DLL und EXE) zu tun hat. Kann aber auch sein, dass ich da voll auf dem Holzweg bin. Sicher ist nur, dass nicht mehrfach versucht wird Form1 freizugeben. Allerdings ist ebenfalls sicher, wenn Form1 nicht freigegeben wird, tritt keine Fehlermeldung auf und Form1 wird definitiv nicht freigegeben (OnDestroy tritt dann nicht ein). Ich komme einfach nicht so richtig weiter. Habe nur ich das Problem? Vermutlich ja: Sonst macht keiner was mit DLL und Forms, weil es da nur Probleme gibt, oder? Vielleicht kann mir jemand eine Alternative nennen. Voraussetzung ist, dass der Aufruf der Funktione aus einer beliebigen Programmier-/Scriptsprache erfolgen kann (z.B. VBA). Gruß, StTüff |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
@StTüff: Der Fehler tritt offensichtlich in TmSession.FreeHENV beim Aufruf von SQLFreeHandle auf. Da läuft offensichtlich irgendetwas schief, was du schlecht beeinflussen kannst. Als ganz bösen Workaround kannst du die Zeile "SQLFreeHandle" in TmSession.FreeHENV in try..except klammern und den Fehler ignorieren:
Delphi-Quellcode:
@peschai:
procedure TmSession.FreeHENV;
begin if FHENV = 0 then exit; try SQLFreeHandle(SQL_HANDLE_ENV, FHENV); except end; FHENV:=0; end; Zitat:
Den virtuellen Destruktor destructor Destroy, 1. den man in eigenen Klassen überschreiben kann, 2. der immer mit einem Aufruf von inherited; enden sollte und 3. den man nie direkt aufrufen sollte. Die statische Methode procedure Free, die 1. man nie überschreiben sollte, 2. als einzige (letzendlich) nutzen sollte, um ein Objekt freizugeben und 3. die eben aus dem Grund existiert, dass sie prüfen kann ob "Self <> nil" ist - eine virtuelle Methode kann das nämlich nicht. Darum reicht FreeAndNil! Den Zeiger vorher auf NIL zu prüfen ist überflüssig. |
Re: Problem beim Beenden (DLL mit Formular und mODBC)
Hallo Flocke!
Danke für die Info! Da bin ich auf der einen Seite froh, dass ich nicht ganz auf dem Holzweg war, andererseits traurig, dass es keine "perfekte" Lösung gibt. Die Frage, die jetzt noch bleibt: Ist es besser das Formular nicht freizugeben (Windows XP gibt den Speicher beim Beenden der Anwendung frei, oder?), oder eben den von Dir vorgeschlagenen Workaround zu verwenden. Was hinterlässt potentiel mehr "Reste"? Vielleicht findet auch noch jemand den genauen Grund. Ich werde mit meinen bescheidenen Mitteln auch noch mal forschen. Gruß und noch mal vielen Dank, StTüff |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:21 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