![]() |
Abfangen von Exceptions bei LoadLibrary
Hallo,
in meiner 2D-Grafikbibliothek gibt es eine Klasse, die nach allen verfügbaren Plugin-DLLs sucht. Dabei wird jede DLL in einem angegebenen Verzeichnis einzeln geladen und dann überprüft, ob sie bestimmte Funktionen exportiert. Mein Problem ist nun das folgende: Gibt es ein Problem beim Laden der Bibliothek (wird zum Beispiel eine DLL, die die DLL benötigt nicht gefunden), so wird eine Exception geworfen. Das will ich nicht - die Bibliothek soll einfach links liegen gelassen werden. Das kuriose ist nun, dass die Exception nur geworfen wird, wenn das Programm nicht aus dem Debugger heraus ausgeführt wird. Mein Code:
Delphi-Quellcode:
Eine Beispiel-Exception (tritt auf, wenn eine von AndorraDX93D.dll benötigte Komponente gelöscht wurde):
res := FindFirst(dir+'*Andorra*'+Extension, faAnyFile, searchrec);
ahandle := 0; while (res = 0) do begin try try {$IFDEF Win32} ahandle := Windows.LoadLibrary(PChar(dir+searchrec.Name)); //<--- Hier wird die Exception (siehe unten) geworfen (vermute ich) {$ELSE} ahandle := dynlibs.LoadLibrary(PChar(dir+searchrec.Name)); {$ENDIF} except //Load the next module if something didn't work... Continue; end; if AHandle <> 0 then begin @fileinfo := GetProcAddress(ahandle, 'Andorra2DLibraryInformation'); //If procedure exists, it must be an Andorra 2D Plugin Library if @fileinfo <> nil then begin //Read fileinfo fileinfo(info); //The library must be compatible if info.LibVersion = LibraryVersion then begin //Call callback and pass name and information CallBack(searchrec.Name, info); end; end; end; finally if AHandle <> 0 then FreeLibrary(AHandle); end; res := FindNext(searchrec); end;
Code:
Der komplette Code:
---------------------------
Novcl: NoVCL.exe - Komponente nicht gefunden --------------------------- Die Anwendung konnte nicht gestartet werden, weil d3dx9_31.dll nicht gefunden wurde. Neuinstallation der Anwendung könnte das Problem beheben. --------------------------- OK --------------------------- ![]() Nach dieser Fehlermeldung läuft das Programm munter weiter. Dieses Verhalten hat schon einige Entwickler, die mit meiner Bibliothek arbeiten irritiert. Ich schätze, dass das Problem darin liegt, dass die Exception in der geladenen DLL geworfen wird und daher von meinem Hauptprogramm nicht abgefangen werden kann. Vielen Dank im Voraus, Andreas |
Re: Abfangen von Exceptions bei LoadLibrary
Interessant. Weißt du näheres über die DLL? Hast du mal versucht, das mit einer eigenen DLL nachzustellen (am besten einer nicht-Delphi-DLL)?
|
Re: Abfangen von Exceptions bei LoadLibrary
Ja, die DLL kenn ich näher, habe sie selbst geschrieben. Die AndorraDX93D.dll lädt die d3dx9_31.dll statisch.
Das gleiche Problem habe ich aber auch mit anderen DLLs, die DLLs statisch laden. |
Re: Abfangen von Exceptions bei LoadLibrary
Dir ist bewusst, dass durch dein Continue das FindNext() nie aufgerufen wird und er somit in einer Endlosschleife bei der gleichen DLL hängt?
Die Meldung scheint mir auch eher vom Windows PE Loader zu kommen aufgrund einer statischen Abhängigkeit anstatt von dem oben geposteten Quellcode. |
Re: Abfangen von Exceptions bei LoadLibrary
Wenigstens vielleicht mal irgendeine Reaktion?
|
Re: Abfangen von Exceptions bei LoadLibrary
Hallo,
Danke für den Hinweis mit dem "continue" und "FindNext" - ich habe das behoben. Trotzdem weiß ich immer noch nicht, wie ich den PE-Loader davon überzeugen kann keine Exceptions zu werfen. Dass dieser die Quelle für das Problem ist, ist logisch. Andreas |
Re: Abfangen von Exceptions bei LoadLibrary
Nach der Methode RTFM, die ich beim erstellen dieses Threads leider auf eine Googlesuche beschränkte, habe ich eine Lösung für das Problem gefunden:
Delphi-Quellcode:
Siehe
{$IFDEF WIN32}
//Prevent the library from showing any error messages while loading. SetErrorMode(SEM_FAILCRITICALERRORS); {$ENDIF} try FHandle := LoadLibrary(PChar(AName)); finally {$IFDEF WIN32} SetErrorMode(0); {$ENDIF} end; ![]() Ich hoffe, dass dies jemandem weiterhilft, der das selbe Problem hat wie ich. |
Re: Abfangen von Exceptions bei LoadLibrary
Hallo,
dafür gibts doch die Funktion SafeLoadLibrary aus SysUtils. Die sichert sogar das FPU-Steuerwort. Die Funktion hat 2 Parameter, der erste ist der Dateiname der DLL, der zweite Parameter gibt der ErrorMode an. Vorgabe ist dafür SEM_NOOPENFILEERRORBOX, um das Anzeigen eines Fehlerdialogs zu verhindern. Ciao Chris |
Re: Abfangen von Exceptions bei LoadLibrary
Altbekannt, da der PE Loader abhängig von dem Modus still oder laut das ganze ausgibt. Aber anscheinend ist das damals bei mir wohl untergegangen.
Aber mal ein zusätzlicher Hinweis: DLLs die in MS Visual Studio C++ geschrieben wurden haben in ihrem Startup Code die Eigenheit die FPU Exception Mask umzustellen. Dadurch werden illegale Operationen still und heimlich von der FPU behandelt, also es wird NaN und INF berechnet anstatt einer Exception. Delphi wiederrum setzt Exceptions voraus und kommt dadurch spätestens bei irgendwelchen Fließkommaberechnungen in die Bedrängnis, wenn es von NaN oder INF etwas berechnen soll. Von daher sollte hier nochmals explizit ![]() Sorry nochmals dass ich damals nicht auf die WinAPI Funktion hingewiesen hatte. @Chris.R: SafeLoadLibrary() wurde für die von mir beschriebene Gegebenheit eingeführt und mit Delphi 7 um den zweiten Parameter erweitert, da dieser zuvor nicht von außen steuerbar war. |
Re: Abfangen von Exceptions bei LoadLibrary
Danke für den Hinweis mit dem "SafeLoadLibrary" aus der Unit "SysUtils", ich wusste nicht, dass Delphi/FreePascal eine solche Methode bereits anbietet - eine Abhängigkeit zur WinAPI weniger in meinem Quellcode. :thumb:
Ich habe nur Delphi-DLLs getestet und vom Umbiegen des FPU-Steuerworts wusste ich nichts - das hat sich nun geändert. Edit: Da FreePascal "SafeLoadLibrary" unvollständig implementiert, habe ich das jetzt in eine neue "SafeLoad" Prozedur geschrieben:
Delphi-Quellcode:
Edit2:
uses
{$IFDEF WIN32}Windows{$ELSE}dynlibs{$ENDIF}; function AcLoadLibrary(AModule: string): TAcHandle; var fpu_word: Word; begin //Store the fpu control word as some dlls might corrupt it when they are not //loaded properly fpu_word := get8087cw; {$IFDEF WIN32} //On Windows prevent the PE-Loader from showing up any exceptions SetErrorMode(SEM_FAILCRITICALERRORS); {$ENDIF} try result := LoadLibrary(PChar(AModule)); finally {$IFDEF WIN32} //Reset the error mode to default SetErrorMode(0); {$ENDIF} //Reset the FPU word set8087cw(fpu_word); end; end; SEM_NOOPENFILEERRORBOX, was bei "SafeLoad" der Default ist, unterdrückt das Anzeigen der Fehlermeldung leider nicht! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:14 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