Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Komplettes Projekt in DLL auslagern (https://www.delphipraxis.net/62572-komplettes-projekt-dll-auslagern.html)

PierreB 6. Feb 2006 17:34


Komplettes Projekt in DLL auslagern
 
Moin,

ich hab da ein mehr oder weniger kompliziertes Problem:

Ich will ein fertiges Programm (besteht circa aus 4 Forms) in eine DLL auslagern, da es seinen Dienst als Plugin in einem anderen Programm tun soll. Also kein Fremdprogramm, ich hab die Sourcen zu dem Programm. Dies soll nun komplett in die DLL wandern um es dann aus dem anderen Programm heraus aufzurufen.

Nur leider sind meine Kenntnisse im Bezug auf DLL und Plugins extrem begrenzt, weshalb ich auf eure Hilfe aufbaue. Die Suchfunktion brachte mehr oder weniger gute Threads zum Vorschau, wo ich zwar ungefähr erkennen konnte wie man ein neues Form in einer DLL erstellt, jedoch möchte (kann) ich nicht alles neuprogrammieren, sondern möchte es wie gesagt nur in die DLL "verschieben". hat da jemand ne Ahnung wie man das einfach hinbekommen kann ?

Danke,

Matze 6. Feb 2006 17:38

Re: Komplettes Projekt in DLL auslagern
 
Hi,

ich weiß nur, dass sich Firmulare in DLLs nicht gut machen. Es soll irgendwelche Kompatibilitätsprobleme o.ä. geben (Habe ich hier irgendwo einmal gelesen). Für das Auslagern von Formularen sind Packages geeignet, doch musst du einige VCL Packages mit ausliefern.

mirage228 6. Feb 2006 17:39

Re: Komplettes Projekt in DLL auslagern
 
Hi,

Erstmal könntest Du natürlich Runtime packages verwenden, aber um mal auf das Problem hier einzugehen ... ;)

Du bindest einfach die Form-Unit in die DLL ein und rufst das Formular dynamisch auf.
Du kannst dann natürlich nicht die globalen Form Variablen benutzen, du musst die anderen Forms auch dynamisch erstellen.

Beispiel:
Delphi-Quellcode:
library Bla;

uses
  uDeineFormUnit;

function ShowForm(): Integer; stdcall;
begin
  with TDeinForm.Create(nil) do
  try
    Result := ShowModal();
  finally
    Free;
  end;
end;

exports
  ShowForm;

begin
end.
mfG
mirage228

PierreB 6. Feb 2006 17:41

Re: Komplettes Projekt in DLL auslagern
 
Zitat:

Du bindest einfach die Form-Unit in die DLL ein und rufst das Formular dynamisch auf.
Du kannst dann natürlich nicht die globalen Form Variablen benutzen, du musst die anderen Forms auch dynamisch erstellen.
:shock: So einfach geht das ? Ich werd das ausprobieren, danke erstmal.

@Matze: Danke für den Hinweis, mal gucken ob ich dazu noch was finde.

PierreB 10. Feb 2006 12:48

Re: Komplettes Projekt in DLL auslagern
 
Moin,

also so wie von mirage beschrieben geht es erstmal wunderbar (mit Form1), jetzt hab ich nur so meine Probleme mit dem zweiten Form. Auf Form1 liegt ein Button, der folgendes Ereignis aufruft:
Delphi-Quellcode:
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
i : Integer;
begin
  with TchooseFont.Create(nil) do
  try
     if ShowModal() = mrYes then
     begin
       form1.schriftart.Text := '';
       if Listbox2.Items.Count > -1 then
        begin
         if Listbox2.Items.Count = 1 then Form1.schriftart.text := form1.schriftart.text + ' ' + Listbox2.Items[0] else
          begin
           for i := 0 to Listbox2.Items.Count-1 do
           Form1.schriftart.text := form1.schriftart.text + ' ' + Listbox2.Items[i] + ',';
          end;
        Edit1.Text := '';
        if not Listbox2.Items.Count < -1 then Form1.RichEdit1.Font.Name := Listbox2.Items[0] else Form1.RichEdit1.Font.Name := 'Tahoma';
        end;
     end
  finally
    Free;
  end;
end;
ChooseFont ist in diesem Fall Form2, auf dieser Form liegt ein Button dessen ModulResult Eigenschaft ich auf "mrYes" gesetzt hab. Klicke ich nun auf den Button im Form1, wird Form2 auch korrekt erstellt und läuft. Klicke ich nun auf den Button auf Form2, werden die Werte aus der Listbox auf Form2 nicht wie erwartet ins "schriftart"-Edit auf Form1 übertragen, sondern ich bekomme ne böse Fehlermeldung a'la "
Zugriffsverletzung bei Adresse 0038A72B in Modul 'test.dll'. Lesen von Adresse 00000360.". Dies allerdings nur wenn ich die Forms aus der DLL lade, kompiliere ich das Projekt ganz normal als eigenständige Exe geht alles problemlos. Weiß jemand wo der Fehler liegt ?

Danke,

mirage228 10. Feb 2006 13:46

Re: Komplettes Projekt in DLL auslagern
 
Hi,

Du benutzt die globale Variable Form1, das ist nicht gültig in diesem Kontext (da dein Form ja nicht darin verwendet ist sondern wie im Code oben anders erstellt wird).
Da du ja eh in TForm1 bist gerade kannst Du einfach "Self" nehmen oder Form1. ganz weglassen.

mfG
mirgae228

PierreB 10. Feb 2006 13:55

Re: Komplettes Projekt in DLL auslagern
 
Vielen Dank, jetzt gehts fehlerfrei. :cheers:

PierreB 10. Feb 2006 14:10

Re: Komplettes Projekt in DLL auslagern
 
Argh, jetzt bekomme ich beim Beenden des Programmes das die DLL einbindet so einige Runtime-Errors, unter anderem:
Zitat:

---------------------------
**************.exe - Fehler in Anwendung
---------------------------
Die Anweisung in "0x00b43192" verweist auf Speicher in "0x01292208". Der Vorgang "read" konnte nicht auf dem Speicher durchgeführt werden.
Klicken Sie auf "OK", um das Programm zu beenden.
---------------------------
OK
---------------------------
Und
Zitat:

---------------------------
Error
---------------------------
Runtime error 216 at 0051F1A9
---------------------------
OK
---------------------------
Weiß jemand woran das liegt und wie man es aufheben kann ?

PierreB 12. Feb 2006 07:34

Re: Komplettes Projekt in DLL auslagern
 
Das Problem an dem Problem ist, dass die Fehler nur kommen wenn ich die DLL in das bereits fertige Projekt einbinde. Erstelle ich ein neues Projekt und binde die DLL ein geht alles fehlerfrei, es muss also an dem bestehenden Projekt liegen. Leider habe ich keine Ahnung wo der Fehler liegen kann, keine ne Idee ? :(

Balu der Bär 3. Dez 2006 09:40

Re: Komplettes Projekt in DLL auslagern
 
Bei einem anderen Projekt bekomme ich beim Beenden des Programmes nachdem ich ein Form aus einer DLL aufgerufen habe ebenfalls obige zwei Meldungen. Hat jemand eine Idee woran das liegt und wie man es vermeiden kann? Besten Dank.

SirThornberry 3. Dez 2006 09:43

Re: Komplettes Projekt in DLL auslagern
 
für mich klingeln die Fehler als wären Strings oder Objekte zwischen DLL und Haupprogramm ohne ShareMem ausgetauscht worden.

GuenterS 3. Dez 2006 09:48

Re: Komplettes Projekt in DLL auslagern
 
Zitat:

Zitat von SirThornberry
für mich klingeln die Fehler als wären Strings oder Objekte zwischen DLL und Haupprogramm ohne ShareMem ausgetauscht worden.

ist dies auch der Fall, wenn man zwischen Hauptprogramm und DLL nur Shortstrings also strings[255] verwendet?

Balu der Bär 3. Dez 2006 09:56

Re: Komplettes Projekt in DLL auslagern
 
Nein, auch mit eingebundener ShareMem bleiben die bösen Fehler am Ende. :-(

Elvis 3. Dez 2006 10:59

Re: Komplettes Projekt in DLL auslagern
 
Zitat:

Zitat von Balu der Bär
Nein, auch mit eingebundener ShareMem bleiben die bösen Fehler am Ende. :-(

Im Gegensatz zu Packages sind DLLs eigenständige Binaries. Sie enthalten also ihre eigene Implementierung eines MemoryManagers[1] und wenn nicht anders angegeben enthalten sie ihre eigene Version der RTL, aller verwendeten Unit und eigentlich allem was Delphi zu Delphi macht.
Wenn du ein Form aus einer DLL lädst hast du 3 Möglichkeiten.
  • Du referenzierst die benötigten Packages (RTL,VCL,XXX) in Exe und DLL extern. Dadurch ist ein TObject für Echse und DLL das gleiche. Genau wie TObject und alles andere in den extern gelinkten Packages.
    Das bedeutet aber, dass du die DLL immer mit der gleichen Compilerversion wie bei der Echse kompilieren musst.
  • Du benutzt Interfaces.
    Damit bist du kompatibel zwischen Sprachen und Delphi Versionen, da sich Interfaces in Delphi generell an COM-Pflichten halten und somit zwangläufig kompatibel sind.
    Du kannst damit auch easy die Abhängigkeit auf ShareMem los werden. Indem du anstatt Strings, WideStrings nimmst.
    WideString werden von Windows selbst verwaltet.
    IMHO sind Interfaces in Delphi32 fast immer die netteste Art Funktionalität bereit zu stellen.
    Dank autom. Referenzzählung muss sich der konsumierende Code auch nicht mehr mit widerlichen try-finally Blöcken ärgern. :)
  • Du gibst nur ein Handle auf dein Fenster zurück und arbeitest nur mit API-Funktionen.
    Dadurch gibt es keine Vermischung von unterschiedlichen Implementierungen der RTL.
Verion1 ist die, die am einfachten ist. Aber sie zwingt dich mindestens RTL und VCL extern mitzugeben.
Lösung 2 erfordert einen Wrapper, der ein Interface implementiert. Aber nach diesem Mini-Schnipsel bist absolut unabhängig und kannst auch D7 kompilierte DLLs mit 2006 benutzen und vice versa.
Lösung 3 ist IMHO absolut furchtbar, auch wenn die WinAPI-Fritzen da sicherlich anderer Meinung wären. :mrgreen:





[1]den Punkt hast du mit ShareMem schon gelöst

GuenterS 3. Dez 2006 11:07

Re: Komplettes Projekt in DLL auslagern
 
Kannst Du mir ein Beispiel geben wie, so ein Wrapper aussehen könnte?

Die DLL wurde mit D7 Prof. erstellt und sollte dann in TDE verwendet werden...

Elvis 3. Dez 2006 14:08

Re: Komplettes Projekt in DLL auslagern
 
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:

Zitat von GuenterS
Kannst Du mir ein Beispiel geben wie, so ein Wrapper aussehen könnte?

Die DLL wurde mit D7 Prof. erstellt und sollte dann in TDE verwendet werden...

Kein Problem.
Ich habe mich aber zurückgehalten, da ich keine Lust hatte mir was sinnvolles auszudenken. :mrgreen:
Man nehme eine Form in D7, die Ein Edit, einen Button und eine ListBox hat.
Drücke ich den Button wird der Inhalt an die LB gehängt.
Das ganze könnte man so als Interface verpacken um diese Funktionalität anderen zur Verfügung zu stellen ohne dass sie etwas über TObject, AnsiStrings oder die VCL wissen müssten:
Delphi-Quellcode:
unit uDllFormInterfaces;

interface
uses
  Windows;

type
  IDllForm = interface(IUnknown)
  ['{CE9CD182-13A2-4DAE-B7AA-ED8A8100B8A4}']
    function get_Caption : WideString; stdcall;
    procedure set_Caption(const value : WideString); stdcall;

    function get_Item(aIndex : Integer) : WideString; stdcall;
    procedure set_Item(aIndex : Integer; const value : WideString); stdcall;

    function get_Handle : HWnd; stdcall;

    function AddLine(const line : WideString) : Integer; stdcall;

    procedure Show; stdcall;
    function ShowDialog : Integer; stdcall;
    procedure Hide; stdcall;


    property Caption : WideString
      read get_Caption
      write set_Caption;
    property Item[aIndex : Integer] : WideString
      read get_Item
      write set_Item;
    property Handle : HWnd
      read get_Handle;
  end;
Verpacken könnte man es so:
Delphi-Quellcode:
uses
  uDllFormInterfaces,
  uDllForm,
  Windows;

type
  TDllFormWrapper = class(TInterfacedObject, IDllForm)
  private
    fForm: TDllForm;
  protected
    function get_Caption: WideString; stdcall;
    function get_Item(aIndex: Integer): WideString; stdcall;
    procedure set_Caption(const value: WideString); stdcall;
    procedure set_Item(aIndex: Integer; const value: WideString); stdcall;
    property Form : TDllForm read fForm;
    function get_Handle: HWnd; stdcall;
  public

    function AddLine(const line: WideString): Integer; stdcall;

    property Caption : WideString
      read get_Caption
      write set_Caption;
    property Item[aIndex : Integer] : WideString
      read get_Item
      write set_Item;
    property Handle : HWnd
      read get_Handle;

    constructor Create;
    destructor Destroy; override;

    procedure Hide; stdcall;
    procedure Show; stdcall;
    function ShowDialog : Integer; stdcall;

  end;

  function CreateDllForm : IDllForm; stdcall;

implementation

uses
  Dialogs;

function CreateDllForm : IDllForm;
begin
  result := TDllFormWrapper.Create();
end;

{ TDllFormWrapper }

constructor TDllFormWrapper.Create;
begin
  inherited;
  fForm := TDllForm.Create(nil);
end;

destructor TDllFormWrapper.Destroy;
begin
  fForm.Free();
  ShowMessage('freed!'); // weil manche nicht an RefCounting glauben ;-)
  inherited;
end;

function TDllFormWrapper.AddLine(const line: WideString): Integer;
begin
  result := Form.ListBox1.Items.Add(line);
end;

function TDllFormWrapper.get_Caption: WideString;
begin
  result := Form.Caption;
end;

function TDllFormWrapper.get_Item(aIndex: Integer): WideString;
begin
  result := Form.ListBox1.Items[aIndex];
end;

procedure TDllFormWrapper.set_Caption(const value: WideString);
begin
  Form.Caption := value;
end;

procedure TDllFormWrapper.set_Item(aIndex: Integer;
  const value: WideString);
begin
  Form.ListBox1.Items[aIndex] := value;
end;

procedure TDllFormWrapper.Hide;
begin
  Form.Hide();
end;

procedure TDllFormWrapper.Show;
begin
  Form.Show();
end;

function TDllFormWrapper.ShowDialog : Integer;
begin
  result := Form.ShowModal();
end;

function TDllFormWrapper.get_Handle: HWnd;
begin
  result := Form.Handle;
end;
Ich habe eine Screenie angehängt, der zeigt dass es geht und beide Mini-Projekte. ;)

Balu der Bär 3. Dez 2006 18:36

Re: Komplettes Projekt in DLL auslagern
 
Danke dir Robert, mal gucken inwieweit ich das in meinem Programm umsetzen kann. ;)


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