![]() |
Aus einer DLL auf externe Funktionen zugreifen
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 |
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.
|
Hm... also da fällt mir folgendes ein:
Delphi-Quellcode:
Geht das denn so? Eigentlich gibt es da doch immer Probleme, oder?
// 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; Könntest du vielleicht ein kleines Beispiel geben (Funktionsnamen stehen oben)? Chris |
Zitat:
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:
Der DLL Code:
// 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;
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. |
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 |
Hi,
wo muss ich die Deklartionen in der MyAppIntf einfügen? Diese Unit ist doch eine neuerstellte, oder? :oops: Chris |
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 |
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
Delphi-Quellcode:
gibt es immer, dass heißt auch, wenn ich überhaupt nicht auf die Daten zugreife, eine AccessViolation.
FreeLibrary(hDLL);
Hier mal der ganze Source:
Delphi-Quellcode:
Chris
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; |
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:
Um dieses Problem zu umgehen, musst du vor dem FreeLibary alle Interfaces freigeben. Dies kannst du auf folgende Weise machen:
Delphi-Quellcode:
Noch ein Tipp:
showMessage(iPlg.GetName);
iPlg := nil; // Interface freigeben FreeLibrary(hDLL); Wenn du mehrere Plugins gleichzeigtig im Speicher halten willst, so bietet sich die Klasse TInterfaceList aus der Unit Contnrs an. |
Re: Aus einer DLL auf externe Funktionen zugreifen
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' |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09: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