AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Aus einer DLL auf externe Funktionen zugreifen
Thema durchsuchen
Ansicht
Themen-Optionen

Aus einer DLL auf externe Funktionen zugreifen

Ein Thema von CalganX · begonnen am 31. Mär 2003 · letzter Beitrag vom 10. Dez 2009
Antwort Antwort
Seite 1 von 2  1 2      
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#1

Aus einer DLL auf externe Funktionen zugreifen

  Alt 31. Mär 2003, 21:20
Hi,
ich habe eine Frage: wie kann ich in einer DLL auf Funktionen meines Hauptprogrammes zugreifen? Muss ich dafür extra eine weitere DLL schreiben? Das Problem ist, dass die Funktion Instanz des Formulares ist und die Funktion auf das Formular zugreift..

Also: wie geht das?

Chris
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#2
  Alt 31. Mär 2003, 21:39
Mir fällt keine Möglichkeit ein, die Funktion deines Programms in die DLL zu importieren. Das einzige, was mir jetzt einfällt, wäre einen Zeiger auf die Funktion in der Unit an eine Funktion der DLL zu übergeben; der Zeiger wird dann referenziert und die entsprechende Funktion ausgeführt.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#3
  Alt 31. Mär 2003, 22:00
Hm... also da fällt mir folgendes ein:
Delphi-Quellcode:
// in der DLL
type
  TFunctions = packed record
    fGetSyn: function: TSynEdit;
    fGetSth: function: PChar;
  end;
{...}
function DoOperation(fFunc: TFunctions): boolean;
var
  Syn: TSynEdit;
begin
  Syn := fFunc.fGetSyn;
end;

// in dem Programm
type
  TFunctions = packed record
    fGetSyn: function: TSynEdit;
    fGetSth: function: PChar;
  end;
{...}
function TFrmMain.GetCurSyn: TSynEdit;
begin
  // ...
end;
{...}
procedure TFrmMain.Button1Click(Sender: TObject);
var
  fFuncs: TFunctions;
begin
  fFuncs.fGetSyn := GetCurSyn;
end;
Geht das denn so? Eigentlich gibt es da doch immer Probleme, oder?
Könntest du vielleicht ein kleines Beispiel geben (Funktionsnamen stehen oben)?

Chris
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#4
  Alt 31. Mär 2003, 22:40
Zitat:
fGetSyn: function: TSynEdit;
Bist du dir da ganz sicher, dass du ein TSynEdit (bzw eine Komponente allgemein) der DLL übergeben willst? Da musst du dann die Unit ShareMem einbinden die wiederum die borlndmm.dll benötigt. Ein (V)C++ Programm hat wiederum seinen eigenen Speichermanager und somit geht das ganze nach hinten los.


Ich würde in deinem Fall auf Interfaces setzen. Diese sind sowohl in Delphi als auch in C++ nutzbar. Es besteht auch kein direkter Zugriff auf irgendwelche Daten, ohne dass das über eine Interface-Methode geregelt ist, die in deinem Hauptprogramm implementiert ist und somit dessen Speichermanager nutzt.

Hier mal ein kleines Beispiel für eine Plugin-Schnittstelle per Interfaces

Delphi-Quellcode:
// unit MyAppIntf.pas
IEditor = interface;
IApp = interface;
IPlugin = interface;

{ IPlugin wird von der Plugin DLL implementiert. Der Entrypoint "InitPlugin" liefert dieses Interface zurück. }
IPlugin = interface
  ['{8E5F6F87-BD7C-4F51-A2B1-36E437E20648}']
  { GetName liefert den Namen des Plugins, der im Menü verwedet wird }
  function GetName: WideString; stdcall;
  { GetVersion liefert die Versionsnummer: HiWord=Major, LoWord=Minor }
  function GetVersion: Integer; stdcall;
  { Execute wird von der Anwendung aufgerufen, wenn der Benutzer auf
    den Menüpunkt klickt. }

  function Execute(App: IApp): Integer; stdcall;
end;

{ IApp wird von der Anwendung implementiert und an IPlugin.Execute übergeben }
IApp = interface
  ['{8E5F6F87-BD7C-4F51-A2B1-36E437E20648}']
  { GetEditor liefert ein Interface auf den Editor }
  function GetEditor: IEditor; stdcall;
  { Terminate beendet das Programm }
  procedure Terminate; stdcall;
end;

{ IEditor bietet Zugriff auf den Editor und wird von IApp.GetEditor zurückgeliefert. }
IEditor = interface
  ['{2044641E-CF97-470B-9112-B0E28B0CB019}']
  function CaretX: Integer; stdcall;
  function CaretY: Integer; stdcall;

  procedure Clear; stdcall;
  procedure SetContent(const Value: WideString); stdcall;
  function GetContent: WideString; stdcall;
  procedure CopyToClipboard; stdcall;
  ...

  property Content: WideString read GetContent write SetContent;
end;
Der DLL Code:
Delphi-Quellcode:
uses MyAppIntf;
type
  TPlugin = class(TInterfacedObject, IPlugin)
    function GetName: WideString; // der Compiler fügt hier STDCALL autom. ein
    function GetVersion: Integer;
    function Execute(App: IApp): Integer;
  end;

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

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

function TPlugin.Execute(App: IApp): Integer;
begin
  Result := 1; // True

  App.GetEditor.Content := 'Dieser Text erscheint im Editor.';
  App.GetEditor.CopyToClipboard;
end;


{ einzige exportierte Funktion }
function InitPlugin: IPlugin; stdcall; {export;}
begin
  Result := TPlugin.Create;
end;

exports
  InitPlugin;

end.

In der Anwendung:
Delphi-Quellcode:
type
  TApp = class(TInterfacedObject, IApp)
  private
    FEditor: IEditor;
  public
    constructor Create;

    function GetEditor: IEditor;
    procedure Terminate; stdcall;
  end;

  TEditorAdapter = class(TInterfacedObject, IEditor)
  private
    FSynEdit: TSynEdit;
  public
    constructor Create(ASynEdit: TSynEdit);

    procedure Clear;
    ...
  end;

{ TApp }
constructor TApp.Create;
begin
  inherited Create;
  FEditor := TEditorAdapter.Create(Form1.SynEdit);
end;

function TApp.GetEditor: IEditor;
begin
  Result := FEditor;
end;

procedure TApp.Terminate;
begin
  Form1.Close;
end;

{ TEditorAdapter }
constructor TEditorAdapter.Create(ASynEdit: TSynEdit);
begin
  inherited Create;
  FSynEdit := ASynEdit;
end;

procedure TEditorAdapter.Clear;
begin
  FSynEdit.Clear;
end;

Das ich hier WideString anstatt dem AnsiString (=string) verwendet habe liegt in der Tatsache, dass WideString unter Delphi keine Referenzzählung hat und somit nicht dem Problem mit unterschiedlichen Speichermanagern unterworfen ist, da der Speichermanager den WideString wieder freigibt, der ihn auch erzeugt hat. Und wenn mir jetzt einer mit dem Kommentar aus der Hilfe "Im Linux-Produkt von Borland wird für Wide-Strings eine Referenzzählung durchgeführt." kommt, dem muss ich sagen, dass Kylix den System-Speichermanager nutzt, was alle Linux-Programme machen. Und der ist nun mal ein und derselbe für jedes Modul.
Ein anderer Grund für WideString ist, dass auch (V)C++ diesen unterstützt und zwar als LPWSTR.

Aber zurück zu den Interfaces. Diese kann man auch in (V)C++ nutzen und hat somit eine sehr flexible Schnittstelle geschaffen. Durch die Verwendung von GUIDs ist es sogar möglich bei einer Erweiterung der Funktionalität alte Plugins am laufen zu halten.
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#5
  Alt 1. Apr 2003, 13:35
Hi!
Super! Werde mir das gleich ansehen.
Ich bin mir jetzt nicht hundertprozentig sicher (ich habe das gerade erstmal überflogen) ob das geht, aber das SynEdit ist dynamisch...

Chris
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#6
  Alt 1. Apr 2003, 14:10
Hi,
wo muss ich die Deklartionen in der MyAppIntf einfügen? Diese Unit ist doch eine neuerstellte, oder?

Chris
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#7
  Alt 1. Apr 2003, 14:34
Hab' es jetzt doch hinbekommen...
Aber nun gibt es noch ein weiteres Problem: könntest du mir vielleicht ein Beispiel geben, wie ich in der Anwendung auf Knopfdruck dieses PlugIn installieren kann? Ich steige da noch nicht ganz durch. Wäre dir echt dankbar!

Chris
  Mit Zitat antworten Zitat
CalganX

Registriert seit: 21. Jul 2002
Ort: Bonn
5.403 Beiträge
 
Turbo Delphi für Win32
 
#8
  Alt 1. Apr 2003, 15:47
OK. Das nächste Mal versuche ich es doch nochmal, bevor ich poste... Funktioniert.
Aber leider gibt es ein Problem: beim entladen der DLL mit
FreeLibrary(hDLL); gibt es immer, dass heißt auch, wenn ich überhaupt nicht auf die Daten zugreife, eine AccessViolation.
Hier mal der ganze Source:
Delphi-Quellcode:
procedure TMainFrm.mCfgToolsClick(Sender: TObject);
type
  TProcInitPlg = function: IPlugin; stdcall;
var
  fName: string;
  iPlg: IPlugin;
  aProc: TProcInitPlg;
  hDLL: HWND;
  fProc: TFarProc;
  mApp: TApp;
begin
  with TOpenDialog.Create(nil) do begin
    if Execute then
      fName := FileName
    else Exit;
  end;
  hDll := LoadLibrary(@fName[1]);
  fProc := GetProcAddress(hDLL,'InitPlugin');
  if fProc <> nil then begin
    @aProc := fProc;
  end else Exit;
  iPlg := aProc;
  showMessage(iPlg.GetName);
  FreeLibrary(hDLL);
end;
Chris
  Mit Zitat antworten Zitat
jbg

Registriert seit: 12. Jun 2002
3.483 Beiträge
 
Delphi 10.1 Berlin Professional
 
#9
  Alt 1. Apr 2003, 21:40
Wenn man die Leute im Stich lässt (= wenn man beim Arbeiten ist), dann kommen die auch ohne Hilfe zum Ziel.

Zu deinem Problem mit der Schutzverletzung:

Zitat:
iPlg := aProc;
Hiermit liefert die DLL eine neues Interface zurück. Wenn du nun die DLL entlädst (FreeLibrary), so bleibt der Interface-Zeiger iPlg noch besteht, wohingegen der Speicherplatz des Interfaces von Windows freigegeben wird. Da Delphi beim Verlassen von mCfgToolsClick bei allen dort verwendeten Interfaces den Referenzzähler um 1 herunter setzt (bei 0 wird das Interface freigegeben), greift das Programm auf ungültigen Speicher zu, was eine AV zur Folge hat.

Um dieses Problem zu umgehen, musst du vor dem FreeLibary alle Interfaces freigeben. Dies kannst du auf folgende Weise machen:
Delphi-Quellcode:
  showMessage(iPlg.GetName);
  iPlg := nil; // Interface freigeben
  FreeLibrary(hDLL);
Noch ein Tipp:
Wenn du mehrere Plugins gleichzeigtig im Speicher halten willst, so bietet sich die Klasse TInterfaceList aus der Unit Contnrs an.
  Mit Zitat antworten Zitat
Benutzerbild von Die Muhkuh
Die Muhkuh

Registriert seit: 21. Aug 2003
7.332 Beiträge
 
Delphi 2009 Professional
 
#10

Re: Aus einer DLL auf externe Funktionen zugreifen

  Alt 22. Jul 2004, 17:58
Hi,


ich hab das hier auch mal durchgemacht. Nur kommt bei mir beim compilieren, der Unit "MyAppInft" folgende Fehler:

[Fehler] Unit1.pas(29): Undefinierter Bezeichner: 'CaretX'
[Fehler] Unit1.pas(29): Undefinierter Bezeichner: 'CaretY'
[Fehler] Unit1.pas(29): Undefinierter Bezeichner: 'Clear'
[Fehler] Unit1.pas(36): Undefinierter Bezeichner: 'SetContent'
[Fehler] Unit1.pas(36): Undefinierter Bezeichner: 'GetContent'
[Fehler] Unit1.pas(36): Undefinierter Bezeichner: 'CopyToClipboard'
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz