Folgende Situation führt nach meiner Erfahrung zur Laufzeit zum Absturz:
Im Projekt VS.Exe ist eine Exception der Klasse C0000005 aufgetreten. Meldung: access violation at 0x01411708: read of address 0x01411708. 'Laufzeitfehler suchen' zeigt dort aber nur '????' an; das Programm kann in der IDE nur mit 'Programm zurücksetzen' und vom Desktop aus durch Ctrl-Alt-Del beendet werden.
Konstruktion von Programm und DLL: Es gibt eine Standardvorlage für Formulare: type TGForm = Class(TForm). Alle Formulare sind davon abgeleitet: type TExeMainForm = class(TGForm) bzw. type TDLLForm1 = class(TGForm) [in DFM steht immer inherited]. Die DLL wird erst zur Laufzeit geladen:
var hLib: THandle; // hLib := LoadLibrary( vsDllSystem ); // if hLib > 32 // then begin // @SystemVerteiler := GetProcAddress( hLib, 'SystemVerteiler' ); // try // if @SystemVerteiler <> nil // then SystemVerteiler( Variante, Global, AktAdressen ); // finally // FreeLibrary( hLib ); //end; // end;
Durch SystemVerteiler wird ein Zusatzformular erzeugt und ShowModal bearbeitet. Nach Beendigung dieses Formulars wird FreeLibrary ausgeführt; unmittelbar anschließend folgt die o.g. Exception. WinSight zeigt, dass das Zusatzformular ordnungsgemäß aufgelöst und danach die DLL entladen wird; aber kein weiterer Befehl wird ausgeführt.
Versuch einer Erklärung: Obwohl das Standardformular TGForm sowohl in der EXE als auch in der DLL enthalten ist, wird durch FreeLibrary offensichtlich auch die Vorlage im Arbeitsspeicher der EXE-Datei entladen.
Provisorische Lösung: Die DLL wird zwar erst bei Bedarf geladen; sie wird aber erst am Ende des Programms entladen. Also:
EXE enthält eine globale Variable DLLInstanz. Die DLL wird dann wie folgt gestartet:
if DLLInstanz <= 32 then DLLInstanz := LoadLibrary( vsDllSystem ); // if DLLInstanz > 32 // then begin // @SystemVerteiler := GetProcAddress( DLLInstanz, 'SystemVerteiler' ); // try // if @SystemVerteiler <> nil // then SystemVerteiler( Variante, Global, AktAdressen ); // finally // ; {ohne Ausführung} //end; // end;
Erst unter EXEMainFormClose wird die DLL entladen: if DLLInstanz > 32 // then FreeLibrary(DLLInstanz).
Dieses Verfahren funktioniert; aber dadurch steht die DLL natürlich unnütz lange im Arbeitsspeicher.
Hinzu kommt, dass mein Programm bisher schon viele User-Ressourcen verlangt; dieses Problem wird durch das DLL-Problem natürlich verschärft.
Gibt es bessere Lösungen? Danke für Ratschläge! Jürgen
PS. Ich arbeite unter Windows 95 (Version 4.00.950) mit Delphi 5.1 Professional vom 03.02.2000.
Im Projekt VS.Exe ist eine Exception der Klasse C0000005 aufgetreten. Meldung: access violation at 0x01411708: read of address 0x01411708. 'Laufzeitfehler suchen' zeigt dort aber nur '????' an; das Programm kann in der IDE nur mit 'Programm zurücksetzen' und vom Desktop aus durch Ctrl-Alt-Del beendet werden.
Konstruktion von Programm und DLL: Es gibt eine Standardvorlage für Formulare: type TGForm = Class(TForm). Alle Formulare sind davon abgeleitet: type TExeMainForm = class(TGForm) bzw. type TDLLForm1 = class(TGForm) [in DFM steht immer inherited]. Die DLL wird erst zur Laufzeit geladen:
var hLib: THandle; // hLib := LoadLibrary( vsDllSystem ); // if hLib > 32 // then begin // @SystemVerteiler := GetProcAddress( hLib, 'SystemVerteiler' ); // try // if @SystemVerteiler <> nil // then SystemVerteiler( Variante, Global, AktAdressen ); // finally // FreeLibrary( hLib ); //end; // end;
Durch SystemVerteiler wird ein Zusatzformular erzeugt und ShowModal bearbeitet. Nach Beendigung dieses Formulars wird FreeLibrary ausgeführt; unmittelbar anschließend folgt die o.g. Exception. WinSight zeigt, dass das Zusatzformular ordnungsgemäß aufgelöst und danach die DLL entladen wird; aber kein weiterer Befehl wird ausgeführt.
Versuch einer Erklärung: Obwohl das Standardformular TGForm sowohl in der EXE als auch in der DLL enthalten ist, wird durch FreeLibrary offensichtlich auch die Vorlage im Arbeitsspeicher der EXE-Datei entladen.
Provisorische Lösung: Die DLL wird zwar erst bei Bedarf geladen; sie wird aber erst am Ende des Programms entladen. Also:
EXE enthält eine globale Variable DLLInstanz. Die DLL wird dann wie folgt gestartet:
if DLLInstanz <= 32 then DLLInstanz := LoadLibrary( vsDllSystem ); // if DLLInstanz > 32 // then begin // @SystemVerteiler := GetProcAddress( DLLInstanz, 'SystemVerteiler' ); // try // if @SystemVerteiler <> nil // then SystemVerteiler( Variante, Global, AktAdressen ); // finally // ; {ohne Ausführung} //end; // end;
Erst unter EXEMainFormClose wird die DLL entladen: if DLLInstanz > 32 // then FreeLibrary(DLLInstanz).
Dieses Verfahren funktioniert; aber dadurch steht die DLL natürlich unnütz lange im Arbeitsspeicher.
Hinzu kommt, dass mein Programm bisher schon viele User-Ressourcen verlangt; dieses Problem wird durch das DLL-Problem natürlich verschärft.
Gibt es bessere Lösungen? Danke für Ratschläge! Jürgen
PS. Ich arbeite unter Windows 95 (Version 4.00.950) mit Delphi 5.1 Professional vom 03.02.2000.
Comment