Interfaces, Objecte und Bibliotheken

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Interfaces, Objecte und Bibliotheken

Beitrag von Socke »

Hallo,
aktuell baue ich an einer Anwendung, die auf einer Bibliothek aufsetzt. Dabei soll die Anwendung eigentlich nur ein Frontend für die Bibliothek sein (d.h. möglichst wenig eigener Code).
Dazu wollte ich in der Bibliothek ein paar Objekte erstellen, welche die gesamten Daten und die dazugehörigen Funktionen (= Sinn eines Objekts), enthalten. Die Bibliothek hätte dann jeweils eine procedure/function um die Objekte zu erstellen bzw. wieder frei zu geben. Ausgetauscht werden dabei dann die Pointer auf die Objekte.

Jetzt stellt sich mir jedoch die Frage, wie mein Frontend auf die Objekte zugreifen soll.
Mein erster Ansatz waren Funktionen in der Bibliothek, die die entsprechenden Objekt-Methoden aufrufen (das zu bearbeitende Objekt wird als Parameter übergeben). Damit hätte ich jedoch etliche Funktionen, die eigentlich nichts, außer Objekt-Methoden kapseln, machen. Dann wäre die schöne Objektorientierung aber hinfällig (-> ich habe nur Funktionen/Prozeduren).
Eine Variante davon wäre, eine zusätzliche Klasse zu erstellen, die die Funktionen kapselt, sodass im Frontend eine Klasse benutzt werden kann. Die Funktionen werden dann indirekt über eben diese Klasse aufgerufen.

Ein anderer Ansatz wären (hoffentlich) Interfaces. Mit denen habe ich jedoch nicht sehr viel Erfahrung und im Internet findet sich wenig über Objekte mit Interfaces, die zwischen verschiedenen Anwendungen (bzw. Bibliotheken) ausgetauscht werden.
Meine Versuche dahin gehend scheitern am Freigeben der Objekte.

Code: Alles auswählen

// erzeugt eine neue Instanz meiner Klasse
function CreateInterface: TInterfacedObject; stdcall; external 'lib1.dll';
// gibt eine Instanz meiner Klasse frei
procedure FreeInterface( AObject: TInterfacedObject ); stdcall; external 'lib1.dll';
// TInterfacedObject weil in Bibliothek und Anwendung vorhanden
var o: TInterfacedObject;
      i: IBInterface;  // so heißt mein Interface
begin
  WriteLn('Trying to get Object');
// Objekt erzeugen
  o := CreateInterface;
  WriteLn('Got Object: ',IntToHex(PtrUInt(o),6));
// überprüfen, ob IBInterface unterstützt wird
  if Supports(o, IGuid, i) then
  begin
// eine Methode des Interfaces aufrufen
    WriteLn('Result of ''IBInterface.GetInteger'': ',i.GetInteger);
  end;
 
  WriteLn('Trying to free interfaced object');
// objekt freigeben
  FreeInterface(o);
  WriteLn('Object freed');
  ReadLn;
end;
Der Fehler tritt beim Freigeben des Objektes auf (EInvalidPointer), aber nur, wenn ich mit Support(Objekt, GUID, Interface) die Interface-Unterstützung überprüfe! Wenn ich nur das Objekt erstelle und wieder frei gebe, funktioniert alles ohne Fehler. Wenn ich nur die Unterstützung überprüfe, mir aber keinen Pointer auf das Interface zurück geben lasse (und es somit auch nicht benutze), gibts nur noch "External: SIGSEGV". Der Debugger hält dann die Ausführung an und zeigt als Prozedur "SYSTEM_TOBJECT_$__FREE" an.

Hat jemand hier Erfahrung mit Interfaces oder andere Ideen?
Was genau macht Supports? Ich konnte die Implementation nicht finden... Bzw. warum ist meine Objektvariable danach nicht mehr nutzbar?

MfG Die Socke

P.S. Der Roman zu meinem Problem wird demnächst überall im Handel verfügbar sein :lol:

pluto
Lazarusforum e. V.
Beiträge: 7192
Registriert: So 19. Nov 2006, 12:06
OS, Lazarus, FPC: Linux Mint 19.3
CPU-Target: AMD
Wohnort: Oldenburg(Oldenburg)

Beitrag von pluto »

amit hätte ich jedoch etliche Funktionen, die eigentlich nichts, außer Objekt-Methoden kapseln
Schau dir mal die Lazarus Soruce an... du wirst festellen das sie Teilweise nix anders machen. als Methoden weiter zu leiten.
Interfaces
Sind zwar nicht schlecht.... stellen aber eigentlich auch ein kleinen nachteil... du musst meine ich alle Methoden du in einem Interface defnierst auch benutzten in deiner Klasse.

Ich würde das noch etwas anders machen, evlt. würde hier eine bases Klasse nicht schlecht sein.

Du erstellst dir eine Klasse die auf die Lib zugreifen kann, und eine weitere die dann die Methoden Kapselt und Fertig.

Ich sehe in der Verwendung von Interfaces keinen wirklichen Verwendung...
MFG
Michael Springwald

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Beitrag von Socke »

danke für die Antwort
pluto hat geschrieben: Sind zwar nicht schlecht.... stellen aber eigentlich auch ein kleinen nachteil... du musst meine ich alle Methoden du in einem Interface defnierst auch benutzten in deiner Klasse.
dass ich nur die Methoden im Interface deklariere, die ich benötige, sollte irgendwo klar sein; die Implementation der Methoden von IUnknown (Basis-Interface) sind in der Klasse TInterfacedObject implementiert, also auch kein Problem.
pluto hat geschrieben: Ich würde das noch etwas anders machen, evlt. würde hier eine bases Klasse nicht schlecht sein.
Stimmte. Ne Basis Klasse mit abstrakten Methoden (wie TStrings) wäre auch noch eine Möglichkeit.
pluto hat geschrieben: Du erstellst dir eine Klasse die auf die Lib zugreifen kann, und eine weitere die dann die Methoden Kapselt und Fertig.
Dann hätte ich immer noch etliche Funktionen, die von der Bibliothek exportiert werden müssen; genau das, was ich vermeiden möchte.
pluto hat geschrieben: Ich sehe in der Verwendung von Interfaces keinen wirklichen Verwendung...
Der Vorteil wäre, dass ich nur zwei Funktionen pro Klasse brauche: eine zum Erstellen und eine zum Freigeben (könnte man nicht die Prozedur Free zu einem Interface hinzufügen?). Alternativ müsste ich für jede Methode und jede Eigenschaft für jede Klasse eine (bei Eigenschaften zwei) Funktionen bereitstellen, die die eigentlichen Aufrufe in der Bibliothek kapseln. Unter Verwendung einer Kapsel-Klasse in der Anwendung, hätte ich noch ein paar mehr.

so, neuer Stoff zum Nachdenken
Socke

Edit:
Ich habe gerade versucht, beim Freigeben des Objektes, vorher einen TypeCast zu machen (Ist eigentlich sinnlos, da Destroy virtual ist). Jedoch kam dabei heraus, dass bereits beim überprüfen der Klasse ein Fehler auftritt (External: SIGSEGV -> SYSTEM_TOBJECT_$__INHERITSFROM$TCLASS$$BOOLEAN). Daraus schließe ich, dass meine Objektvariable nicht mehr auf ein Objekt zeigt (ich hab keine Ahnung auf was dann). Also: Wo finde ich die Implementation von Supports(...) bzw. hat jemand ne Ahnung, was los ist und/oder wie ich die Fehler umgehen kann?

Antworten