AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Objekte zw. Programm und DLL austauschen - Interfaces?
Thema durchsuchen
Ansicht
Themen-Optionen

Objekte zw. Programm und DLL austauschen - Interfaces?

Ein Thema von Namenloser · begonnen am 6. Sep 2008 · letzter Beitrag vom 6. Sep 2008
Antwort Antwort
Seite 1 von 2  1 2      
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#1

Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 20:23
Hallo DP-User

ich schreibe gerade an einer kleinen Client/Server-Anwendung. Um das ganze möglichst flexibel zu halten, nutze ich ein selbstentwickeltes XML-ähnliches, binäres Format und habe an eine Plugin-Architektur gedacht.

Dabei exportiere ich in der DLL eine Register-Funktion, die die Adressen aller in dieser DLL enthaltenen Funktionen mit Funktionsnamen in eine Liste im Hauptprogramm einträgt (ähnlich wie es Delphi mit BPLs macht).
Wenn der Server einen Befehl bekommt, schaut er in seiner Liste nach und führt, wenn der Befehlsname in der Liste enthalten ist, das zugehörige Callback aus. Ich dachte daran, den Funktionen aus der DLL als Parameter einfach einen meiner "XML"-Tags zu übergeben, der wiederum andere Tags enthalten kann. So könnte ich die Parameterübergabe flexibel gestalten. KÖNNTE: Denn ich kann in der DLL nicht auf die Objekte aus dem Hauptprogramm zugreifen. Ich vermute, das liegt daran, dass DLL und Hauptprogramm jeweils ihre eigene RTL, VCL usw. haben.

Ich vermute, dass ich dafür Interfaces benutzen muss. Mit denen habe ich aber noch nie gearbeitet.
Helfen die denn überhaupt bei diesem Problem? Muss ich für alle bereits vorhandenen XML-Klassen, die ich in der DLL benutzen möchte, entsprechende Interfaces deklarieren?
Das Problem ist nämlich, dass ich die Objekte nicht nachträglich von TInterfacedObject ableiten kann, weil sei teilweise schon von anderen Klassen abgeleitet sind. Heißt das wiederum, ich muss für jede Klasse eine Wrapperklasse konstruieren? Gibt es vielleicht Tools, die sowas automatisieren?


Also am liebsten wäre es mir, wenn es eine andere Lösung gäbe...
Im schlimmsten Falle könnte ich vielleicht den Inhalt der Tags in einen Buffer speichern und hinterher wieder einlesen
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#2

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 20:31
Ja, Interfaces sind in diesem Zusammenhang durchaus recht nützlich. Sie werden nämlich nicht nach Adresse verglichen wie Klassen (was dort dazu führt, dass as und is fehlschlagen können, weil DLL.Klasse <> Hauptprogramm.Klasse), sondern nach GUID, welche natürlich überall gleich ist.

Dass du nicht von TInterfacedObject ableiten kannst, ist alles andere als tragisch. Die Implementierung der drei IInterface-Methoden ist äußerst kurz, du kannst sie einfach kopieren.
Zur Frage, ob du zu jeder Klasse ein Interface deklarieren musst: Das Interface legt die Schnittstelle fest. Alles, was daher außerhalb des Moduls verwendet werden soll, sollte daher in einem Interface deklariert werden.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#3

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 20:35
Delphis XMLDocument ist bereits interface-basiert: IXmlDocument.
Was du beachten musst ist, dass die Lebensdauer von Interfaces durch Referenzzählung verwaltet wird.
Wenn du einer Interface variable ein Objekt zuweist, dann wird dessen Zähler erhöht, aber wenn du aus den Scope rennst, dann wird er wieder um 1 reduziert.
Erreicht er 0 wird die Instanz vernichtet.

IOW: Wenn du ein Objekt überall als Klasse, nicht Interface, nutzt, dann könnte eine einmalige Zuweisung zu einer Interface instanz dieses Objekt zerstören wenn du die Methode verlässt.

Ein Trick wäre den Referenzzähler künstlich um 1 zu erhöhen. (_AddRef)
Wenn du es nur als Parameter übergibst, kannst du diesen auch als "const" deklarieren. Genau wie bei AnsiString wird dabei die Referenzzählung ignoriert.

Hier passiert nix:
Delphi-Quellcode:
procedure Miep.DoSomething(const instance : ISomeInterface);
begin
  instance.SomeMethod();
end;
Das hier ist aber GANZ böse:
Delphi-Quellcode:
procedure Miep.DoSomething(const instance : ISomeInterface);
var
  tmp : ISomeInterface;
begin
  tmp : instance;
end;
Wenn du in DoSomething ein Objekt wirfst, dann wird beim Zuweisen zu tmp der Referenzzähler auf 1 erhöht. Beim Verlassen der Methode aber reduziert und dadurch wird das Objekt zerstört.
Du kannst dem generell entgegenwirken, wenn du dafür sorgst, dass der Zäher immer mindestens 1 ist. Das erreichst du wenn du einmal _AddRef auf die Instanz ausführst.

Die coolste Lösung ist gar keine Objektreferenzen von diesen Instanzen zu benutzen. Weder in der Exe noch in ener DLL. Dadurch funktioniert die Referenziertzählung überall und Objekte werden autom. freigegeben.
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#4

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:03
Danke für die Antworten

@Elvis:
Wie gesagt, meine Klass eist nur XML-ähnlich aufgebaut von der Struktur her. Es ist aber ein eigenes, binäres Format. Ich habe mich gegen XML entschieden, weil die Kommunikation über das Internet laufen soll, und ich den Größenzuwachs bei XML insbersondere bei Binärdaten vermeiden will. Deshalb kann ich die Klasse von Delphi nicht benutzen.

Wie kann ich denn völlig ohne Objektreferenzen arbeiten? Irgendwo muss das Objekt doch mal erzeugt werden

@Apollonius:
Ist es denn sinnvoll, den Code zu kopieren? Es sind zwar nicht sehr viele Klassen, aber irgendwie widerstrebt mir das.


Zur Zeit sieht meine Deklaration so aus:
Delphi-Quellcode:
  TBinXMLValue = class(TMemoryStream)
  private
    function getAsBoolean: boolean;
    function getAsFloat: extended;
    function getAsInt64: int64;
    function getAsLongint: longint;
    function getAsString: string;
    procedure setAsBoolean(const Value: boolean);
    procedure setAsFloat(const Value: extended);
    procedure setAsInt64(const Value: int64);
    procedure setAsLongInt(const Value: longint);
    procedure setAsString(Value: string);
  protected
    procedure SaveToStream(const aStream: TStream);
    procedure LoadFromStream(const aStream: TStream);
  public
    constructor Create;
    property AsString: string read getAsString write setAsString;
    property AsLongint: longint read getAsLongint write setAsLongInt;
    property AsInt64: int64 read getAsInt64 write setAsInt64;
    property AsFloat: extended read getAsFloat write setAsFloat;
    property AsBoolean: boolean read getAsBoolean write setAsBoolean;
  end;

  TBinXMLTag = class
  private
    FName: string;
    FChildren: TBinXMLTaglist;
    FParent: TBinXMLTag;
    FValue: TBinXMLValue;
    procedure SetName(const Value: string);
  protected
    procedure SetParent(const Value: TBinXMLTag);
    procedure SaveToStream(const aStream: TStream);
    procedure LoadFromStream(const aStream: TStream);
  public
    constructor Create(const aParent: TBinXMLTag = nil);
    destructor Destroy; override;

    property Name: string read FName write SetName;
    property Parent: TBinXMLTag read FParent;
    property Children: TBinXMLTaglist read FChildren;
    function NewChild(const aName: string=''): TBinXMLTag;
    property Value: TBinXMLValue read FValue;
  end;

  TBinXMLTagList = class(TObjectList)
  private
    FParent: TBinXMLTag;
    function GetItem(index: integer): TBinXMLTag;
    procedure SetItem(index: integer; const Value: TBinXMLTag);
    procedure FreeAllItems;
    function GetItemByName(Name: string): TBinXMLTag;
  protected
    procedure SetParent(const Value: TBinXMLTag);
    procedure SaveToStream(const aStream: TStream);
    procedure LoadFromStream(const aStream: TStream);
  public
    constructor Create(const aParent: TBinXMLTag = nil);
    property Parent: TBinXMLTag read FParent;
    property Items[index: integer]: TBinXMLTag read GetItem write SetItem; default;
    property ItemByName[Name: string]: TBinXMLTag read GetItemByName;
    function Add(AItem: TBinXMLTag): integer;
  end;
Es gibt noch ein TBinXMLDocument, das ich aber in der DLL nicht brauchen werde. Wie könnte man bei den obigen Deklarationen am sinnvollsten Interfaces einflicken?
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:07
TInterfacedObject implementiert mit den drei Methoden die Referenzzählung und den as-Operator. Es gibt kaum andere sinnvolle Implementation (sieht man von Fällen ab, in denen man die Referenzzählung ausschalten will). Daher spricht eigentlich nichts gegen eine reine Kopie.

Bezüglich Objektreferenzen: Die Idee ist, dass du nirgendwo eine Variable vom Typ TBinXMLValue deklarierst, sondern immer nur IBinXMLValue. TBinXMLValue kommt damit nur noch im Ausdruck TBinXMLValue.Create vor.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#6

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:11
Zitat von Apollonius:
Bezüglich Objektreferenzen: Die Idee ist, dass du nirgendwo eine Variable vom Typ TBinXMLValue deklarierst, sondern immer nur IBinXMLValue. TBinXMLValue kommt damit nur noch im Ausdruck TBinXMLValue.Create vor.
Okay, das macht Sinn. Aber wie gebe ich das Objekt dann frei? Ich habe im Hinterkopf, dass man dazu dem Interface nil zuweisen muss. Ist das korrekt?
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:19
Delphi macht das automatisch, z.B. wird in Prozeduren, bei denen eine lokale Variable ein Interface (oder ein langer String, dynamisches Array oder Variant) ist, automatisch ein Try-Finally-Block generiert, wodurch das _Release sichergestellt wird. Bei Klassen und Records läuft es ähnlich.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#8

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:24
Ja, aber TBinXMLValue wird ja z.B. in TBinXMLTag.Create erzeugt. Wenn ich jetzt statt TBinXMLValue IBinXMLValue benutzen würde, sähe das doch immer noch so aus:
Delphi-Quellcode:
constructor TBinXMLTag.Create;
begin
  // FValue = IBinXMLValue
  FValue := TBinXMLValue.Create;
end;
Was schreibe ich dann in den Destruktor? Oder macht Delphi das auch automatisch?

Danke für deine Hilfe
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:28
Ja, alle finalisierungsbedürftigen Felder sind in einer Tabelle in der Klassenstruktur gespeichert. CleanupInstance (welches von TObject.FreeInstance verwendet wird) ruft für alle Interfaces dann _Release auf.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Elvis

Registriert seit: 25. Nov 2005
Ort: München
1.909 Beiträge
 
Delphi 2010 Professional
 
#10

Re: Objekte zw. Programm und DLL austauschen - Interfaces?

  Alt 6. Sep 2008, 21:28
Zitat von NamenLozer:
Aber wie gebe ich das Objekt dann frei? Ich habe im Hinterkopf, dass man dazu dem Interface nil zuweisen muss. Ist das korrekt?
Wenn du eine Klasse hast, die ein Feld deines Interfaces besitzt, dann wird im Destruktor autom. der Referenzzähler reduziert.

Hier mal ein Beistift, den ich mir jetzt nur im Browser aus den Fingern gesaugt habe.
Du solltest die Meldung aus InnerMiep.DomeSothing sehen, und wenn du Test() verlässt, sollte "Futsch!" erscheinen.
Delphi-Quellcode:
type
  ISomeInterface = interface
  ['...']
    procedure DoSomething; stdcall;
  end;

  InnerMiep = class(TInterfaceObject, ISomeInterface)
  public
    procedure DoSomething; stdcall;
    destructor Destroy; override;
  end;

  Miep = class(TInterfaceObject, ISomeInterface)
  private
    fValue : ISomeInterface;
  public
    // diese property implementiert das Interface
    property Value : ISomeInterface
      implements ISomeInterface;
    procedure AfterConstruction; override;
  end;

...

procedure Miep.AfterConstruction;
begin
  inherited;
  fValue := InnerMiep.Create();
end;

procedure InnerMiep.DoSomething;
begin
  ShowMessage('Hmmm, don''t really know what exactly to do here...');
end;

destructor InnerMiep.Destroy;
begin
  ShowMessage('Futsch!');
  inherited;
end;

...

procedure Test;
var
  xyz : ISomeInterface;
begin
  xyz := Miep.Create();
  xyz.DoSomething();
end;
Robert Giesecke
I’m a great believer in “Occam’s Razor,” the principle which says:
“If you say something complicated, I’ll slit your throat.”
  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 12:32 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