![]() |
Objekt an Interface zuweisen
Hallo!
Delphi-Quellcode:
Bin grad dabei, das Beispiel zu studieren. Meine Frage. Wie kann ich prüfen, ob das Objekt korrekt an das Interface zugewiesen wurde. Das Beispiel ist aus einem Thread mit dem Titel:
type
TApp = class(TInterfacedObject, IApp) private FEditor: IEditor; //Ein Interface constructor TApp.Create; begin inherited Create; FEditor := TEditorAdapter.Create(Form1.SynEdit); //Interface := Klasse; if FEditor is SynEdit then ShowMessage('Editor wurde zugewiesen'); //gibt Compilerfehler : '.' erwartet aber THEN gefunden. Wie frage ich ab, ob Zuweisung //korrekt end; "Dll wird nicht geladen...". Ich beschäftige mich grad mit Intefaces, weil ich das für mein nächste Projekt in der Firma benötige. Da kommt dieses Beispiel grad recht. Danke im Voraus für Eure Hilfe profmaster |
Re: Objekt an Interface zuweisen
Was ist denn SynEdit? Eine Klasse? Wenn ja, würde der Fehler nicht kommen. Wenn nein, ist das der Fehler.
|
Re: Objekt an Interface zuweisen
Zitat:
Also wenn das Interface <> nil ist, dann ist das Objekte korrekt zugewiesen worden. Ein Zugreifen auf das im Interface verpackte Objekt ist nicht möglich. Da muss man dann schon eine Methode schreiben, die Self zurückliefert:
Delphi-Quellcode:
Womit aber jedem die Tür zum fehlerhaften Zugriff auf das interne Objekt gestattet ist.
Ibla = interface
function GetObject: TObject; end; Tbla = class(TInterfacedObject, Ibla) function GetObject: TObject; end; function Tbla.GetObject: TObject; begin Result := Self; end; |
Re: Objekt an Interface zuweisen
Hallo jbg!
Zitat:
freundliche Grüße von profmaster |
Re: Objekt an Interface zuweisen
Bei Interfaces ist es normalerweise nicht notwendig sich Gedanken um das dahinter stehende Objekt zu machen. Dieses Objekt unterstützt die Schnittstellen des Interfaces (gut das man Deutsch und Englisch mischen kann) und mehr braucht man nicht zu wissen. Denn wenn man auf das Objekt direkt zugereifen muss, dann sollte man sein Interface mal anschauen, ob man das nicht noch darein packen kann. Und damit ältere Plugins auch noch funktionieren macht man das dann so:
Altes Programm:
Delphi-Quellcode:
Neues Programm:
IMyIntf = interface
[GUID-123] procedure Bla; end;
Delphi-Quellcode:
IMyIntf10 = interface
[GUID-123] procedure Bla; end; IMyIntf = interface(IMyIntf10) [GUID-987] procedure NeuBla; end; |
Re: Objekt an Interface zuweisen
Hallo jbg!
Habe mal ausgehend von dem Thread-Beispiel folgende Dll gebaut:
Delphi-Quellcode:
Wie greife ich nun in meiner Anwendung auf mein Plugin zu?
library IntfDll;
{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muß die erste Unit im Uses-Anweisungsteil des Interface-Abschnitts Ihrer Unit sein, wenn Ihre DLL Prozeduren oder Funktionen exportiert, die String-Parameter oder Funktionsergebnisse übergeben. Dies gilt für alle Strings die an und von Ihrer DLL übergeben werden -- selbst für diese, die in Records oder Klassen verschachtelt sind. ShareMem ist die Schnittstellen-Unit zur DELPHIMM.DLL, welche Sie mit Ihrer DLL weitergeben müssen. Um die Verwendung von DELPHIMM.DLL zu vermeiden, übergeben Sie String-Parameter unter Verwendung von PChar- oder ShortString-Parametern. } uses FastShareMem, SysUtils, Dialogs, MyAppIntf, SynEdit, Forms, Classes; type TPlugin = class(TInterfacedObject, IPlugin) function GetName: WideString; stdcall; // der Compiler fügt hier STDCALL autom. ein function GetVersion: Integer; stdcall; function Execute(App: IApp): Integer; stdcall; end; type TApp = class(TInterfacedObject, IApp) private FEditor: IEditor; public constructor Create(AEditor: IEditor); function GetEditor: IEditor; stdcall; procedure Terminate; stdcall; property Editor: IEditor read GetEditor; end; TEditorAdapter = class(TInterfacedObject, IEditor) private FContent: WideString; FSynEdit: TSynEdit; public constructor Create(ASynEdit: TSynEdit); procedure Clear; stdcall; function CaretX: Integer; stdcall; function CaretY: Integer; stdcall; procedure SetContent(const Value: WideString); stdcall; function GetContent: WideString; stdcall; procedure CopyToClipboard; stdcall; property Content: WideString read GetContent write SetContent; end; { TPlugin } function TPlugin.GetName: WideString; stdcall; begin Result := 'Mein &Testplugin'; // "T" unterstrichen im Menü end; function TPlugin.GetVersion: Integer; stdcall; begin Result := (1 shl 16) or 0; // 1.0 end; function TPlugin.Execute(App: IApp): Integer; stdcall; begin Result := 1; // True ShowMessage('Execute wurde aufgerufen!'); App.GetEditor.Content := 'Dieser Text erscheint im Editor.'; App.GetEditor.CopyToClipboard; end; { TApp } constructor TApp.Create(AEditor: IEditor); begin inherited Create; FEditor := AEditor; if Assigned(FEditor) then ShowMessage('Editor wurde zugewiesen'); end; function TApp.GetEditor: IEditor; begin Result := FEditor; end; procedure TApp.Terminate; begin Application.Terminate(); end; { TEditorAdapter } constructor TEditorAdapter.Create(ASynEdit: TSynEdit); begin inherited Create; FSynEdit := ASynEdit; //FSynEdit := TSynEdit.Create; end; function TEditorAdapter.CaretX: Integer; stdcall; begin Result := 0; end; function TEditorAdapter.CaretY: Integer; stdcall; begin Result := 0; end; procedure TEditorAdapter.Clear; stdcall; begin FSynEdit.Free; FSynEdit := nil; end; procedure TEditorAdapter.SetContent(const Value: WideString); stdcall; begin FContent := Value; end; function TEditorAdapter.GetContent: WideString; stdcall; begin Result := FContent; end; procedure TEditorAdapter.CopyToClipboard; stdcall; begin FSynEdit.CopyToClipBoard; end; function InitApp: IApp; stdcall; begin Result := TApp.Create(TEditorAdapter.Create(TSynEdit.Create(Application))); end; function InitPlugin: IPlugin; stdcall; begin Result := TPlugin.Create; end; function InitEditor: IEditor; begin Result := TEditorAdapter.Create(TSynEdit.Create(Application)); end; exports InitApp, InitPlugin; //Die Initialisierung meines Plugin begin end. Mich irretiert hier, das neben dem Editoradapter ein TPlugin und noch ein TApp existiert. Nur der EditorAdapter wäre übersichtlicher. Oder ein TPlugin/IPlugin, das alle Zuweisungen und sonstigen Zugriffe abdeckt. Irgendwie verstehe ich das Design noch nicht. Ich habe folgende Fragen: Warum IPlugin, wo doch der EditorAdapter da ist? Warum dann noch IApp? Warum nicht nur der EditorAdapter und sonst nichts? Gibt es Richtlinien zum Interface-Design im Sinne guten Programmierstils? Wie greife ich nun in meiner Anwendung auf dieses Interface zu, ohne allzuviele fehlerträchtige Verrenkungen zu machen. Im Beispiel ist mir die Methode TForm1.mCfgToolsClick(Sender: TObject); zu unübersichtlich. Hier sei sie noch mal zur Erinnerung:
Delphi-Quellcode:
Ich habe die Implementation der Interfaces in die Dll gepackt, weil ich ja meine Anwendung mit Hilfe der Interfaces um Funktionalität erweitern will, die ja dann in meiner Dll stecken muß, mit der ich meine Anwendung erweitere.
procedure TForm1.mCfgToolsClick(Sender: TObject);
type TProcInitPlg = function: IPlugin; stdcall; var fName: string; iPlg: IPlugin; aProc: TProcInitPlg; hDLL: HWND; fProc: TFarProc; mApp: TApp; begin ShowMessage(GetCurrentDir); with TOpenDialog.Create(nil) do begin InitialDir := GetCurrentDir; if Execute then fName := FileName else begin ShowMessage('Datei existiert nicht!'); Exit; end; end; (* fName := GetCurrentDir; if fName[Length(fName)]<>'\' then fName := fName + '\'; fName := fName + 'plugin.dll'; *) SetLastError(0); hDll := LoadLibrary(@fName[1]); if hDll = 0 then ShowMessage(SysErrorMessage(GetLastError)); fProc := GetProcAddress(hDLL,'InitPlugin'); if fProc <> nil then begin @aProc := fProc; //InitPlugin ausführen und Interface an aProc end else begin ShowMessage('DLL konnte nicht geladen werden!'); Exit; end; iPlg := nil; iPlg := aProc; //TApp und TPlugin war erst in Anwendung implementiert. Da klappte das so //Wie kann ich jetzt das gleiche erreichen? Da muß ich doch sicher analog der obigen //Vorgehensweise für alle vorhandenen Interfaces eine ProcedureAddress laden, Interface //initialisieren und dann irgendwie drauf zugreifen. Das scheint mir etwas umständlich und //fehlerträchtig, wenn ich eine wirklich große Anwendung duch Plugins erweitern will. Geht //das nicht auch einfacher? Leider hab ich momentan keine Idee wie? // --- Hier wird die Execute Routine aufgerufen --- hinzu am 19.08.05 23:34 mApp := TApp.Create; //funktioniert so nicht, weil TApp jetzt in Dll imlementiert if Assigned(iPlg) then begin iPlg.Execute(mApp); //Plugin ausführen. Problem: Content wird nicht zugewiesen => Warum nicht? end else ShowMessage('Plugin konnte nicht initialisiert werden!'); showMessage(iPlg.GetName); //Prüfen, ob Routine gefunden iPlg := nil; //Plugin-Zeiger löschen FreeLibrary(hDLL); //Klar, Dll am Ende wieder freigeben end; Bitte heft mir. Ich bin bezüglich der Implementation etwas ratlos. profmaster |
Re: Objekt an Interface zuweisen
Zitat:
Zitat:
Zitat:
Der TEditorAdapter wird in der Anwendung implementiert, weil dort das Editor-Objekt liegt. Das IPlugin wird hingegen im Plugin implemetiert, und die Anwendung greift dann darauf über das vom InitPlugin zurückgelieferte IPlugin zu. Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Also die Plugins laden und die exportierte Funktion InitPlugin aufrufen. Das von dieser zurückgelieferte IPlugin Interface in eine TIinterfaceList (oder eine davon angeleitete, spezialisierte TPluginList) schieben. Und jetzt die Plugin-DLL auf keinen Fall freigeben, denn sonst hängen die Interfaces in der Luft. Im OnClick-Handler muss man jetzt nur noch durch die PluginList iterieren und das passende finden. Das Suchen des passenden Interfaces lässt sich auch noch in eine eigene Funktion auslagern, die entweder das IPlugin oder nil zurückliefet (ggf. bei nil eine Exception auslöst). Im OnDestroy dann einfach PluginList.Clear aufrufen und die DLLs entladen (oder das von Windows machen lassen). |
Re: Objekt an Interface zuweisen
Hallo jbg!
JUHUUUUU, es klappt jetzt. Danke für Deine Hilfe! Jetzt kann ich weitermachen! Programmierergrüße von Profmaster |
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:32 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