AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Abfangen von Exceptions bei LoadLibrary
Thema durchsuchen
Ansicht
Themen-Optionen

Abfangen von Exceptions bei LoadLibrary

Ein Thema von igel457 · begonnen am 22. Dez 2008 · letzter Beitrag vom 21. Sep 2009
Antwort Antwort
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#1

Abfangen von Exceptions bei LoadLibrary

  Alt 22. Dez 2008, 18:05
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:
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;
Eine Beispiel-Exception (tritt auf, wenn eine von AndorraDX93D.dll benötigte Komponente gelöscht wurde):
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  
---------------------------
Der komplette Code:
http://andorra.cvs.sourceforge.net/v...ew=markup#l_50

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
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 22. Dez 2008, 18:24
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)?
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#3

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 22. Dez 2008, 19:05
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.
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#4

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 22. Dez 2008, 20:17
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.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#5

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 28. Dez 2008, 00:47
Wenigstens vielleicht mal irgendeine Reaktion?
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#6

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 31. Dez 2008, 11:24
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
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#7

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 21. Sep 2009, 21:13
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:
{$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;
Siehe MSDN-Library durchsuchenLoadLibrary

Ich hoffe, dass dies jemandem weiterhilft, der das selbe Problem hat wie ich.
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Chris.R

Registriert seit: 8. Sep 2009
Ort: Nürnberg
68 Beiträge
 
Delphi 2010 Professional
 
#8

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 21. Sep 2009, 22:13
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
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#9

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 21. Sep 2009, 22:16
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 Delphi-Referenz durchsuchenSafeLoadLibrary() erwähnt werden. Werden DLLs komplett statisch geladen kommt der Startup Code der App (somit Delphi der die Maske umsetzt) erst nach dem Startup Coder statisch gelinkten DLLs, da der PE Loader diese Abhängigkeiten vorher auflösen muss. Wenn eine DLL oder auch eine solche DLL Kette aber dynamisch geladen wird hat man ein Problem. Von daher der Hinweis.

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.
  Mit Zitat antworten Zitat
Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#10

Re: Abfangen von Exceptions bei LoadLibrary

  Alt 21. Sep 2009, 22:44
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.

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:
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;
Edit2:
SEM_NOOPENFILEERRORBOX, was bei "SafeLoad" der Default ist, unterdrückt das Anzeigen der Fehlermeldung leider nicht!
Andreas
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:28 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