AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Interface referenzen auf gleichheit prüfen?
Thema durchsuchen
Ansicht
Themen-Optionen

Interface referenzen auf gleichheit prüfen?

Ein Thema von maximov · begonnen am 11. Okt 2004 · letzter Beitrag vom 14. Okt 2004
Antwort Antwort
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#1

Re: Interface referenzen auf gleichheit prüfen?

  Alt 12. Okt 2004, 13:23
Hi Choose,

so langsam nähern wir uns dem Punkt:

Delphi-Quellcode:
  mov eax, [MyInterfaceRef] ; eax => "magischer Zeiger" mit Objektreferenz+IOffset (s.o.)
  mov edx, [eax] ; edx => "magischer Bereich"
  call edx, [edx+$0c] ; Sprung nach [edx+Methodenselektor]
ist natürlich nicht ganz richtig erklärt

Delphi-Quellcode:
  mov eax, [MyInterfaceRef] ; lade eax mit Interface aus Variable MyInterfaceRef
  mov edx, [eax] ; lade edx mit VMT des Interfaces
  call edx, [edx+$0c] ; spinge indirect an die Addresse die in der Interface VMT an Index 3 steht, eg. rufe .AnOperationIntrocuedByMyInterface Dispatcher auf
Allerdings stehtin der VMT eben NICHT der direkte Aufruf von .AnOperationIntrocuedByMyInterface drinnen sondern eine Addresse zu einem durch den Compiler erzeugten Disptacher. Dieser Dispatcher "subtrahiert" von der aktuelle Intrface Referenez in EAX = Self.Interface den IOffset und springt danach zu .AnOperationIntrocuedByMyInterface.

Nun dieser Mechanismus ist natürlich in Delphi 5,5,7 gleich geblieben, und stellt auch tatsächlich einen direkten Zusammenhang zu den implementirenden Klassen dar. Das ist alles richtig. ABER, diese Funktionalität ist eben undokumentiert und absolut Delphi typisch. Normale Interfaces in anderen Sprachen arbeiten absolut nicht so.
Soll heisen: man kann und darf sich eigentlich darauf nicht verlassen.

Desweiteren kann man sehr wohl dieses Verhalten zur Laufzeit dynamisch verändern. Man kann nämlich den VMT-Zeiger auf die VMT des Interfaces im "Datenbereich" des Objectes dynamisch verbiegen. Dieser VMT-Zeiger auf das Interface liegt so wie der VMT Zeiger auf die Klasse innerhalb des Datenbereiches des Objectes. Zb. Pointer(Self^) zeigt auf die VMT der Klasse. Und Pointer(Self + IAnyInterface.IOffset)^ zeigt auf die VMT des Interfaces.

Eine VMT eines Interfaces ist sehr simpel. Sie besteht immer aus mindestens 3 Zeigern auf die proceduren ._QueryInterface(), ._AddRef, ._Release. Danach kommen die durch das Interface zusätzlich deklarierten Methoden. Also so

Delphi-Quellcode:
type
  PMyVMT = ^TMyVMT;
  TMyVMT = packed record
    _QueryInterface: Pointer;
    _AddRef: Pointer;
    _Release: Pointer;

    AnOperationIntrocuedByMyInterface: Pointer;
  end;
Eine allozierte Interface-Variable sieht dann minimal so aus:

Delphi-Quellcode:
   PMyIntf = ^TMyIntf;
   TMyIntf = packed record
     VMT: PMyVMT;

     Field1: Integer;
     Field2: Integer;
   end;
Exakt so sehen auch Objecte aus, und das ist ein Problem für die Entwickler bei Borland, denn nun müssen sie beide VMT's, die der Objecte und die der Interfaces in ein Object reinbekommen. Der Trick besteht nun darin das ein Object im Speicher aus einer "Kette" von solchen VMTs besteht. Als erste, ausgehende vom Pointer Self kommt das ursprüngliche Object mit seinem VMT zeiger zur Klasse und danach die einzelnen VMTs der verschiedenen impelemntierten Interfaces. Normalerweise sind diese nur die Zeiger auf die VMTs der Interfaces, also ohne zusätzliche Datenfelder.

Ein Object mit Interfaces sieht im Speicher also so aus:
Delphi-Quellcode:
  
type
  PMyObjectIntf = ^TMyObjectIntf;
  TMyObjectIntf = packed record
    VMT_Class: Pointer;
    Field1: type;
    Field2: type;
   
    VMT_Interface1: Pointer;
    VMT_Interface2: Pointer;
    VMT_Interface3: Pointer;
  end;
Nun erklärt sich auch .IOffset, denn eine Interface Variable die auf ein Klassen implementiertes Interface in Delphi zeigt, zeigt im Grund mitten in den Speicherbereich des Objectes selber, also exakt an Addresse Self + IInterface1.IOffset.

Aber exakt das wird bei Interfaces anderer Programmiersprachen nicht so sein, und es stellt noch keinen Bezug auf die Klasse eines Objectes dar und es stellt auch NICHT sicher das die Reichenfolge und die .IOffsets bei ausschließlicher Kenntnis der Interface-Varibale von aussen berechnet werden können. Soll heisen, nur das implementierende Object selber hatt Zugriff auf seine Klassen-RTTI und kann die .IOffsets errechnen. Über einen normaler Interface-Zeiger geht dies nicht da die .IOffsets abhängig von der Klasse unterschiedlich sein können eben auch wenn verschiedene Klassen das gleiche Intrface implementieren.
Zwei Klassen, A und B implementieren das Interface C. Die VMT von C liegt aber in der Klasse A an einem ganz anderen IOffset als in Klasse B. Somit hat man eben keine Möglichkeit, von Aussen nur mit Hilfe einer Interface Variablen auf Self -> Self.ClassType -> Self.RTTI zu berechnen. In jedem Falle benötigt man dazu ein spezielles Interface das dann wie in meinem obigen Source den Interface-Zeiger umrechnet in einen Objectzeiger. Diese "Umrechnung" wird eben im Gegensatz zu anderen Programmiersprachen, durch den Delphi Compiler über die hardcoded erzeugten Dispatcher Funktionen erledigt.

WENN, man aber nun ein zusätzliches Interface zwingend benötigt, so kann man auch gleich den sauberen Weg wie oben angedeutet beschreiten.

Auf alle Fälle gilt: Da es zwischen einer Interface-Referenz keinen zwingenden Zusammenhang zum implementierenden Object gibt, kann man auch nicht Interface-Referenzen direkt in Object-referenzen umrechnen.

Gruß Hagen
  Mit Zitat antworten Zitat
Antwort Antwort


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 00:00 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