Fehler beim Beenden der Anwendung, nur bei aktiver XP-Theme
-
In weiteren Tests heute, konnte ich feststellen das die Fehler auch nur dann auftreten, wenn ich 'Laufzeit-Packages Verwenden' aktiviert habe. Wenn ich die Laufzeitpackages in meine .EXE und .DLLs mit hineinlinke tritt der Fehler nicht auf. Ebenso zeigte ein Test in einer Windows7 Umgebung keinerlei Anzeichen von Fehlern.
Hat denn wirklich niemand einen Idee oder Tipp woran das liegen könnte?
Ich könnte das das Problem dadurch beheben, das ich eben generell die Laufzeit-Packages mitlinke. Dann würden aber z.B. so wie ich das jetzt habe, der direkte Zugriff auf meine ADO-Komponenten in der Datenmodul-DLL nicht mehr funktionieren.
Oder ich müsste mir dann z.B. eine Übergabeschicht bauen um die Datenbank Daten z.B. in Stringlisten zu übergeben und dann weiterverarbeiten.Please Help.
Grüße Netzschleicher
-
Blödsinn. Verzeihung.
-
Wenn du mehrere Module hast und dazwischen Objekte irgendwelcher Art austauschen möchtest, mußt du alle beteiligten Module mit Laufzeit-Packages und dynamischer RTL linken. Die einzige Alternative ist, alles zusammen in eine einzige Executable zu linken; alles andere funktioniert nicht.
Wie sieht das aus; verwenden alle Module einheitlich dieselben Einstellungen hinsichtlich dynamischer RTL und Packages?
-
Das hatten wir schon.
Ja, alle Module und werden mit der dynamischen RTL und den Laufzeit-Packages gelinkt. Es lief ja auch alles super bestens. Bis ich auf die Idee kam mal anzusehen wie meine Anwendung unter XP bei aktivierten LUNA-Design aussieht, und da kam dann der Fehler beim Beenden. Und nur in denen Modulen die Formulare enthalten auf welchen BitButtons oder ImageButtons (z.b. LMDButton) sitzen. Das ganze lässt sich mit dem kleinen Testprojekt das ich mir gemacht habe nachvollziehen. Unter Windof7 ist wieder alles OK. Nur unter XP eben nicht. Dabei spielt es auch keine Rolle, ob es sich um meinen Desktoprechner, mein Notebook, oder um ein virtuelles XP handelt.
-
Netzschleicher schrieb:
Das hatten wir schon.
Ah, okay, dann ist keine Umerziehung mehr nötig
Netzschleicher schrieb:
Und nur in denen Modulen die Formulare enthalten auf welchen BitButtons oder ImageButtons (z.b. LMDButton) sitzen. Das ganze lässt sich mit dem kleinen Testprojekt das ich mir gemacht habe nachvollziehen.
Könntest du das mal irgendwo hochladen? Aber ohne LMD-Komponenten, wenn's geht.
-
Ich hab Dir das Testprojekt als ZIP-Datei bei einem freien File-Uploader eingestellt:
[url]
http://www.file-upload.net/download-3716396/DLL_Test2.zip.html
[/url]Ich habe auch die kompilierten Dateien welche bei mir den Fehler erzeugen mit drin gelassen. Beim Starten kommt das Hauptfenster, dort gibt es einen Button um das in die DLL ausgelagerte Fenster zu öffnen. Beim Schließen des DLL-Fensters, egal ob mit dem Close-Button oder über das Schließen-X oben links passiert noch nichts. Erst wenn man dann das Hauptfenster schließt kommt der Fehler. Allerdings nur bei aktiver XP-Luna Oberfläche, bei statisch gelinker DLL, sowie beim Compilieren mit den Laufzeit-Packages. Wenn Du den Bitbutton durch einen normalen Button ersetzt tritt der Fehler nicht auf.
Bin jetzt wirklich mal gespannt was bei Dir herauskommt.
Vielen Dank schonmal in Voraus.
Grüße Netzschleicher
P.S.: Ich arbeite mit RAD Studio 2007 Enterprise
-
Vorab: ich habe RAD Studio XE und zur Not noch 2010 zur Hand; frühere Versionen habe ich nicht installiert.
In XE kann ich die Anwendung erstmal überhaupt nicht starten; es fliegt direkt beim Start irgendeine Zugriffsverletzung. Vermutlich hängt's mit dem bei dir aktivierten CodeGuard und irgendeinem Projektimporter-Bug zusammen.
Nachdem ich die Projektstruktur in XE nachgebaut habe, kann ich das Problem in meiner XP-VM reproduzieren.
Ich hab mal kurz mit dem Remote-Debugger reingeschaut und folgenden Stack-Trace bekommen:
:5b0f1531 ; C:\WINDOWS\system32\uxtheme.dll :5b0f47be uxtheme.CloseThemeData + 0x4b :5b0f4792 uxtheme.CloseThemeData + 0x1f :50292dee vcl150.@Themes@TThemeServices@UnloadThemeData$qqrv + 0x1e :32b9c17b ; E:\Eigene Dateien\RAD Studio\Projekte\test\DllBitBtnAVTest\Debug\Win32\CC32110MT.DLL :32b9c7f5 ; E:\Eigene Dateien\RAD Studio\Projekte\test\DllBitBtnAVTest\Debug\Win32\CC32110MT.DLL :0034152f ; E:\Eigene Dateien\RAD Studio\Projekte\test\DllBitBtnAVTest\Debug\Win32\testdll2.dll :7c9324ca ; C:\WINDOWS\system32\ntdll.dll :7c81caae ; C:\WINDOWS\system32\kernel32.dll :7c81cb26 kernel32.ExitProcess + 0x14 :32b9c0c8 ; E:\Eigene Dateien\RAD Studio\Projekte\test\DllBitBtnAVTest\Debug\Win32\CC32110MT.DLL :32b9911b CC32110MT.__wexecvpe + 0x7b :32b99134 CC32110MT._exit + 0x10 :32b9c568 ; E:\Eigene Dateien\RAD Studio\Projekte\test\DllBitBtnAVTest\Debug\Win32\CC32110MT.DLL
Damit ist schon recht klar, wer das Problem verursacht; nur der Grund ist es noch nicht klar. Aus irgendeinem Grund mag es CloseThemeData() nicht, wenn man das Theme-Handle für die Buttons in dieser Situation freigibt. Dabei kann man im Debugger beobachten, daß dasselbe Handle mehrfach von Windows selbst freigegeben wird; vermutlich wird es auch mehrfach geöffnet und verwendet intern Referenzzählung. Allerdings wird CloseThemeData() in Themes.pas nur ein einziges Mal aufgerufen, und zu diesem Aufruf korrespondiert natürlich ein OpenThemeData()-Aufruf.
Mit ein wenig Recherche per Google kommt man auf das:
http://www.progtown.com/topic117136-av-at-application-closing.html
und damit hierauf:
http://qc.embarcadero.com/wc/qcmain.aspx?d=25253Die Lösung ist also, in der DLL Folgendes einzufügen:
void setIsLibrary (void) { System::IsLibrary = true; } #pragma exit setIsLibrary 31
-
Wow, ich hätte nie das Du so schnell eine Lösung dafür hast. Da weis ich jetzt nicht wie ich mich dafür bedanken soll. Auf jeden Fall 1000Dank.
Ich bin ja bemüht neben meinem Hauptberuf mich in vielen kleinen Schritten in die Sache einzuarbeiten. Aber es ist leider nicht immer die Zeit dafür da die ich vielleicht gerne dafür hätte. Mittlerweile hab ich mir auch das C++Builder 2007 Buch von Richard Kaiser zugelegt, und den Stroustrup 'Die C++ Programmiersprache' gleich dazu.
Allerdings wäre ich bei meinem derzeitigen Wissensstand nicht wirklich auf das Problem und die Lösung gekommen.
Die Ergänzung hab ich vorgenommen, und das ganze gleich dann noch in einer Win2000, WinXP und in einer Win7 VM getestet. Und es läuft prima.Zwei kleine Fragen hätte ich jetzt noch. Wo wäre die Ergänzung besser aufgehoben. Ich der CPP-Datei meiner "DLL-Form" oder in der DLL-CPP-Datei wo auch die 'WINAPI DllEntryPoint' Funktion steht. Probiert hab ichs in beiden. Und beidesmal hat es funktioniert. Als zweites, ist die Ergänzung nur in den DLLs nötig die z.B. solche BitButtons beinhalten, oder besser in jeder DLL?
Auf jeden Fall nochmals vielen vielen Dank.
Grüße und Gute Nacht Netzschleicher
P.S. Hab noch schnell den von Dir verlinkten Bericht der Embarcadero QualityCentral Überflogen. Wenn ich das richtig verstehe sollte diese Ergänzung in alle DLLs eingebaut werden. Damit hat sich dann meine zweite Frage geklärt.
Grüße nochmals Netzschleicher
-
Netzschleicher schrieb:
Wo wäre die Ergänzung besser aufgehoben. Ich der CPP-Datei meiner "DLL-Form" oder in der DLL-CPP-Datei wo auch die 'WINAPI DllEntryPoint' Funktion steht.
Ich finde es direkt bei DllEntryPoint() am besten. Das ist allerdings Geschmackssache.
Netzschleicher schrieb:
Als zweites, ist die Ergänzung nur in den DLLs nötig die z.B. solche BitButtons beinhalten, oder besser in jeder DLL?
Dringend nötig ist sie in allen DLLs, die Forms, Frames oder Komponenten beinhalten, die in irgendeiner Form UI-Elemente verwenden, die sich mithilfe des Theming-API selbst zeichnen. Da das ziemlich viele sind, ist eine gute Faustregel: immer dann, wenn du in der DLL irgendwas mit visuellen Komponenten/Frames/Formularen machst. Es immer zu tun schadet allerdings auch nicht.
Der einfachste Weg, dieses Problem zu vermeiden, ist übrigens die Verwendung eines Packages. Packages sind auch nichts anderes als DLLs, nur werden sie von der IDE und während des Ladens etwas anders behandelt (etwa mußt du LoadPackage() statt LoadLibrary() verwenden um sie manuell zu laden). Aber wann immer du Komponenten/Formulare/Frames in eigene Module auslagern willst, sind Packages eigentlich die bessere Wahl, denn dafür sind sie gemacht. Speziell dann, wenn du irgendwann mal deine eigenen Komponenten entwickeln willst: die steckst du in ein Package, installierst es in der IDE, und schon erscheinen deine Komponenten in der Tool-Palette.
-
Ich finde es direkt bei DllEntryPoint() am besten. Das ist allerdings Geschmackssache.
Da hab ich die Ergänzung auch hingepackt. Dann lag ich nicht so falsch.
Da die meisten meiner DLLs Formulare und damit auch Komponenten enthalten werde ich die einfach in alle DLLs einfügen.Über Packages hab ich auch schon etwas gelesen. Auch das es mit denen wohl weniger solche Probs geben soll. Jedoch hab ich mich da nicht weiter vertieft.
Können Packages denn auch so wie DLLs statisch geladen werden und dann mit einer Header-Datei die in den Packages untergebrachten Funktionen bekannt gemacht werden? Nur so nebenbei. Obwohl ich jetzt keine besondere Lust verspüre alles in Packages umzuändern.
-
Netzschleicher schrieb:
Können Packages denn auch so wie DLLs statisch geladen werden und dann mit einer Header-Datei die in den Packages untergebrachten Funktionen bekannt gemacht werden? Nur so nebenbei.
Ja. Um statisch gegen ein Laufzeit-Package zu linken, mußt du die zugehörige .bpi-Datei (nicht die .lib-Datei!) referenzieren; das entspricht also der .lib-Datei einer DLL. (Genaueres hier: http://docwiki.embarcadero.com/RADStudio/de/Packages_und_Standard-DLLs). Die Handhabung ist ansonsten wie die von DLLs, nur daß du mit Packages ein bißchen flexibler bist. Ein Package-Projekt ist sozusagen ein DLL-Projekt und eine statische Bibliothek zugleich: du kannst es als DLL benutzen und statisch oder dynamisch binden, oder du kannst es statisch in deine Executable hineinkompilieren.
Netzschleicher schrieb:
Obwohl ich jetzt keine besondere Lust verspüre alles in Packages umzuändern.
Brauchst du ja nicht; es funktioniert auch so
-
Ich hab das mit dem Package gleich mal in einem Testprojekt versucht. Hat einwandfrei geklappt. Ich musste lediglich nicht die von Dir genannte BPI sondern die erzeugte LIB-Datei dazulinken, dann hat das ganze auch mit einem Package funktioniert. Und das Fehlerfrei ohne die kleine Ergänzung die Du mir letzte Nacht genannt hast.
Wäre das eingentliche Thema meines Treads hier nicht etwas für die FAQ. Ich denke es gibt bestimmt noch mehr Leute wie ich die vielleicht dieses Problem haben.
-
Netzschleicher schrieb:
Ich hab das mit dem Package gleich mal in einem Testprojekt versucht. Hat einwandfrei geklappt. Ich musste lediglich nicht die von Dir genannte BPI sondern die erzeugte LIB-Datei dazulinken, dann hat das ganze auch mit einem Package funktioniert.
Langsam. Die BPI ist die Import-Bibliothek und entspricht der LIB-Datei deiner DLL. Die LIB-Datei eines Packages hingegen entspricht einer statischen Bibliothek - das Laufzeit-Package ist also gar nicht mehr involviert, denn so linkst du den Package-Inhalt in dein Projekt hinein. Das kann auch sinnvoll sein, aber wenn du mehrere Module à la DLLs willst, mußt du die BPI-Datei nehmen.
-
Sorry, hatte gestern noch meinen Fernseher angeschlafen....
Ah, ok. Hab das jetzt nochmal nachvollzogen. Stimmt, wenn ich die LIB-Datei einbinde funktioniert es auch ohne das die BPL vorhanden ist.
Dann muß ich mal stöbern wie ich die BPI-Datei in ein Projekt einbinde. Wenn ich das per #pragma link mache, oder die Datei dem Projekt in der Projektverwaltung hinzufüge, kommt beim Linken immer die Meldung das ein nicht auflösbaren externes Symbol referenziert wurde.Werd das ganze mal als Testprojekt auf der Platte behalten.
Die andere DLL Geschichte funzt jetzt absolut prima.
-
Netzschleicher schrieb:
Dann muß ich mal stöbern wie ich die BPI-Datei in ein Projekt einbinde. Wenn ich das per #pragma link mache, oder die Datei dem Projekt in der Projektverwaltung hinzufüge, kommt beim Linken immer die Meldung das ein nicht auflösbaren externes Symbol referenziert wurde.
Hast du die Funktion denn korrekt mit __declspec(dllexport) definiert? Bei mir gehts dann problemlos.
-
Sch..., ertappt. Hatte vergessen die Header-Datei für den Im- Export zu includieren.
#ifndef _TESTINC #define _TESTINC #ifdef __DLL__ #define __EXPORT_TYPE __declspec(dllexport) #else #define __EXPORT_TYPE __declspec(dllimport) #endif //----------------------------------------------------------------------------- __EXPORT_TYPE void showBPLform(void); //----------------------------------------------------------------------------- #endif
Allerdings konnte ich die BPL-Datei dann nicht linken. Es kamen 74 Linkerfehler mit nicht auflösbaren externen Symbolen. Alle haben mit der VCL zu tun. Ohne die Header-Datei kompiliert und linkt die BPL, allerdings exportiert diese dann meine Beispielfunktion ja nicht.
-
Netzschleicher schrieb:
Allerdings konnte ich die BPL-Datei dann nicht linken. Es kamen 74 Linkerfehler mit nicht auflösbaren externen Symbolen.
Ah, richtig - wenn dein Package die VCL benutzt, mußt du "vcl.bpi" zu den erforderlichen Packages hinzufügen. Desgleichen für weitere Komponenten, die du referenzierst - etwa für die Ribbon-Controls bräuchtest du noch "vclribbons.bpi".
Einfach Rechtsklick im Projektmanager auf "Erfordert", dann .bpi-Datei auswählen. Findest du unter $(BDS)\release .
-
Ah, verstehe. Bis jetzt findet sich bei "Erfordert" lediglich die rtl.bpi.
Hab jetzt die vcl.bpi hinzugefügt und neu kompiliert. Jetzt läuft das Programm.
Supi.
Werd ich mir speichern, als referenz, wenn ich die Packages mal brauche.
Danke sehr.
-
Und wieder ich.
Nachdem mir audacia mit dem Code
void setIsLibrary (void) { System::IsLibrary = true; } #pragma exit setIsLibrary 31
sehr geholfen hat mein Problem mit der AccessViolation beim Beenden meiner Anwendung unter aktiver XP-Theme zu beheben, taucht dieses nun wieder auf.
Ich habe in meiner Anwendung im Hauptmodul zwei Abfragen, mit denen ich prüfe ob die DLLs auch wirklich zu meiner Anwendung gehören, und eine die Abfrägt ob das Datamodul initialisiert ist. Beide Abfragen werfen jeweils mit
throw Exception( <Fehlermeldung> )
eine Exception um das Programm dann zu beenden. Diese Abfragen finden im Konstruktor des Hauptfensters statt. Nun wäre ich wieder für einen Tipp dankbar, um den Fehler auch bei einer Exception zu beheben.
Oder gibt es noch eine bessere Möglichkeit ausser einer solchen Exception das Programm vorzeitig aus dem Konstruktor heraus zu beenden?
Vielen Dank in Voraus, Netzschleicher
-
In meiner Beispielanwendung habe ich jetzt einfach mal im Konstruktor eine Exception geworfen. Das verursacht unter XP nach wie vor keine AV. Bitte zeig mal genau, was du gemacht hast. (Du kannst auch gerne wieder ein Projekt hochladen.)