Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi InterfaceTable eines Interfaces? (https://www.delphipraxis.net/87899-interfacetable-eines-interfaces.html)

Kedariodakon 7. Mär 2007 00:15


InterfaceTable eines Interfaces?
 
Nun hab ich mal so eine ganz kuriose Sache, jedes TObject hat ja die bekannte Funktion "GetInterfaceTable"...

Komme ich über ein Interface auch an diese Tabelle?

Sprich ich hab ein Variable Intf: IUnknown, welche auch belegt ist, dass Object dahinter ist mir völlig unbekannt...
Nun würde ich gern alle GUIDs der implementierten Interfaces haben...

Bis jetzt mach ich es pie mal daumen so (Achtung, das ist nur ein grobes Funktionsbeispiel... :duck: ):
Delphi-Quellcode:
Function GetGUIDs( Const Intf: IUnknown ): {irgendwas...}
Begin
  If Supports( Intf, IInt1 ) Then {lalala}.Add( GUIDToString( IInt1 ) );
  If Supports( Intf, IInt2 ) Then {lalala}.Add( GUIDToString( IInt2 ) );
  If Supports( Intf, IInt3 ) Then {lalala}.Add( GUIDToString( IInt3 ) );
  If Supports( Intf, IInt4 ) Then {lalala}.Add( GUIDToString( IInt4 ) );
  If Supports( Intf, IInt5 ) Then {lalala}.Add( GUIDToString( IInt5 ) );
  { Mach mir ein wildes Result... }
End;
Nunja, aber da kann man ja schnell mal ein Interface vergessen, daher wär so eine Tabelle schon eine sehr feine Sache...
Vorallem, da ja eventuell mal ein neueres Modul mit einem alten Programm läuft, welches ja ev. mal das Interface nicht kennt (macht die Liste dannn ja unvollständig)...

Hat jemand eine Idee? :gruebel:


Bye Christian

Kedariodakon 7. Mär 2007 00:35

Re: InterfaceTable eines Interfaces?
 
Ok ich hab mal einen kleinen Umweg versucht:

Delphi-Quellcode:
Type
  IIntfTbl = Interface
    ['{C93CB029-F127-493C-9A65-8C5E446BE830}']
    Function GetObjInterfaceTable: PInterfaceTable; StdCall;
  End;

{...}

  TBasisModulDingens = Class( TInterfacedObject, {viele weitere Interfaces...}, IIntfTbl )
  {...}
  Protected
    { Protected-Deklaration }
    Function GetObjInterfaceTable: PInterfaceTable; StdCall;
  {...}
  End;

{...}
Function TBasisModulDingens.GetObjInterfaceTable: PInterfaceTable;
Begin
  Result := GetInterfaceTable;
End;
{...}
Nunja aber da is das Result immer Nil... liegt wohl daran, dass das Interface über eine DLL eingeladen wird, da fehlen wohl die RTTI...
Richtig?

Nunja kann man das dennoch irgendwie realisieren?

Bye Christian

Kedariodakon 7. Mär 2007 13:28

Re: InterfaceTable eines Interfaces?
 
*push*

Kedariodakon 8. Mär 2007 12:47

Re: InterfaceTable eines Interfaces?
 
Suche immer noch nach einer einfacehn Lösung bzw. einen Lösungsansatz...

:duck:

Bye Christian

Kedariodakon 12. Mär 2007 10:33

Re: InterfaceTable eines Interfaces?
 
*push* In Hoffnug auf eine Lösung :zwinker:

negaH 13. Mär 2007 10:31

Re: InterfaceTable eines Interfaces?
 
probiere mal

Delphi-Quellcode:
type
  IIntfTbl = Interface
    ['{C93CB029-F127-493C-9A65-8C5E446BE830}']
    function SupportsInterface(Index: Integer; out GUID: TGUID): Bool; stdcall;
  end;

function TXyz.SupportsInterface(Index: Integer; out GUID: TGUID): Bool; stdcall;
var
  Table: PInterfaceTable;
  Class: TClass;
begin
  Result := False;
  Class := ClassType;
  while (Index >= 0) and (Class <> nil) do
  begin
    Table := Class.GetInterfaceTable;
    if Table <> nil then
      if Index < Table.EntryCount then
      begin
        Move(Table.Entries[Index], GUID, SizeOf(TGUID));
        Result := True;
        Exit;
      end else Dec(Index, Table.EntryCount);
    Class := Class.ParentClass;
  end;
end;

procedure Test;
var
  I: Integer;
  IntfTbl: IIntfTbl;
  GUID: TGUID;
begin
  I := 0;
  if IUnknown.QueryInterface(IIntfTbl, IntfTbl) = S_OK then
    while IntfTbl.SupportsInterface(I, GUID) do
    begin
      ..... tue was mit GUID
      Inc(I);
    end;
end;
Du baust dir quasi eine einfache Iteriermethode die dir alle unterstützten GUIDs aller Klassen der Vererbungshierarchie zurückgibt.
Ein Zugriff direkt auf die RTTI's über Modulgrenzen hinweg ist eine sehr sehr schlechte Idee, dh. den Zeiger auf die PInterfaceTable zurückzugeben ist kontraproduktiv.

Gruß Hagen

Kedariodakon 13. Mär 2007 14:55

Re: InterfaceTable eines Interfaces?
 
Das Prinzip funktioniert :thumb:
Hab schon gar nicht mehr an eine Lösung geglaubt...

Hmm, nur hat ich sowas in der Art auch versucht, nur war der Pointer zur Table immer NIL...

Ich hab mir das noch ein wenig zusammengestutzt, rausgekommen ist das:
(Falls nochmal jemand sowas brauch)
Delphi-Quellcode:
Type
  IInterfaceTable = Interface
    ['{19B847B4-37F6-40A7-A999-6AF680D6CFE2}']
    Function GetCount:                  Integer; StdCall;
    Function GetItem( Index: Integer ): TGUID;   StdCall;
    { *** }
    Property Count:                   Integer Read GetCount;
    Property Items[ Index: Integer ]: TGUID  Read GetItem; Default;
  End;

{ ... }

Type
  TaObj = Class( {...}, IInterfaceTable )
  Protected
    { Protected-Deklaration }
    Function ITGetCount:                    Integer;   StdCall;
    Function ITGetItem(    Index: Integer ): TGUID;     StdCall;
    Function ITGetRefItem( Index: Integer ): TGUID;     StdCall;  
    Function IInterfaceTable.GetCount = ITGetCount;
    Function IInterfaceTable.GetItem  = ITGetItem;
    { ... }
  Public                    
    { Public-Deklaration }
    Property IntfCount:                   Integer  Read ITGetCount;
    Property IntfItems[ Index: Integer ]: TGUID    Read ITGetItem;
    { ... }
  End;

{ ... }

Const
  cNullGUID:   TGUID    = ( D1: $00000000; D2: $0000; D3: $0000; D4: ( $00, $00, $00, $00, $00, $00, $00, $00 ); );

{ ... }

Function TaObj.ITGetRefItem(Index: Integer): TGUID;
Var Table: PInterfaceTable;
    aClass: TClass;
    Res:   Boolean;
Begin
  Res    := False;
  aClass := ClassType;
  While ( Index >= 0 ) And ( aClass <> Nil ) Do Begin
    Table := aClass.GetInterfaceTable;
    If Table <> Nil Then Begin
      If Index < Table.EntryCount Then Begin      
        //  Move( Table.Entries[ Index ], GUID, SizeOf( TGUID ) );
        Result := Table.Entries[ Index ].IID;
        Res    := True;
        Break;
      End Else Begin
        Dec( Index, Table.EntryCount );
      End;
    End Else Begin
      //  Keine Tabelle vorhanden...
    End;
    aClass := aClass.ClassParent;
  End;
  If Not Res Then Result := cNullGUID;
End;

Function TaObj.ITGetCount: Integer;
Var Table: PInterfaceTable;
    aClass: TClass;
Begin
  aClass := ClassType;
  If ( aClass <> Nil ) Then Begin
    Result := 0;
    While ( aClass <> Nil ) Do Begin
      Table := aClass.GetInterfaceTable;
      If ( Table <> Nil ) Then Inc( Result, Table.EntryCount );
      aClass := aClass.ClassParent;
    End;
  End Else Begin
    Result := -1; //  Kein "InterfaceTable" vorhanden...
  End;
End;

Function TaObj.ITGetItem( Index: Integer ): TGUID;
Var IntfCnt: Integer;
    nIdx:    Integer;
Begin
  IntfCnt := ITGetCount;
  If ( Index >= 0 ) And ( Index < IntfCnt ) Then Begin
    nIdx   := IntfCnt - Index - 1;
    Result := ITGetRefItem( nIdx );
  End Else Begin
    Result := cNullGUID;
  End;
End;
Bye Christian

Kedariodakon 13. Mär 2007 15:20

Re: InterfaceTable eines Interfaces?
 
Aber so neben bei, kommt man auch an den Interface-Namen ran?

Bye Christian

sirius 13. Mär 2007 16:18

Re: InterfaceTable eines Interfaces?
 
Ich beobachte wohlwollend, was du hier machst :mrgreen: (persönliches Interesse) Hab nur grad keine Zeit da mitzuprobieren.

Was ist denn mit PInterfaceentry := getInterfaceEntry ?

Kedariodakon 13. Mär 2007 16:54

Re: InterfaceTable eines Interfaces?
 
Zitat:

Zitat von sirius
Ich beobachte wohlwollend, was du hier machst :mrgreen: (persönliches Interesse) Hab nur grad keine Zeit da mitzuprobieren.

:freak:

Zitat:

Zitat von sirius
Was ist denn mit PInterfaceentry := getInterfaceEntry ?

Kann dir nicht folgen...
Eigendlich sind in der Tabelle "TInterfaceEntry"s, die brauch ich ja nicht =p

Die Interface Liste ist ja eigendlich abgearbeitet, ich kann ja alle GUIDs auflisten die nun irgendwie, irgendwo reinimplementiert werden...

Nur richtig schön wäre es nun noch den passenden Namen zu haben (der In Delphi verwendet wird z.b. IInterface), falls man da überhaupt rann kommt... :duck:

Bye Christian

negaH 13. Mär 2007 17:14

Re: InterfaceTable eines Interfaces?
 
Zitat:

Ich hab mir das noch ein wenig zusammengestutzt, rausgekommen ist das:
(Falls nochmal jemand sowas brauch)
Sorry, aber aus meiner Sicht sieht dein Source "schei.." formatiert aus ;) Was hast du denn gegen meinen Vorschlag einzuwenden ? Ich meine das er sauberer, kompakter und im Grunde mit wenig Funktionalität exakt ds macht was du brachst. Naja, ist aber Ansichtssache, so wie eben die Formatierungen im Source.

Gruß Hagen

negaH 13. Mär 2007 17:24

Re: InterfaceTable eines Interfaces?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Nur richtig schön wäre es nun noch den passenden Namen zu haben (der In Delphi verwendet wird z.b. IInterface), falls man da überhaupt rann kommt...
Auch das geht. Nehme die Unit im Attachment und benutze die Funktion

Delphi-Quellcode:
function FindTypeInfo(const AGUID: TGUID; AModule: LongWord = allModules): PTypeInfo; overload;
über die PTypeInfo^ und TypInfo.GetTypeData(PTypeInfo)^ kommst du an den Namen der Interfaces und auch an alle aufrufbaren Methoden samt Parametern.

Gruß hagen

PS: hoffe das du meine Unit nicht in deine Sourcecode Formatierung (wenn man es so bezeichnen möchte) umbaust ;););)

negaH 13. Mär 2007 21:08

Re: InterfaceTable eines Interfaces?
 
Nochwas ist mir aufgefallen

Delphi-Quellcode:
  Function ITGetItem(    Index: Integer ): TGUID;     StdCall;
    Function ITGetRefItem( Index: Integer ): TGUID;     StdCall;
du gibts in diesen Methoden einen "komplexen" Datentyp zurück. Das ist bei Interfaces eher unerwünscht. Normalerweise sollte man Interface so konstruieren das sie HResult zurückgeben oder Bool um anzuzeigen das die Funktion fehlgeschlagen oder nicht fehlgeschlagen ist. Komplexere Datentypen gibt man bei Interfaces als Parameter -> out -> zurück. Dies ist nun kein "muß" und Ausnahmen bestätigen die Regel aber es ist eine sinnvolle Designrichtlinie. Ja ich weis das dann indizierte Properties nicht möglich sind, was ich bei Interfaces ohne Sichtbarkeitskapselungen per private/protected etc.pp. eh als sinnlose Erfindung der Bolandianer erachte. Sogesehen empfinde ich deine Konstruktion per indizierter Property -> ITGetItem() etc.pp. als dem Interface-Konzept widersprechend. Interfaces sollen eigentlich ausschließlich nur das deklarieren was public sichtbar sein soll. Deine .GetItem() Methode ist aber eine implementierende Schnittstelle und müsste normalerweise unsichtbar im Interface sein. Da dies Borland aber nicht bei Interfaces unterstützt halte ich es für besser komplett auf dieses Property-Sprachkonstrukt bei Interfaces zu verzichten. Das macht die Schnittstelle letzendlich kompakter, übersichtlicher und somit besser wartbar. Anders ausgedrückt: weniger ist manchesmal mehr, man muß nicht jedes mögliche Sprachkonstrukt benutzen ;)

Gruß Hagen

Kedariodakon 14. Mär 2007 08:35

Re: InterfaceTable eines Interfaces?
 
Erstmal danke für deine ausführlichen Antworten! Muss erstmal alles überblicken...

Zitat:

Zitat von negaH
Ja ich weis das dann indizierte Properties nicht möglich sind, was ich bei Interfaces ohne Sichtbarkeitskapselungen per private/protected etc.pp. eh als sinnlose Erfindung der Bolandianer erachte.

Nunja da ich hier in meinem aktuellen Projekt eigendlich nur mit den Interfaces arbeite, bzw. es versuche diese konsequent zu benutzen sind Property deklerationen in Interfaces eine schöne Möglichkeit ein Interface schön kompakt und übersichtlich zu benutzen. :drunken:

Zitat:

Zitat von negaH
du gibts in diesen Methoden einen "komplexen" Datentyp zurück. Das ist bei Interfaces eher unerwünscht.

Nungut, mit den komplexen Datentypen hast du schon irgendwie recht, sofern das noch wer anders nutzen will/muss/soll... Nunja ich fand es an der Stelle für mich persönlich so praktischer (schon wegen den Propertys :roteyes: )...

Zitat:

Zitat von negaH
Sorry, aber aus meiner Sicht sieht dein Source "schei.." formatiert aus ;)

Nun ok, meine Codeformatierung steht nicht jedem zu, aber so schreklich ist sie ja nun nicht oder? Ich finde sie zumindest absolut übersichtlich... (da gibt es wahrlich schlimmeres...)
:duck:

Zitat:

Zitat von negaH
Was hast du denn gegen meinen Vorschlag einzuwenden ? Ich meine das er sauberer, kompakter und im Grunde mit wenig Funktionalität exakt ds macht was du brachst.

Schlussendlich hab ich mir deinen Code für mich passend gemacht, um ihn so zu verwenden wie ich ihn benötige...
Und bis auf die 2 Wortdreher im Code ist er auch absolut genau der Lösungsansatz den ich gesucht hatte, von daher nochmal danke :spin:

Im Grunde war mein Teil nur ein kleiner Ergebnissbericht, falls nochmal jemand damit arbeiten mag und keine Lösung findet... Ich hab ewig gesucht und nix gefunden =(

Nungut, ich werd mir das mit dem Interface Namen nachher noch näher anschauen.

Bye Christian :hi:


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