MDI-Child aus DLL laden

Dario Linsky

Erfahrenes Mitglied
Da ich meine Anwendung so klein und kompakt wie möglich halten möchte, hab ich mir überlegt, nur das Hauptformular (FormStyle := fsMDIForm) in die eigentliche Anwendung zu compilieren. Alle anderen Formulare, vor allem die MDI-Children möchte ich gerne in dynamisch ladbare Bibliotheken auslagern.
Dazu hab ich den entsprechenden Code gefunden und einigermassen angepasst. Im Hauptformular wird das MDI-Child aus der DLL geladen:
Code:
var
  dllHandle: THandle;
  OpenMDIChild: procedure (PApp: TApplication; PForm: TForm); stdcall;
begin
  DllHandle := LoadLibrary('ProjectDll');
  @OpenMDIChild := GetProcAddress(dllHandle, 'ShowMDI001');
  if @OpenMDIChild <> nil then
  begin
    OpenMDIChild(Application, Self);
  end;
end;
Dadurch wird dann einfach nur eine Funktion aus der DLL aufgerufen, die das Formular dann erzeugt:
Code:
procedure ShowMDI001(PApp: TApplication; PForm: TForm); export; stdcall;
var
  Form: TForm001;
begin
  Application := PApp;
  Form := TForm001.Create(PForm);
  Form.ParentForm := PForm;
  Form.ParentApplication := PApp;
  Form.Show;
end;
Die beiden Felder "ParentForm" und "ParentApplication" des Formulars sind vom Typ TForm und TApplication, und werden im public-Abschnitt vom MDI-Child definiert.
Wenn ich das laufen lasse, dann funktioniert das wie gesagt auch erstmal problemlos. Nur beim Beenden des Programms bekomm ich immer drei Laufzeitfehler. Beim Debuggen kann ich nichts finden, aber irgendwo läuft das Programm nicht ganz sauber.
 

Dario Linsky

Erfahrenes Mitglied
Ich hab's inzwischen schon selber rausgefunden. Für alle, die es vielleicht interessiert, schreib ich noch mal, wie das fehlerlos funktioniert.
Wenn man das MDI-ChildForm aus der DLL zur Laufzeit erzeugt, dann muss das Application-Objekt in der DLL die eigentliche ausführbare Anwendung enthalten - also die eigentliche Host-Anwendung.
Das hatte ich auch schon erledigt. Aber damit die DLL fehlerfrei beendet werden kann, muss nach dem Erstellen des Formulars das Objekt wieder auf den ursprünglichen Zustand zurückgesetzt werden. Sonst wird die DLL nicht richtig beendet und löst beim Beenden der Host-Anwendung einen Fehler aus.
Lange Rede, kurzer Sinn - die Funktion in der DLL muss so aussehen:
Code:
procedure ShowMDI001(PApp: TApplication; PForm: TForm); export; stdcall;
var
  Form: TForm001;
  dllApp: TApplication;
begin
  dllApp := Application;
  Application := PApp; // das Application-Objekt auf die Host-Anwendung einstellen
  Form := TForm001.Create(PForm); // MDI-Child erzeugen
  Form.ParentForm := PForm;
  Form.ParentApplication := PApp;
  Form.Show;
  Application := dllApp; // das Application-Objekt zurücksetzen, damit die DLL vernünftig beendet werden kann
end;