Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Dll Forms... oder ligt es nicht daran ?? (https://www.delphipraxis.net/97909-dll-forms-oder-ligt-es-nicht-daran.html)

dor557 18. Aug 2007 14:43


Dll Forms... oder ligt es nicht daran ??
 
erst mal meine dateien :

die Library :

Delphi-Quellcode:
library Kundendaten;


uses
  SysUtils,
  Classes,
  forms,
  kMain in 'kMain.pas' {KundendatenF};
{$E dll}

{$R *.res}

Procedure PluginMain(Befehl : PChar; Parameter : Pointer); stdcall;
begin
  KundenDatenF := TKundenDatenF.Create(Application);
  try
    KundenDatenF.Show;
  finally
    KundenDatenF.Release;
  end;
end;

exports
 PluginMain;

begin
end.
so nun die KMain.pas :

Delphi-Quellcode:
unit kMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TKundendatenF = class(TForm)
    Button1 : TButton;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  KundendatenF: TKundendatenF;

implementation

{$R *.dfm}

end.
das sind die Daten gewesen aus der DLL.

Nun mache ich in der Hauptanwendung Folgendes :
ich habe mir eine unit Plugins angelegt die so aussieht :

Delphi-Quellcode:
unit plugins;

interface
uses SysUtils, windows, Dialogs, forms;

type TPlugin = procedure(Befehl : PChar; Parameter : Pointer); stdcall;
procedure PluginMain(Befehl : PChar; Parameter : Pointer);

implementation

procedure PluginMain(Befehl : PChar; Parameter : Pointer);
var Plugin: TPlugin;
    Handle: THandle;
begin
  Handle:=LoadLibrary(PChar(ExtractFilePath(ParamStr(0))+'..\lib\kundendaten.dll'));
  if Handle <> 0 then begin
    @Plugin := GetProcAddress(Handle, 'PluginMain');
    if @Plugin <> nil then begin
      Plugin(Befehl, Parameter);
    end;
    FreeLibrary(Handle);
  end;
end;

end.
und das Hauptfenster in der anwendung hat folgendes aussehen :

Delphi-Quellcode:
unit HostFenster;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation
uses plugins;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  PluginMain('',nil);
end;

end.
jetzt sobald ich auf den Button1 klicke um das Plugin zu starten bekome ich folgenden Fehler (Keine Fehlermeldung)

Er erstellt das Formular. und das Verschwindet sogleich wieder.. Kann also nicht daran arbeiten.

Kann mir jemand sagen warum ?

gruss Sascha

Ghostwalker 18. Aug 2007 14:58

Re: Dll Forms... oder ligt es nicht daran ??
 
Du gibst die DLL gleich nach dem Erstellen und dem Anzeigen der Form wieder frei. Dadurch wird auch das Formular beendet und existiert demzufolge auch nicht mehr.

jbg 18. Aug 2007 15:00

Re: Dll Forms... oder ligt es nicht daran ??
 
Zitat:

KundenDatenF.Release;
Das ist schon mal ganz schlecht. Denn dadurch wird das Formular erst beim nächsten Application.ProcessMessages oder der Haupt-Botschaftsschleife freigegeben. Zu der Zeit ist aber die DLL nicht mehr im Speicher.

Release sollte man nur in Event-Handlern benutzen, die in dem betroffenen Formular deklariert sind. Ansonsten .Free verwenden.

dor557 18. Aug 2007 15:03

Re: Dll Forms... oder ligt es nicht daran ??
 
das
Delphi-Quellcode:
KundenDatenF.Release;
Ändert nicht ans meinem Problem.

auch wenn ich das nicht da stehen habe schliesst er das gleich wieder....

:gruebel:

sniper_w 18. Aug 2007 15:07

Re: Dll Forms... oder ligt es nicht daran ??
 
Versuch ohne Owner:
Delphi-Quellcode:
TKundenForm.Create(nil);

Ghostwalker 18. Aug 2007 15:14

Re: Dll Forms... oder ligt es nicht daran ??
 
Delphi-Quellcode:
procedure PluginMain(Befehl : PChar; Parameter : Pointer);
var Plugin: TPlugin;
    Handle: THandle;
begin
  Handle:=LoadLibrary(PChar(ExtractFilePath(ParamStr(0))+'..\lib\kundendaten.dll'));
  if Handle <> 0 then begin
    @Plugin := GetProcAddress(Handle, 'PluginMain');
    if @Plugin <> nil then begin
      Plugin(Befehl, Parameter);
    end;
    FreeLibrary(Handle);
  end;
end;
Da liegt dein Problem. Deine Plugin-Routine macht nichts anderes als das Formular zu Erzeugen und anzuzeigen (im Speicherbereich der DLL). Danach springt sie zurück und du gibst die DLL frei (und damit auch das Formular). Was soll er also noch anzeigen ?

Formulare in DLL's ist eh eine sehr kritische Sache (such mal hier in der DP nach den Stichwörtern Plugin und Form).

dor557 18. Aug 2007 15:20

Re: Dll Forms... oder ligt es nicht daran ??
 
was ich nicht verstehe warum wartet die anwendung nicht auf eine Bestätigung der dll das das Formular mit close oder release geschlossen wurde ??

Ich kann auf jeden fall nichts auf dem erstellten Formular anklicken. Auch wenn ich es als eine Funktion mache nicht.

Wollte mit ShowModal arbeiten aber sobald ich das verwende bekomme ich die meldung das aus einem Sichtbaren Formular kein Modales gemacht werden kann.

Auch mit
Delphi-Quellcode:
TKundenForm.Create(nil);
bekomme ich eine Fehlermeldung.

Irgend wie komisch das ganze. werde nachher mal schauen nach dll form in der Suche. Aber wenn jemand eine Andre lösung hat bin ich Ganz Auge :mrgreen:

Apollonius 18. Aug 2007 15:35

Re: Dll Forms... oder ligt es nicht daran ??
 
Du brauchst auf jeden Fall ShowModal. Sonst wird das Formular ja direkt danach freigegeben. Versuch mal vor dem ShowModal noch ein Hide.

dor557 18. Aug 2007 16:06

Re: Dll Forms... oder ligt es nicht daran ??
 
Auch schon versucht. Geht auch nicht.

Keine ahnung was da nicht so funktioniert wie es soll...

Bin etwas am ende meines Lateins.

Apollonius 18. Aug 2007 16:08

Re: Dll Forms... oder ligt es nicht daran ??
 
Was heißt "geht nicht"? Selber Fehler würde mich wundern, da das Fenster ja versteckt wurde.

Die Muhkuh 18. Aug 2007 16:09

Re: Dll Forms... oder ligt es nicht daran ??
 
Sascha, schnapp mal eine Runde frische Luft, dann sieht Du das Problem auch ;-)

Du greifst auf die DLL zu, rufst die Procedure auf und gibst danach die DLL wieder frei, welche auch die Form in der DLL zerstört. Auf was sollte bitte gewartet werden?

Du musst auf die DLL zugreifen und erst später (Programmende?) wieder per FreeLibrary schließen.

[edit]Ich würde Dir noch vorschlagen, eine Klasse zu schreiben, die erstmal alle dlls im Plugin-Ordner in eine Liste einfügt. Sobald dann ein Plugin benötigt wird, lädt die Klasse die DLL in den Speicher. Bevor nun die DLL-Form geschlossen wird, sendet diese eine Nachricht an das Hauptprogramm, darauf hin schließt sich die Form und die Klasse gibt per FreeLibrary die DLL frei. Soweit der theoretische Ansatz. Jetzt ist Dein Grips gefragt. :) [/edit]

dor557 18. Aug 2007 16:20

Re: Dll Forms... oder ligt es nicht daran ??
 
Wie soll ich denn eine Nachricht an die Dll schicken ?? oder von der DLL in das Hauptprogramm.

Etwa mit Messages ?? wenn ja das habe ich noch nie gemacht und kenne mich damit nicht aus.

Aber wenn jemand einen Rat hat oder eine Tutorial dann würde das Helfen..

Ich versuch mal die DLL zu öffnen ohne das Befreien vom speicher !

Gruss Sascha

Die Muhkuh 18. Aug 2007 16:25

Re: Dll Forms... oder ligt es nicht daran ??
 
Zitat:

Zitat von dor557
Ich versuch mal die DLL zu öffnen ohne das Befreien vom speicher !

Einfach das FreeLibrary nicht gleich hinterher aufrufen, sondern "wo anderst" = Programmende oder beim Drücken auf einen zweiten Knopf.

Zur Kommunikation DLL <-> Hauptprogramm empfehle ich Dir diesen und die nachfolgenden Posts:
Klick mich

dor557 18. Aug 2007 16:30

Re: Dll Forms... oder ligt es nicht daran ??
 
Habe Jetzt die Zeile :

Delphi-Quellcode:
KundendatenF.Release;
Procedure gelöscht.

die Handle Variable als Global variable gesetzt und einen 2. Button auf das Hauptformular gesetzt.

Es ist richtig das ich automatisch den speicher wieder frei gebe.

Nun gebe ich den Speicher bei Klick auf den 2. Button wieder frei. und das Formular Funktioniert.

Aber wie kann ich das vermeiden das ich extra einen Button anklicken muss.

Habe schon oft von msg gehört. Kann ich an die DLL eine Message schicken bzw. von der DLL an das HauptProgramm ??

Die Muhkuh 18. Aug 2007 16:34

Re: Dll Forms... oder ligt es nicht daran ??
 
Hi Sascha,

ich würde, wie gesagt, erst mal eine Klasse "drumrum" bauen, die die DLLs aufruft. Ich denke, dass Du ja nicht nur ein PlugIn haben wirst. Lieber jetzt ein bisschen mehr Zeit (und Nerven) investieren, aber dafür hast Du dann hinterher einen sauberen, erweiterbaren Aufbau einer PlugIn-Klasse. Aber das ist Dir überlassen (ich kenne ja Dein Projekt nicht).

Zum Message verschicken, schau Dir mal Hier im Forum suchenSendMessage bzw. Hier im Forum suchenPostMessage. Beachte allerdings, dass Du ein Handle brauchst, an dass die Nachricht geschickt wird. Das heißt, dass Du der DLL das Handle des Hauptprogramm mitliefern musst.

dor557 18. Aug 2007 16:37

Re: Dll Forms... oder ligt es nicht daran ??
 
Muhkuh : Du hast recht. Aber auch das ist neuland für mich. Begebe mich da in ein Komplettes Neuland für mich.

Habe biser immer nur formulare gemacht und das als Exe Fertig. da habe ich weder Messages gebraucht noch Klassen erstellen müssen.

Ist der Link den du mir da genannt hast eine Anleitung für die Klassen ?? oder ist das etwas anderes ?

Die Muhkuh 18. Aug 2007 16:43

Re: Dll Forms... oder ligt es nicht daran ??
 
Hi Sascha,

der Link (im vorherigen Post), ist eine Anleitung für ein Interface, dass die Kommunikation Hauptprogramm <-> DLL abdeckt.

Klassen an sich, sind nichts "schweres". Hier hab ich noch ein Link für Dich, der Dir das ganze ein bisschen näher bringt.

DeddyH 18. Aug 2007 16:47

Re: Dll Forms... oder ligt es nicht daran ??
 
Ich hab da auch noch nen guten Link zu Ollis HP.

dor557 25. Aug 2007 18:55

Ergebnis bis jetzt !
 
Also habe nun Lektüre gelesen und gemacht und getan und habe folgendes zusammen bekommen.

Hauptprogramm bestehend aus folgenden dateien :
MainF.pas
Interfaces.pas
filefinder.pas (werde ich aber mal nicht mit hinzufügen. denke sieht jeder selbst was der machen soll)

interfaces.pas :
Delphi-Quellcode:
unit interfaces;

interface
 uses classes, forms;
const
  IID_Plugin: TGUID = '{664AAC6B-BF3B-4539-8682-1C33AC692D62}';
  IID_PluginForm: TGUID = '{70B82481-A4E5-4E3F-BAF3-1697EA771FAD}';
  IID_App: TGUID = '{AC519934-9997-432C-9055-E80FD001F502}';

type
  IPlugin = Interface(IInterface)
    ['{664AAC6B-BF3B-4539-8682-1C33AC692D62}']
    function GetName: PChar; stdcall;
    function GetVersion: Integer; stdcall;
  End;

  IPluginForm = Interface(IInterface)
    ['{70B82481-A4E5-4E3F-BAF3-1697EA771FAD}']
  End;


implementation

end.
MainF.pas
Delphi-Quellcode:
unit MainF;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Menus, ActnList, interfaces, filefinder, inifiles;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    Programm1: TMenuItem;
    Beenden1: TMenuItem;
    Plugin1: TMenuItem;
    ActionList1: TActionList;
    Action1: TAction;
    Memo1: TMemo;
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Beenden1Click(Sender: TObject);
    procedure Action1Execute(Sender: TObject);
  private
//    app: IApp;
    hDLL : HWND;
    iPlg: IPlugin;
    iPlgForm : IPluginForm;
  public
    { Public-Deklarationen }
  end;


var
  Form1: TForm1;
  AktDll : Integer;
  ProgDir : String;
  LibDir : String;
implementation

{$R *.DFM}

procedure TForm1.Action1Execute(Sender: TObject);
type
  TProcInitPlg = function(PApp: TApplication; PForm: TForm): IPluginForm; stdcall;
var  fProc: TProcInitPlg;
begin
  @fProc := GetProcAddress(hDLL, 'RunPlugin');
  if fProc(Application,Form1) <> nil then
  begin
    iPlgForm := fProc(Application,Form1);
  end;
end;

procedure TForm1.Beenden1Click(Sender: TObject);
begin
  Close;
end;

procedure TForm1.FormCreate(Sender: TObject);
type
  TProcInitPlg = function: IPlugin; stdcall;
var
  fProc: TProcInitPlg;
  New_Entry_Plugin : TMenuItem;
begin
  ProgDir := extractfilepath(paramstr(0));
  LibDir := copy(ProgDir,0,Pos('bin',ProgDir)-1) + 'lib\';
  messageDlg('folgender Pfad wird durchsucht : ' + LibDir, mtInformation, [mbOK],0);
  Memo1.Lines := FindPlugins(LibDir);
  // Bibliothek laden und Interface holen
  messageDlg('Versuche folgende DLL zu laden : ' + LibDir + Memo1.Lines[0], mtInformation, [mbOK],0);
  hDll := LoadLibrary(PCHAR(libdir + Memo1.Lines[0]));
  @fProc := GetProcAddress(hDLL, 'InitPlugin');
  if fProc <> nil then
  begin
    iPlg := fProc;
    New_Entry_plugin := TMenuItem.Create(self);
    Action1.Caption := PCHAR(iPlg.GetName);
    New_Entry_Plugin.Action := Action1;
    Plugin1.Add(New_Entry_Plugin);
  end;


end;

procedure TForm1.FormDestroy(Sender: TObject);
var i : Integer;
begin
 // PlugIn zerstören
  iplg := nil;
  iPlgForm := nil;
 //  Bibliothek entladen
  FreeLibrary(hDLL);
 //  Application-Interface zerstören
//  app := nil;
end;

end.
nun die dll :
kMain.pas
interfaces.pas
kundendaten.dpr / projektdatei

so nun erstmal die dpr
Delphi-Quellcode:
library Kundendaten;


uses
  SysUtils,
  Classes,
  forms,
  kMain in 'kMain.pas' {KundendatenF},
  interfaces in '..\..\units\interfaces.pas';

{$E dll}

{$R *.res}

function InitPlugin: IPlugin; stdcall;
begin
  Result := TPlugin.Create;
end;

Function RunPlugin(pApp: TApplication; PForm: TForm) : IPluginForm; Stdcall;
var tmpForm : TPluginForm;
begin
  tmpForm := TPluginForm.create(pApp,PForm);
  Result := tmpForm;
end;

exports
  InitPlugin,
  RunPlugin;
begin
end.

die kMain.pas
Delphi-Quellcode:
unit kMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, interfaces;

type
  TKundendatenF = class(TForm)
    Button2: TButton;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TPluginForm = Class(TInterfacedObject, IPluginForm)
  private
    ClientForm : TKundendatenF;
  protected
  public
     constructor create(PApp: TApplication; PForm: TForm);
     destructor Destroy; override;
  End;

  TPlugin = class(TInterfacedObject, IPlugin)
  private
    function GetName: PChar; stdcall;
    function GetVersion: Integer; stdcall;
  protected
    // hier die Methoden von system.TInterfacedObject reinkopieren
  public

  end;

var
  KundendatenF: TKundendatenF;
  dllApp: TApplication;
  PluginForm : TPluginForm;

implementation

constructor TPluginForm.create(PApp: TApplication; PForm: TForm);
begin
  dllApp := Application;
  Application := PApp;
  ClientForm := TKundendatenF.Create(Application);
end;


destructor TPluginForm.Destroy;
begin
  ClientForm.free;
end;

{ TPlugin }
function TPlugin.GetName: PChar;
begin
  Result := '&Kundendaten'; // "T" unterstrichen im Menü
end;

function TPlugin.GetVersion: Integer;
begin
  Result := (1 shl 16) or 0; // 1.0
end;

{$R *.dfm}

procedure TKundendatenF.Button2Click(Sender: TObject);
begin
  close;
end;

procedure TKundendatenF.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

end.
So Funktioniert auch so weit. Ich kann das Programm starten und das MDIChild öffnen. Alles super. Es wird auch korrekt geschlossen. Aber sobald ich das Programm Beenden möchte Gibt er mir eine Fehlermeldung raus.

Ich habe schon versucht mit verschiedenen mitteln denn ich denke das der grund hier ligt :

Delphi-Quellcode:
  dllApp := Application; <<----- Geschätzte uhrsache !!
  Application := PApp;
  ClientForm := TKundendatenF.Create(Application);
habe auch schon versucht das wieder an das Programm zurückzugeben aber ohne erfolg Macht keinen unterschied ! hat jemand einen Rat ?

Gruss Sascha

Ghostwalker 25. Aug 2007 20:37

Re: Dll Forms... oder ligt es nicht daran ??
 
Delphi-Quellcode:
constructor TPluginForm.create(PApp: TApplication; PForm: TForm);
begin
  ClientForm := TKundendatenF.Create(PApp);
end;
So sollte es funktionieren. Die Variable Application wird von Delphi bereits benutzt, die sollte man nicht vermurksen :)

dor557 25. Aug 2007 20:44

Re: Dll Forms... oder ligt es nicht daran ??
 
Das würde bei einem Normalen Programm was nur mit Forularen arbeitet.

Da ich aber MDI Formulare benutze bekomme ich wenn ich das so abändere die Fehlermeldung :

Formular kann nicht erstellt wertden. Zur zeit keine MDI-Formulare aktiv.

deshalb diese änderung.

habe mich halt durchgelesen und kam auf einen Forumbeitrag den ein anderer schon mal geschrieben hatte.

siehre Hier

... Kann nur das nicht 1:1 übernehmen. denke zumindest nicht wenn ich mit Interfaces arbeite. Hänge an der position einfach ein wenig !

Keiner Einen andren Rat ?

Zusatz : Die genaue Fehlermeldung lautet Ungültige Zeigeroperation aufgetreten.

Heffalump 26. Aug 2007 08:32

Re: Dll Forms... oder ligt es nicht daran ??
 
Versuche mal
Delphi-Quellcode:
KundenDatenF.ShowModal;
statt
Delphi-Quellcode:
KundenDatenF.Show;

Die Muhkuh 26. Aug 2007 08:42

Re: Dll Forms... oder ligt es nicht daran ??
 
Moin Sascha,

wo genau kommt diese Zeigeroperation?

dor557 26. Aug 2007 16:36

Re: Dll Forms... oder ligt es nicht daran ??
 
Die kommt wenn ich das Programm mit close beenden möchte !

Ich kann solange das MDI-Child aus der DLL geöffnet wurde auch ohne Probleme die Gleiche Funktion ausführen und das Form wird verschoben würde ich jetzt mal sagen. aber nicht neu erstellt oder überschreiben kann auch sein.

wenn ich das Nun schliesse und will es erneut öffnen bekomme ich eine Zugriffsverletztung um genau zu sein :

"Exception der Klasse EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse 00B53A44 in Module 'Kundendaten.dll'. Lesen von adresse 00000053 Aufgetreten" (Meldung des Debuggers)

schätze mal das das Form/Dll nicht Korrekt geschlossen wird oder die kontrolle nicht richtig an das Programm zurück gegeben wird.

nur wie ich das Lösen kann weiss ich nicht. Habe mir schon Meherere stunden um die Ohren Gehauen !

Die Muhkuh 26. Aug 2007 17:29

Re: Dll Forms... oder ligt es nicht daran ??
 
Hi Sascha,

Du wirst "leider" Debuggen müssen, um uns zumindest die Codezeile zeigen zu können, in der das Problem auftritt. Oder Du hängst das Projekt hier als Attachment dran, dann könnten wir selbst nachschauen.

dor557 26. Aug 2007 19:31

Re: Dll Forms... oder ligt es nicht daran ??
 
Liste der Anhänge anzeigen (Anzahl: 1)
Bekomme von meinem Delphi die Zeile nicht markiert wo einen Fehler verursacht.

nu die meldung.

Im anhang das Projekt.

die dll ist im Verz dll und das Hauptogramm im main Verzeichnis !

Hoffe ihr habe eine lösung.

gruss Sascha

dor557 30. Aug 2007 16:50

Re: Dll Forms... oder ligt es nicht daran ??
 
scheint so das keiner eine Lösung findet !?

Sch.... un nu ?

Werde warscheinlich vorrübergehend ohne MDI childs abreiten müssen bis ich eine Lösung Finde ! kann das sein ?=

Gruss Sascha


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:50 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