Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi TRTTIMethod.Invoke eines Interface ausführen (https://www.delphipraxis.net/211823-trttimethod-invoke-eines-interface-ausfuehren.html)

Friday 7. Nov 2022 20:26

TRTTIMethod.Invoke eines Interface ausführen
 
Hallo,
bei Versuch einen Serializer zu schreiben, bleibe ich gerade bei den Interfaces stecken.
Der Serializer ist eine rekursive Funktion die ein TValue entgegen nimmt.
Übernommen aus diesem Thread: https://stackoverflow.com/questions/...14088#11514088
Allerding ist der Interface Teil in dem sonst gut funktionierenden Beispiel leer.
Das habe ich folgend ergänzt. Es wird über alle Methoden die das Interface definiert iteriert und wenn eine Methode einen Rückgabewert <> nil (also Funktion) hat und keine Parameter erwartet, wird versucht die rekursive Funktion erneut aufzurufen mit dem Rückgabewert der aufzurufenden Funktion:
Code:
    tkInterface: // Identifies an interface type.
      begin
        sList.Add(FSumIndent + 'interface ' + name + ':' + thing.TypeInfo.name);
        IncIndent();
        for LMethod in LContext.GetType(thing.TypeInfo).GetMethods do
        begin
          if (LMethod.ReturnType <> nil) and (length(LMethod.GetParameters) = 0) then
            Serialize(LMethod.name, LMethod.Invoke(thing, []), sList); //<-- AV
        end;
        DecIndent();
        sList.Add(FSumIndent + 'end');
      end;
Dass ich hier bei "LMethod.Invoke(thing,.." eine AV bekomme ist nicht weiter verwunderlich, denn ich übergebe statt einer Instanz nur ein Interface.
Aber die Frage ist wie komme ich an das Objekt ran, dass hinter dem Interface steckt?

himitsu 7. Nov 2022 22:06

AW: TRTTIMethod.Invoke eines Interface ausführen
 
Wo genau tritt der Fehler auf?
* wirklich beim Ausführen der Interface-Methode
* oder erst im Serialize

Bei welcher Methode knallt es?
Zitat:

Delphi-Quellcode:
  IInterface = interface
    ...
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

Diese Beiden solltest du besser nicht ausführen, vor allem nicht das _Release,
weil sonst geschieht es dir zu Recht, wenn es knallt. :angle:

Und auch sonst keine gute Idee, einfach so blind irgendwas aufzurufen, wenn man nicht weiß was es macht.
* da könnte auch drin ein
Delphi-Quellcode:
format c:
oder
Delphi-Quellcode:
delete the internet
gemacht werden
* oder es wird ein Objekt/Interface zurückgegeben, welches du nicht wieder freigibst (Speicherleck) oder vielleicht doch (peng, wenn es garnicht freigegeben werden darf)
* oder etwas ala Lock/Unlock, z.B. für eine CriticalSection (Deadlock oder schlimmer)
* oder


Zitat:

Zitat von Friday (Beitrag 1514449)
Aber die Frage ist wie komme ich an das Objekt ran, dass hinter dem Interface steckt?

Eigentlich garnicht, denn das Interface ist ja gerade dafür da, um Implementation (Objekt) und Interface (Schnittstelle) zu trennen. :roll:

Delphi-Quellcode:
thing as TObject
funktioniert seit ein paar wenigen Jahren, aber ausschließlich für Interfaces, wo auch ein Delphi-Objekt drin steckt.

jaenicke 7. Nov 2022 22:21

AW: TRTTIMethod.Invoke eines Interface ausführen
 
Du solltest dieses Interface mit as oder per hartem Cast z.B. auf TObject casten können. Bei mir funktioniert der Code so allerdings. Wie sehen denn dein Interface, die Klasse dazu und der Aufruf des Serializers aus?

Mein Test:
Delphi-Quellcode:
  {$M+}
  IBlub = interface
  ['{E9AB3CA6-9F88-4D30-9D9D-57D7A0821810}']
    function GetTest: string;
  end;

  TBlub = class(TInterfacedObject, IBlub)
  published
    function GetTest: string;
  end;

Friday 8. Nov 2022 20:38

AW: TRTTIMethod.Invoke eines Interface ausführen
 
Zitat:

Zitat von himitsu (Beitrag 1514452)
Und auch sonst keine gute Idee, einfach so blind irgendwas aufzurufen, wenn man nicht weiß was es macht.

so blind ist das nicht, da ich nur Funktionen von Objekten aus dem eigenen Programm ausführen will und diese in einem weiteren Schritt auch noch durch Attribute "gefiltert" werden. Also es werden dann wirklich nur die Funktionen aufgerufen die ich explizit dafür vorsehe.

Das erstaunlich ist, das es jetzt funktioniert..und zwar ohne Änderungen :o Neuer Tag neues Glück kann man da wohl sagen.
Es wird daran gelegen haben, dass in den gestrigen Versuchsobjekten ein Interface auf ein nicht mehr existierendes Object referenziert hat (was ich fälschlich ausgeschlossen hatte). :roll:

Danke euch für die Unterstützung

himitsu 8. Nov 2022 21:24

AW: TRTTIMethod.Invoke eines Interface ausführen
 
OK, wenn es NUR "Eigenes" ist,
aber ALLE Interfaces implementieren 3 Funktionen für die Speicherverwaltung,
und Zwei davon treffen auf deine Bedingungen zu. (hat Result und keine Parameter)

Delphi-Quellcode:
  IInterface = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;
Zitat:

Interface auf ein nicht mehr existierendes Object referenziert
Wenn man nicht an der Speicherverwaltung rumpfuscht, kann sowas eigentlich nicht passieren,
denn Interfaces räumen sich selbst auf, wenn keine Variable mehr auf sie zeigt.

OK "eigentlich" ... auch viele TComponent implementieren Interfaces, aber dort mit deaktivierter Referenzzählung (_AddRef und _Release machen nichts),
also dort hat nicht das Interface die Controlle, sondern die VCL und solche Interface-Zeiger können wirklich ins Nirvana zeigen.
(drum sollte man an dieser Stelle das Interface nur kurz nutzen)

PS: Unter Anderem dafür gibt es das [unsafe].
https://blog.marcocantu.com/blog/201...eferences.html
https://dalijap.blogspot.com/2022/11...s-part-ii.html



Abgesehn von so Dingen wie bei TComponent,
sollte man es möglichst vermeiden gleichzeitig Interface- und Objekt-Referenzen zu haben.
So gibt es auch keine potentiellen Streitigkeiten, wer das Objekt aufräumt.

Friday 10. Nov 2022 20:22

AW: TRTTIMethod.Invoke eines Interface ausführen
 
Zitat:

Zitat von himitsu (Beitrag 1514504)
OK, wenn es NUR "Eigenes" ist,
aber ALLE Interfaces implementieren 3 Funktionen für die Speicherverwaltung,
und Zwei davon treffen auf deine Bedingungen zu. (hat Result und keine Parameter)

Delphi-Quellcode:
  IInterface = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;
...

diese Funktionen werden mir an dieser Stelle aber nicht zurück gegeben.
Der Serializer, bzw. TRTTIType.GetMethods liest nur die Methoden die explizit in einem folgend deklarierten Interface definiert sind:
Delphi-Quellcode:
IMyInterface = interface(IInterface)
function MyFunc1: interger;
function MyFunc2: interger;


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