Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Plugin-System mit Interfaces und DLLs (https://www.delphipraxis.net/65830-plugin-system-mit-interfaces-und-dlls.html)

MasterEvil 21. Mär 2006 05:46


Plugin-System mit Interfaces und DLLs
 
Hallo leutz,

ich bin momentan dabei ein Plugin-System für meinen EW-ProjectManager zu programmieren.
Dabei habe ich mich für die Arbeit mit Interfaces und DLLs entschieden.

Dies klappt im allgemeinen auch schon Recht gut. Ich durchsuche einen bestimmten Ordner nach dlls und lade diese nacheinander in einen Array, welcher alle nötigen Daten hält.

Ein Object dieses Arrays erzeuge ich so (alle Variablen mit einem F werden gespeichert):

Delphi-Quellcode:
constructor TPlugin.Create(Filename: String);
var
  Proc           : TProcInitPlugin;
begin
  inherited Create;

  FPmInterface:=TPmInterface.Create;
  FFilename:=Filename;

  FLib:=LoadLibrary(PChar(FFilename));
  if FLib<>0 then
  begin
    @Proc:=GetProcAddress(FLib,'InitPlugin');
    FPlugin:=Proc;

    FPluginInfo:=FPlugin.Init(FPmInterface);
  end;
end;
FPmInterface ist dabei das Interface der Hauptapplikation, welches immer an das Plugin übergeben wird, damit es mit der App interagieren kann..
So, wie es hier ist, funktioniert es jetzt. Vorher hatte ich allerdings ein PmInterface, welches für alle Plugins gelten sollte (also nicht immer eins extra für jedes Plugin). Dies funktioniert aber irgendwie nicht, da nach jedem gebrauch das Objekt weg zu sein scheint, da ich immer eine Zugriffsverletzung bekomme, wenn ich es übergeben will. Ich weiss, dass sich die Objekte bei Interfaces selbst zerstören, wenn es keine Referenzen mehr aus sie gibt, aber ich habe doch eine Referenz ?!? das FPmInterface bleibt doch erhalten, auch wenn ich es übergebe ?!? Im Moment muss ich FPmInterface JEDESMAL neu erstellen, wenn ich es benutzen (sprich ans Plugin übergeben) möchte (da ich es im Plugin in jeder Funktion benutze, also immer).

Gibt es da keine bessere Lösung? Mache ich etwas falsch??
Jemand eine Idee?

greetz
Steffen

bhenker 21. Mär 2006 08:24

Re: Plugin-System mit Interfaces und DLLs
 
Hallo Steffen,

habe ein ähnliches Problem bei der Verwendung von Interfaces gehabt. Nachdem ich alle Interfaces per const übergeben habe, war das Problem gelöst. Delphi scheint einen Interface-Parameter ohne const am Ende der Funktion/Prozedur freizugeben. Da bei Dir der Referenzzähler auf 1 steht wird es freigegeben. Das eigentliche Objekt bekommt nichts davon mit und ist nach Aufruf der Funktion/Prozedur ungültig.
Ich hoffe es hilft Dir weiter.

Gruß Bernd

xaromz 21. Mär 2006 08:37

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,

ist FPmInterface ein TInterfacedObject oder ein Interface? Falls es ersteres ist, dann solltest Du das vergessen und nur das Interface speichern. Wenn Du nämlich ein TInterfacedObject erstellst und speicherts ist der Referenzzähler Null. Sobald Du dann das Interface benutzt wird der Referenzzähler erhöht und wieder vermindert -> Objekt wird freigegeben. Lästige Sache.
Siehe auch hier.

Gruß
xaromz

MasterEvil 21. Mär 2006 15:29

Re: Plugin-System mit Interfaces und DLLs
 
erstmal danke für eure Antworten:

@bhenker:
Werds mal ausprobieren, hatte das mit dem const aber in noch keinem Beispiel gesehen.

@xaromz:
Warum das passiert versteh ich jetzt, nur weiss ich nicht wie ich ohne das TInterfacedObject arbeiten soll.
Ich muss das ja erzeugen, um der DLL mein Interface zu geben.

greetz
Steffen

xaromz 21. Mär 2006 16:48

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,
Zitat:

Zitat von MasterEvil
Warum das passiert versteh ich jetzt, nur weiss ich nicht wie ich ohne das TInterfacedObject arbeiten soll.
Ich muss das ja erzeugen, um der DLL mein Interface zu geben.

Deine Klasse musst Du natürlich als TInterfacedObject deklarieren. Was Du aber nicht machen darfst, ist folgendes:
Delphi-Quellcode:
type
  TMyClass = class(TInterfacedObject, IMyInterface)
  end;

procedure MachWas(MyInterface: IMyInterface);
begin
  //
end;

var
  MyClass: TMyClass;

begin
  MyClass := TMyClass.Create;
  MachWas(MyClass);
  MyClass.Free; // <- hier knallts
end;
Stattdessen:
Delphi-Quellcode:
var
  MyInterface: IMyInterface;

begin
  MyInterface := TMyClass.Create;
  MachWas(MyClass);
  MyInterface := nil;
end;
Also durchgängig mit Interfaces arbeiten. Ich weiß aber gar nicht, ob Du sowas überhaupt machst.

Bei Interfaces ist es übrigens tatsächlich immer ratsam, mit const zu arbeiten. Ich hab mich schon gefragt, warum Delphi das nicht automatisch macht.

Gruß
xaromz

shmia 21. Mär 2006 17:37

Re: Plugin-System mit Interfaces und DLLs
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von MasterEvil
Dabei habe ich mich für die Arbeit mit Interfaces und DLLs entschieden.

Dies klappt im allgemeinen auch schon Recht gut. Ich durchsuche einen bestimmten Ordner nach dlls und lade diese nacheinander in einen Array, welcher alle nötigen Daten hält.

Da gibt es aber elegantere Möglichkeiten mit COM-Categories.
Du definierst zuerst eine COM-Categorie mit Namen und GUID.
Sowohl deiner Anwendung, als auch den Plugins ist diese GUID bekannt.
Jedes Plugin registriert sich selbst mit dieser GUID. Die Anwendung sucht und findet die Plugins über diese GUID.
Wo das Plugin auf der Platte liegt ist gleichgültig, es hindert dich aber niemand, alle in ein Verzeichnis zu packen.
Eine DLL kann mehr als ein Plugin enthalten.

MasterEvil 23. Mär 2006 08:11

Re: Plugin-System mit Interfaces und DLLs
 
@ xaromz:
mhh ok, versteh ich.
Aber kann es bei mir nicht anwenden :/
Weil wenn ich das mit dem Interface statt der Klasse als Variablen mache, kann ich auch nur auf Funktionen zugreifen, welche das Interface beschreibt. Ich brauche aber noch weitere Funktionen innerhalb meine Applikation, die von außen zugänglich sind, aber nicht vom Plugin aus.
Da steh ich gerade vor einem Problem :(
Hab auch dein Beschriebenes prob: wärend der Laufzeit funktioniert alles, aber wenn ich das Prog schließe und die Objekte freigeben möchte, knallts :/

@ shmia:
Danke für deine Idee, werd aber wohl erstmal bei Interfaces bleiben ;)

greetz
Steffen

xaromz 23. Mär 2006 08:26

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,

versuch mal folgendes:
Delphi-Quellcode:
var
  MyClass: TMyClass;

begin
  MyClass := TMyClass.Create;
  MyClass._AddRef;            // <- internen Zähler hochsetzen
  MachWas(MyClass);

  MyClass._Release;            // <- internen Zähler runtersetzen, Objekt wird freigegeben
  //MyClass.Free; // <- das hier entfernen
end;
Damit hebelst Du zwar den Garbage Collector etwas aus, aber wenn's läuft... :zwinker:

Gruß
xaromz

MasterEvil 23. Mär 2006 15:04

Re: Plugin-System mit Interfaces und DLLs
 
leider geht auch das nicht :(
Krieg da immer eine "invalid floating point operation". Egal ob ich es mit :=nil oder _Release mache ^^

:(

greetz
Steffen

shmia 23. Mär 2006 15:11

Re: Plugin-System mit Interfaces und DLLs
 
xaromz hat die Sache schon (fast) richtig erlärt:
Delphi-Quellcode:
var
  MyInterface: IMyInterface;
begin
  MyInterface := TMyClass.Create;
  MachWas(MyInterface); // "MyInterface" übergeben, nicht "MyClass"
// MyInterface := nil; // diese Zeile sparen wir uns, da "MyInterface" automatisch "out-of-scope" gerät
end;

MasterEvil 23. Mär 2006 15:28

Re: Plugin-System mit Interfaces und DLLs
 
also gar nicht freigeben? wird auch das Objekt selber entfernt am Ende?

greetz
Steffen

xaromz 23. Mär 2006 15:45

Re: Plugin-System mit Interfaces und DLLs
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

das Zerstören des Objekts überlässt Du dem GC. Daher ruf ich auch _Release auf. Durch das manuelle hochzählen des Referenzzählers steht der am Ende auf Eins. Um das Objekt zu zerstören, rufst Du _Release auf, womit der Zähler auf Null geht und das Objekt sich selbst zerstört. Deshalb ist auch kein Free nötig.

Ich häng mal ein Beispiel ran:
Die beiden oberen Buttons erstellen ein Objekt, einmal mit _AddRef, einmal ohne.
Der mittlere Knopf ruft eine Methode auf, der das Objekt als Interface übergeben wird.
Der untere Knopf zerstört das Objekt mit _Release.
Das Objekt gibt seinen Zustand mit einer MessageBox an.

Ich hoffe, damit wird es etwas klarer.

Gruß
xaromz

//Edit:
@shmia: So wie ich das verstanden habe, will er ja das Objekt in seiner Hauptanwendung weiterverwenden, also nicht nur für eine einzige Prozedur erstellen.

negaH 23. Mär 2006 18:22

Re: Plugin-System mit Interfaces und DLLs
 
Der Aufruf von ._AddRef() und ._Release() ist eine sehr schlechte Idee und sollte eigentlich niemals notwendig sein.

Bei der Benutzung von Interfaces in Delphi ist ein Punkt ganz wichtig: Alle Zugriffe auf ein Objekt sollten immer über das Interface erfolgen. Eine manuelle Freigabe der Objekte hinter dem Interface oder des Interfaces selber ist niemals notwendig.


Werden Interfaces als Paramater benutzt so sollte man diese als CONST deklarieren. Dies ist aber keine zwingende Notwendigkeit wenn man zb. die Variable selber in der Funktion noch weiter benutzen möchte. Der Unterschied zwischen CONST und nicht CONST ist nachfolgender:

Delphi-Quellcode:

procedure XYZ(MyIntf: IInterface);
// try                      
//   MyIntf._AddRef;      <- unsichtbarer Code durch den Compiler erzeugt
begin

  MyIntf := nil;        // zulässige Anweisung um das Interface "freizugebenen" innerhalb der lokalen Gültigkeit
//  MyIntf._Release;      <- unsichtbarer Code durch Compiler

  MyIntf := ABC;        // zulässig
//  MyInt._Release;       <- usichtbarer Code
//  ABC._AddRef  
//  MyIntf := ABC;


  MyIntf._Release;     // TÖDLICH und absolut FALSCH, Variable MyIntf ist weiter <> nil und erzeugt AV im
                        // letzten unsichtbaren try finally Block unten
end;
// finally                <- unsichtbarer    
//   MyIntf._Release;
// end;


procedure XYZ(const MyIntf: IInterface);
// <- KEIN try finally durch compiler
begin

  MyIntf := nil; // <- unzulässig da MyIntf ein Konstante
  MyIntf := ABC; // <- unzulässig

  MyIntf._Release; // eventuell TÖDLICH da das Interface danach einen Reference Counter von X -1 hat. Unter
                    // Umständen wird das Objekt hinter dem Interface freigegeben
                    // Es kann also auch erwünscht sein
end;
Man sieht das bei dem Aufruf mit CONST
1.) die Anwendung schneller wird weil der Compiler auf ein try finally Block verzeichten kann
2.) der Source SICHERER wird da man nicht unbeabsichtig wie im ersten Beispiel die Paramatervariable modifizieren kann


Bei der Erzeugung von Interface geht man immer so vor

Delphi-Quellcode:
var
  MyIntf: IInterface;
// try                          <- unsichtbarer Code des Compilers
//   Pointer(MyIntf) := nil;  
begin
  MyIntf := TObjectClass.Create;
  MyIntf.Methode1();
end;
// finally                      <- unsichtbarer Code
//   MyIntf._Release;
// end;
Man sieht auch hier wieder das ein Aufruf von ._AddRef() und ._Release() wiederum TÖDLICHE Konsequenzen haben wird.

Gruß Hagen

xaromz 23. Mär 2006 19:05

Re: Plugin-System mit Interfaces und DLLs
 
Hallo Hagen,
mit Deinen Ausführungen hast Du natürlich recht.
Weiter oben hat MasterEvil aber geschrieben, dass er im Hauptprogramm auf Methoden/Eigenschaften des Objektes zugreift, die nicht per Interface erreichbar sind. Das ist ja wegen der Sichtbarkeit vom "objektorientierten Standpunkt" aus auch gut so. Leider ist so ein Mix aber nicht wirklich gefahrlos möglich, da er zu den beschriebenen Seiteneffekten führt.
Übrigens kann man manchmal auf die beiden Methoden _AddRef und _Release nicht verzichten. Mas muss nur wissen, was man tut (Ich musste mir auch mal meine eigene Implementierung der beiden Methoden schreiben, aber das ist 'ne andere Geschichte).

Gruß
xaromz

jbg 23. Mär 2006 19:41

Re: Plugin-System mit Interfaces und DLLs
 
Ich habe mir für ein Programm ein Klasse geschrieben, die erst auf die Interface-Referenzzählung "hört", wenn ich mittels einer eigenen Methode "Release" (unterschied zu _Release) als Freizugeben markiert habe. Damit kann ich das Objekt auch ohne Interface nutzen. Defekte Plugins zerschießen mir damit auch nicht das gesamte Programm.

Delphi-Quellcode:
type
  TInterfaceNeutralObject = class(TModifyObject)
  private
    FRefCount: Integer;
    FAllowRelease: Boolean;
  protected
    procedure CleanUp; virtual; // hier den Destruktorcode einfügen
  public
    destructor Destroy; override;
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;

    procedure Release; // Statt .Free muss Release aufgerufen werden
  end;

{ TInterfaceNeutralObject }

function TInterfaceNeutralObject.QueryInterface(const IID: TGUID; out Obj): HRESULT;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := E_NOINTERFACE;
end;

procedure TInterfaceNeutralObject.Release;
begin
  if (FRefCount = 0) and not FAllowRelease then
  begin
    CleanUp;
    FAllowRelease := True;
    Free;
  end
  else
  begin
    CleanUp;
    FAllowRelease := True;
    if FRefCount = 0 then
      Free;
  end;
end;

procedure TInterfaceNeutralObject.CleanUp;
begin
end;

function TInterfaceNeutralObject._AddRef: Integer;
begin
  Result := -1;
  Inc(FRefCount);
end;

function TInterfaceNeutralObject._Release: Integer;
begin
  Result := -1;
  Dec(FRefCount);
  if (FRefCount <= 0) and FAllowRelease then
    Free;
end;

destructor TInterfaceNeutralObject.Destroy;
begin
  {$IFDEF INTFDEBUG}
  if not FAllowRelease then
    //raise Exception.CreateFmt('InterfaceNeutralObject "%s" was not destroyed by Release', [ClassName]);
    MessageBox(0, PChar(Format('InterfaceNeutralObject "%s" was not destroyed by Release', [ClassName])), 'Error', MB_ICONHAND or MB_OK);
  {$ENDIF INTFDEBUG}
  inherited Destroy;
end;
Aber wenn man es richtig macht, dann sollte man besser ein weiteres Interface deklarieren, dass dann den Zugriff auf die "versteckten" Eigenschaften erlaubt. Dem Plugin-System muss man dieses Interface ja nicht verraten. Alternativ kann man auch eine GetObject: TObject Methode dem Interface hinzufügen, dass dann das dahinterliegende Objekt zurückliefert.

negaH 23. Mär 2006 21:30

Re: Plugin-System mit Interfaces und DLLs
 
Man kann ein Objekt auch gemischt mit Interfaces benutzen, das geht dann so:

Delphi-Quellcode:
var
  Obj: TMyObject;
  Intf: IInterface;
begin
  Obj := TMyObject.Create;
  Intf := Obj;

  Intf.MethodA();
  Obj.MethodA();

end;
Wichtig ist nur:

sobald man eine Interface Variable mit dem einer Objektvariable zugewiesen hat wirkt das automatische Referencecounting der Interfaces und dem Delphi Compiler. D.h. die variable Obj muß und darf nicht mehr über .Free oder so freigegeben werden.

Diese Ausführungen beziehen sich natürlich nur auf Klassen die auch eine Referenzzählung implementieren und diese auch benutzen.

Man kann es auch so machen:

Delphi-Quellcode:

type
  IPublicInterface = interface
    {GUID} 
    function MethodA: Integer;
  end;

implementation

type
  TMyObject = class;

  ISelf = interface
    {GUID}
    function _Self: TMyObject;
  end;

  TMyObject = class(TInterfacedObject, IPublicInterface, ISelf)
    function MethodA: Integer;
    function _Self;
  end;

function TMyObject.MethodA: Integer;
begin
  Result := 0;
end;

function TMyObject._Self: TMyObject;
// Nichts, In EAX == versteckter 1. Parameter ist Self schon drinnen, und Result == EAX
begin
end;


procedure Test;
var
  Intf: IInterface;
begin
  Intf := TMyObject.Create;

  (Intf as ISelf)._Self.MethodA;
end;

Gruß Hagen

mirage228 23. Mär 2006 21:36

Re: Plugin-System mit Interfaces und DLLs
 
Hi Hagen,

Ich glaube bei dir hat sich ein kleiner Schreibfehler eingeschlichen.
Bei der Dekleration der Funktion "_Self" hast Du den Ergebnistypen vergessen:
Delphi-Quellcode:
function _Self: TMyObject; //: TMyObject; fehlte
mfG
mirage228

xaromz 23. Mär 2006 21:41

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,
Zitat:

Zitat von negaH
Wichtig ist nur:

sobald man eine Interface Variable mit dem einer Objektvariable zugewiesen hat wirkt das automatische Referencecounting der Interfaces und dem Delphi Compiler. D.h. die variable Obj muß und darf nicht mehr über .Free oder so freigegeben werden.

Das ist noch nicht alles. Schau Dir mal mein Demoprogramm an. Da wird das Objekt schon durch den Aufruf einer Prozedur (mit dem Objekt als Parameter) freigegeben, weil eben die Referenzzählung durcheinendergerät.

Gruß
xaromz

negaH 24. Mär 2006 04:28

Re: Plugin-System mit Interfaces und DLLs
 
Zitat:

Das ist noch nicht alles. Schau Dir mal mein Demoprogramm an. Da wird das Objekt schon durch den Aufruf einer Prozedur (mit dem Objekt als Parameter) freigegeben, weil eben die Referenzzählung durcheinendergerät.
Nein, die Referenzzählung arbeitet einwandfrei, du machst einfach einen logischen Denkfehler.

Delphi-Quellcode:


procedure TuWas(Intf: IInterface);
// try
//   Intf._AddRef  <-  Referenzcounter ist jetzt +1
begin
end;
// finally
//   Intf._Release; <- Referenzcounter ist jetzt 0, ergo Object wird freigegeben
// end;

procedure Test1;
begin
  TuWas(TMyObject.Create); // <- hier impliziter Aufruf, KEINE SICHTBARE Referenzzählung
end;

procedure Test2;
var
  Intf: IInterface;
begin
  Intf := TMyObject.Create;
  TuWas(Intf);
end;
Bei Test1 existiert defakto KEIN lokaler Gültigkeitsbereich für ein Interface. Ergo wenn man ein Object direkt einer Funktion übergibt die ein Interface erwartet und dieses NICHT als const deklariert hat, so wird das Objekt zerstört. Das ist auch logisch, denn betrachte mal den Fall das man TuWas() aufruft mit einem gerade frisch allozierten Interface das später im Program NICHT weiter benutzt wird. Würde der Compiler anderes arbeiten würde dieses allozierte Interface als Speicherleiche übrig bleiben.

Bei Test2 hat man nun explizit das erzeugte Object in eine Interfacevariable gespeichert. Man hat also damit auch explizit eine Scope=Gültigkeitsbereich der offensichtlich die Scope der lokalen Funktion ist, bzw. des lokalen Stacks. Der Compiler kann nun, weil WIR es IHM auch gesagt haben, das Refenerenzecounting benutzen.

Es lässt sich nun streiten ob es nicht richtiger von Borland gewesen wäre für den Testfall in Test1 temporär eine "unsichtbare" lokale Interfacevariable anzulegen die dann gleich nach Rückkehr von TuWas auf nil gesetzt, ergo freigegeben wird. Das ändert nämlich nichts am Sachverhalt das diese Temporäre unsichtbare Interfacevariable wiederum inetwa so aussähe:

Delphi-Quellcode:
 
//  try
//    Temp := MyObject; // RefCounter == +1
   TuWas(Temp);
//  finally
//    Temp._Release ;   // RefCounter == 0, ergo MyObject.Free
//  end;
Du siehst in jedem Falle würde nach dem Aufruf von TuWas() das Objekt immer fregegeben werden.
Das liegt einfach daran das der Compiler nicht das wissen kann was DU einfach mal so vorraussetzt. Nämnlich das FMyObject ein Feld deiner TForm Klasse ist und somit aus DEINER Sicht eine globale Gültigkeit besitzt.
Demo ist aber tatsächlich nicht so, da FMyObject eine Klasse ist und kein Interface !!

Eines ist also sicher, dieses Verhalten ist durchaus logisch, aber leider nicht so richtig dokumentiert.

Fazit: wenn man mit Objekten und Interfaces arbeiten möchte dann sollte man immer mit Hilfe einer lokalen Interfacevariablen, in der man das Object speichert, arbeiten.

Wenn DU also möchtest das dein FMyObject global zur kompletten laufzeit deines TForm auch gültig bleibt dann musst DU dies dem Compiler auch sagen. Inetwa so

Delphi-Quellcode:
type
  TForm1 = class
    FMyObject: TMyObject;
    FMyObjectIntf: IInterface;
  end;

procedure TForm1.FormCreate();
begin
  FMyObject := TMyObject.Create;
  FMyObjectIntf := FMyObject;
end;
Fertig ! Beim zerstören von TForm1 wird FMyObjectIntf automatisch auf nil gesetzt, ergo auch FMyObject.Free aufgerufen.

Gruß Hagen

xaromz 24. Mär 2006 08:55

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,
Zitat:

Zitat von negaH
Nein, die Referenzzählung arbeitet einwandfrei, du machst einfach einen logischen Denkfehler.

Ich hab' da keinen Denkfehler, keine Angst. Erklärung folgt.
Zitat:

Zitat von negaH
Bei Test1 existiert defakto KEIN lokaler Gültigkeitsbereich für ein Interface. Ergo wenn man ein Object direkt einer Funktion übergibt die ein Interface erwartet und dieses NICHT als const deklariert hat, so wird das Objekt zerstört. Das ist auch logisch, denn betrachte mal den Fall das man TuWas() aufruft mit einem gerade frisch allozierten Interface das später im Program NICHT weiter benutzt wird. Würde der Compiler anderes arbeiten würde dieses allozierte Interface als Speicherleiche übrig bleiben.

Du benutzt aber ein anderes Beispiel als wir hier diskutieren. Bei uns sieht das so aus:
Delphi-Quellcode:
procedure Test1;
begin
  FMyObject := TMyObject.Create;
  TuWas(FMyObject);

  TuWasAnderes(FMyObjekt);
end;
Hier knallts, weil eben der erste Aufruf den Referenzzähler erhöht und wieder vermindert, wodurch das Objekt freigegeben wird. Bei TuWasAnderes ist also das Objekt schon zerstört.
Natürlich ist dieses Verhalten korrekt (was die Referenzzählung von Interfaces angeht), aber, und das ist der Punkt, unerwartet. Wer noch nicht so viel Ahnung von Interfaces hat, würde annehmen, dass FMyObjekt ja auch eine Refernez ist, aber auf das Objekt. Nur gibt's bei Objekten keinen Referenzzähler :( . Darum geht's mir, ich will nur auf diese Stolperfalle hinweisen. Und hier könnte der Delphi-Compiler tatsächlich erkennen, dass ich das Objekt nicht freigeben will und noch einen Referenzblock rumbasteln. Da Delphi das nicht macht, kann man es selbst machen.
Zitat:

Zitat von negaH
Fazit: wenn man mit Objekten und Interfaces arbeiten möchte dann sollte man immer mit Hilfe einer lokalen Interfacevariablen, in der man das Object speichert, arbeiten.

Was übrigens das Gleiche macht, wie ich, nur implizit statt explizit.

Aber wie wäre es eigentlich damit, und hier sind wir wieder beim Thema des Threads, wenn das Objekt zwei Interfaces implementiert, wobei nur das eine an das Plugin weitergegeben wird, während das andere im Hauptprogramm verwendet wird? So bräuchts man sich nicht mit diesem Problem rumschlagen.

Gruß
xaromz

jbg 24. Mär 2006 09:06

Re: Plugin-System mit Interfaces und DLLs
 
Zitat:

Zitat von xaromz
Aber wie wäre es eigentlich damit, und hier sind wir wieder beim Thema des Threads, wenn das Objekt zwei Interfaces implementiert, wobei nur das eine an das Plugin weitergegeben wird, während das andere im Hauptprogramm verwendet wird? So bräuchts man sich nicht mit diesem Problem rumschlagen.

Hatte ich das nicht schon vorgeschlagen?
Zitat:

Zitat von jbg
Aber wenn man es richtig macht, dann sollte man besser ein weiteres Interface deklarieren, dass dann den Zugriff auf die "versteckten" Eigenschaften erlaubt


xaromz 24. Mär 2006 09:15

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,
Zitat:

Zitat von jbg
Zitat:

Zitat von xaromz
Aber wie wäre es eigentlich damit, und hier sind wir wieder beim Thema des Threads, wenn das Objekt zwei Interfaces implementiert, wobei nur das eine an das Plugin weitergegeben wird, während das andere im Hauptprogramm verwendet wird? So bräuchts man sich nicht mit diesem Problem rumschlagen.

Hatte ich das nicht schon vorgeschlagen?
Zitat:

Zitat von jbg
Aber wenn man es richtig macht, dann sollte man besser ein weiteres Interface deklarieren, dass dann den Zugriff auf die "versteckten" Eigenschaften erlaubt


Tatsache. Hatte ich überlesen.

Gruß
xaromz

negaH 24. Mär 2006 13:34

Re: Plugin-System mit Interfaces und DLLs
 
Delphi-Quellcode:
Darum geht's mir, ich will nur auf diese Stolperfalle hinweisen. Und hier könnte der Delphi-Compiler tatsächlich erkennen, dass ich das Objekt nicht freigeben will und noch einen Referenzblock rumbasteln. Da Delphi das nicht macht, kann man es selbst machen.
Nein, und das darf der Compiler eben nicht, bzw. er kann es auch garnicht.
Das verhalten ein Object zu erstellen und dieses dann impliziert als Interface nach Gebrauch zerstören zu lassen ist absolut erwünscht und korrekt. Nicht nur aus Sicht eines Delphi Programmierers sondern aus genereller Sicht bei der Benutzung von Interfaces. Sobald man auf die Ebene von Interfaces wechselt gelten deren Regeln auch für Objekte, Punkt.

Delphi-Quellcode:
Was übrigens das Gleiche macht, wie ich, nur implizit statt explizit.
Das Gleiche im Sinne der internen Arbeitsweise ist nicht das Gleiche im Sinne des Verstehens, Lesbarkeit und Portierungssicherheit eines Sources. Ich kann die explizite Anwendung von ._AddRef und ._Release im Vergleich zur Benutzung einer Interfacevariablen und dem Asunuztzen der natüelichen Fähigkeiten des Compilers nicht empfehlen.

Delphi-Quellcode:
Aber wie wäre es eigentlich damit, und hier sind wir wieder beim Thema des Threads, wenn das Objekt zwei Interfaces implementiert, wobei nur das eine an das Plugin weitergegeben wird, während das andere im Hauptprogramm verwendet wird? So bräuchts man sich nicht mit diesem Problem rumschlagen.
versteht und benutzt man Interfaces einfach auf korrekte Art dann ist das KEIN Problem ergo ist die doppelte Benutung von doppelten Interfaces nur ein doppeltgemoppelter Aufwand der unnötig ist.

Das ist so also ob man an einem Auto noch zusätzlich 4 grüne Räder anbringt damit man mit 4 scharzen Rädern die an 4 roten Räder montiert sind fahren kann.

Wie gesagt das einzigste Problem ist das man als Entwickler sich in die Funktionsweise von Interfaces einarbeiten muß. Das spezielle Verhalten von Objekten ohne RefCounter als Interfaces mit RefCounter ist nicht nur in Delphi so sondern auch in anderen Programmiersprachen. Das "Problem" ansich ist schon sehr oft, schon vor Jahren, in den einschlägigen Newsgroups diskutiert worden.
Es ist defakto garkein "problem" im Compiler oder im Konzept Object->Interface, sondern nur ein Problem im Verständnis des Programmiers.

Fange doch mal an das Pferd richtig aufzuzäumen und entwickle mal von Grund auf ein eigenes Konzept von Interfaces und RefCounter innerhalb von Klassen. Du wirst sehen, egal wie du es konstruierst du wirst IMMER auf exakt das Verhalten wie es jetzt in Delphi ist kommen.

Gruß Hagen

xaromz 24. Mär 2006 13:52

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,
Zitat:

Zitat von negaH
Sobald man auf die Ebene von Interfaces wechselt gelten deren Regeln auch für Objekte, Punkt.

Die Regeln von Interfaces können niemals für Objekte gelten, da Objekte keine Interfaces sind. Aber ich weiß, was Du meinst :wink: .
Zitat:

Zitat von negaH
versteht und benutzt man Interfaces einfach auf korrekte Art dann ist das KEIN Problem ergo ist die doppelte Benutung von doppelten Interfaces nur ein doppeltgemoppelter Aufwand der unnötig ist.

Das ist so also ob man an einem Auto noch zusätzlich 4 grüne Räder anbringt damit man mit 4 scharzen Rädern die an 4 roten Räder montiert sind fahren kann.

Schade, dass Du nicht verstanden hast, um was es eigentlich geht.
Zitat:

Zitat von negaH
Fange doch mal an das Pferd richtig aufzuzäumen

:?:
Zitat:

Zitat von negaH
und entwickle mal von Grund auf ein eigenes Konzept von Interfaces und RefCounter innerhalb von Klassen. Du wirst sehen, egal wie du es konstruierst du wirst IMMER auf exakt das Verhalten wie es jetzt in Delphi ist kommen.

Das weiß ich durchaus. Das System ist ja auch gut so. Wie gesagt, ich weise nur auf die möglichen Seiteneffekte hin.

Gruß
xaromz

negaH 24. Mär 2006 14:12

Re: Plugin-System mit Interfaces und DLLs
 
@Xarmoz:

Ich verstehe deine "Probleme" sehr wohl, aber sehe es einfach nicht als "Problem". Du machst aus deinem Problem ein Problem das angeblich in Delphi existieren soll und schlägst Lösungen vor die dein "Problem" im Endeffekt nur noch verschlimmbesseren.

Und exakt damit habe ICH ein Problem. Und das habe ich versucht hier für andere Leser des Threads exakt herauszuarbeiten.

Es existiert einfach kein Problem mit Objekten und Interfaces in Delphi, das was problematisch ist ist einfach die Tatsache des Verständnisses wie alles zusammenhängt.

Schlußendlich meine ich aber das wir beide auf das Gleiche hinauswollen (und das ist das Einzigste ws zählt), es aber eben aus anderen Blickwinkeln betrachten ;)

Gruß Hagen

xaromz 24. Mär 2006 14:40

Re: Plugin-System mit Interfaces und DLLs
 
Hallo,
Zitat:

Zitat von negaH
Schlußendlich meine ich aber das wir beide auf das Gleiche hinauswollen (und das ist das Einzigste ws zählt), es aber eben aus anderen Blickwinkeln betrachten ;)

:thumb:

Gruß
xaromz

MasterEvil 25. Apr 2006 21:40

Re: Plugin-System mit Interfaces und DLLs
 
Huhu,

erstmal sorry, dass ich so lang nichts geschrieben hab, war erst im Urlaub und danach hab ich eure Anmerkungen erstmal umgesetzt.

Ich in jetzt so gut wie fertig (jedenfalls mit Version 1, das ding wächst ja mit meinem PM mit) und es klappt wunderbar.
Vielen dank also für eure ausführliche Hilfe! :)

Da ihr euch ja so gut auskennt, habt ihr eventuell ja auch eine Lösung für dieses (dazugehörige) Problem:
DLL Formular Problem

greetz
Steffen


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