Announcement

Collapse
No announcement yet.

Warnung: Standardformular in DLL führt zu Zugriffsverletzung

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Warnung: Standardformular in DLL führt zu Zugriffsverletzung

    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.

  • #2
    Hallo,

    das Problem mit den USER-Ressourcen hat nichts mit der DLL zu tun. Eine mit Delphi compilierte Anwendung verpackt die Formulare (DFM) als Ressourcen und hängt diesen Block an das ausführbare Modul an. Windows lädt jedoch die Ressourcen nicht gleich beim Programmstart, sondern erst beim ersten Zugriff darauf.

    Wenn nun die Formulare nicht bereits in der Projektdatei (DPR) automatisch erzeugt werden, sondern erst unmittelbar vor dem Anzeigen und nach dem Schliessen des Formulars wieder zerstört werden, bringt das Auslagern in eine DLL überhaupt keine Vorteile. Eine DLL hätte erst dann Vorteile, wenn die Formulare von verschiedenen Anwendungen gemeinsam genutzt werden und es auf jedes Byte eingesparten Festplattenspeicherplatz ankommt.

    Ich würde daher auf die DLLs verzichten und die Formulare <b>nicht</b> automatisch erzeugen lassen, sondern erst unmittelbar vor dem Aufruf

    Comment


    • #3
      Hi

      Hm, was verstehst Du als "Vorlage" ? Ich nehme an Du beziehst Dich auf die Arbeitsweise eines "inherited" in den DFM Resourcen.
      Da gibt es aber keine "Dynamisch geladenen Vorlagen". Das inherited der DFM sagt dem Formularlageprocess das zuerst die DFM Vorlage der Mutterklasse geladen werden muß. Vorstellen kann man sich das so:

      <pre>

      type
      TA = class
      property Caption;
      end;

      TB = class(TA)
      property Text;
      end;

      TC = class(TB)
      property Tag;
      end;

      nun die DFM's vereinfacht:

      A:
      object TA
      Caption = 'test'

      B:
      inheritd object TB
      Text = 'Forum';

      C:
      inherited object TC
      Tag = 1234

      </pre>

      beim Laden muss nun eine TC Instance vollständig initialisiert werden, d.h. alle 3 Eigenschaften Caption, Text, Tag. Diese Eigenschaften sind aber auf 3 DFM's verteilt gespeichert.

      Als erste wird eine vollständige Instance vom Typ TC erstellt. Das Formulare existiert also jetzt im Speicher. Aber die Eigenschaften beinhalten noch falsche Werte.

      Nun, werden alle DFM's nach der richtigen Reihenfolge geladen. Diese DFM's sind sowas wie sortierte INI Dateien, das TReader Object iteriert durch die DFM's, und setzt die gelesenen Eigenschaftswerte in die aktuelle TC Instance.

      Nach diesem Ladeprocess steht im Speicher NUR EINE vollständig initialisierte Instance vom Typ TC. Also NUR EIN Formular, keine Vorfahren etc.
      Eine Vorlage gibt es einfach NICHT ! Die einzigste real wichtige Vorlage sind die Klassentypdefinitionen gespeichert im Codesegment der EXE/DLL. Diese Klassendef. enthalten nichts anders als die VMT,DMT,Interfaces etc einer Klasse. TC enthält also einen Zeiger auf TB usw. Dadurch kann der komplette Klassetyp TC aus TC + TB + TA zusammengesetzt werden. Alle Eigenschaften, published Methoden usw. sind also als Informationsrecord in der EXE gespeichert.

      Gruß Hage

      Comment

      Working...
      X