探讨:接口引用(接口RTTI) 如何从一个接口变量取得其接口类型(GUID)? ( 积分: 200 )

  • 主题发起人 主题发起人 dejoy
  • 开始时间 开始时间
D

dejoy

Unregistered / Unconfirmed
GUEST, unregistred user!
近期在写一个类pascal解释器,对borland的RTTI机制进行了一番学习,了解了borland的RTTI机制,但本人水平有限,在学习有关接口的RTTI过程中,遇到了些无法解释的问题,在这里提出来,大家共同探讨。
首先说明“接口引用”这个概念在delphi中也许不存在,是我相对于“类引用”提出来的。我们知道在delphi 中有类引用的概念,定义方式如TClass = class of TObject,其实质是指向类RTTI的一个指针,我们可以用这个类引用实现好多动态功能。可接口就比较特殊,虽然定义语法和类定义类似,但只是一个空壳,需要通过某个具体的类来实现。虽然接口是一个空壳,但是这个空壳也有RTTI信息,可以通过TypeInfo函数得到。
在VCL中其实也运用了好多 “接口引用”的概念,比如IInterface中的QueryInterface函数,查询接口支持的函数supports等,但在delphi并没有类似“ Interface of Interface”这样的句法来定义一个接口引用,而是使用一个TGUID来完成接口引用的功能。TGUID其实被定义为一个结构类型,delphi的编译器知道如何把TGUID类型转换成接口引用来使用,但对开发者来说却是不公布的。比如:
var
Obj : TObject;
m:TComponent;
ClassRef: TClass;
Intf: IInterface;
IID: TGUID;
begin
obj := TComponent.Create(nil);
ClassRef := obj.ClassType
//对于类变量,我们可以用类函数classType来取得它的类类型。
m := obj as TComponent;
Intf := m
//把M赋给接口变量,因为TComponent实现了IInterface接口。
{
IID := ? intf ;//无法取得接口变量的接口类型?!
}
end;

归结起来,写一个函数,取得一个接口变量的接口类型(GUID):
function GetIntfGUID(AIntf: IInterface):TGUID;
begin
Result := ;//如何实现?和各位继续探讨
end;
 
近期在写一个类pascal解释器,对borland的RTTI机制进行了一番学习,了解了borland的RTTI机制,但本人水平有限,在学习有关接口的RTTI过程中,遇到了些无法解释的问题,在这里提出来,大家共同探讨。
首先说明“接口引用”这个概念在delphi中也许不存在,是我相对于“类引用”提出来的。我们知道在delphi 中有类引用的概念,定义方式如TClass = class of TObject,其实质是指向类RTTI的一个指针,我们可以用这个类引用实现好多动态功能。可接口就比较特殊,虽然定义语法和类定义类似,但只是一个空壳,需要通过某个具体的类来实现。虽然接口是一个空壳,但是这个空壳也有RTTI信息,可以通过TypeInfo函数得到。
在VCL中其实也运用了好多 “接口引用”的概念,比如IInterface中的QueryInterface函数,查询接口支持的函数supports等,但在delphi并没有类似“ Interface of Interface”这样的句法来定义一个接口引用,而是使用一个TGUID来完成接口引用的功能。TGUID其实被定义为一个结构类型,delphi的编译器知道如何把TGUID类型转换成接口引用来使用,但对开发者来说却是不公布的。比如:
var
Obj : TObject;
m:TComponent;
ClassRef: TClass;
Intf: IInterface;
IID: TGUID;
begin
obj := TComponent.Create(nil);
ClassRef := obj.ClassType
//对于类变量,我们可以用类函数classType来取得它的类类型。
m := obj as TComponent;
Intf := m
//把M赋给接口变量,因为TComponent实现了IInterface接口。
{
IID := ? intf ;//无法取得接口变量的接口类型?!
}
end;

归结起来,写一个函数,取得一个接口变量的接口类型(GUID):
function GetIntfGUID(AIntf: IInterface):TGUID;
begin
Result := ;//如何实现?和各位继续探讨
end;
 
太高深了,学习
 
既然AIntf是个IInterface指针,那么其对应的IID(TGUID)是不确定的,也是不唯一的,因为实现AIntf实现类可能实现了多个接口,所以你这个“取得一个接口变量的接口类型”从原理上来说就是不成立的,因为这个返回值有可能有很多个;
你应该采用先有一个指定类型的接口变量,然后看是否能从AIntf获取这个指定类型的接口指针来判断AIntf是否“支持这个接口”,即用给定的IID调用AIntf的QueryInterface方法,通过判断是否返回一个接口指针来判断这个AIntf是否支持这个给定的IID类型的接口;
 
谢谢帅哥,不过我的意思不是要取得一个类或者类实例是否实现了某一个接口,而是要取得一个接口变量的类型(或名称,其实就是GUID)。像这样

var
intfInterface

IID:TGUID

begin
{
在这期间,intf被赋予了一个接口变量,这个接口是什么是不定的,不过肯定是从IInterface派生的。
}
IID := GetIntfGUID(intf);//在这儿要取得这个接口变量到底是个什么接口,是ICompoent,或是IDesigner还是其它的什么接口等等 ?
end

不管AIntf实现类可能了多少个接口,但是Aintf只能是一个接口,举个例
Aintf := obj as IInterface1;//Aintf 就是一个IInterface1类型的接口变量,我用GetIntfGUID(Aintf)想要返回的就是IInterface1这个接口的GUID
Aintf := obj as IInterface2;//Aintf 就是一个IInterface2类型的接口变量,我用GetIntfGUID(Aintf)想要返回的就是IInterface2这个接口的GUID
 
有办法,接口要使用M+/M-编译命令:
{M+}
IYourIntf=Interface
[guid]
....
end;
{M-}
看一下system的相关声明:
Unit

System

Delphi syntax:

type
PInterfaceEntry = ^TInterfaceEntry;

TInterfaceEntry = packed record
IID: TGUID;
VTable: Pointer;
IOffset: Integer;
ImplGetter: Integer;

end;

C++ syntax:

struct PACKAGE TInterfaceEntry

{
TGUID IID;
void* VTable;
int IOffset;
int ImplGetter;
};

typedef TInterfaceEntry *PInterfaceEntry;

Description

PInterfaceEntry is a pointer to a TInterfaceEntry value.

TInterfaceEntry contains the following fields:

IID: The GUID that uniquely identifies the interface.
VTable: The VTable to use for dispatching interface calls.
IOffset The offset of the interface in the implementing object.
ImplGetter A method pointer for accessing the interface if IOffset is not available.

有一个全局函数大概叫GetIntfMetaData,我找不到在哪个单元声明了
调用方法大概是:GetIntfMetaData(typeInfo(yourclass),InterfaceEntry);

InterfaceEntry属于PInterfaceEntry类型
通过InterfaceEntry.IID获得Guid

李维的Inside Vcl中有详细介绍
 
google了一下,找到了:
http://210.202.166.43/howto.net/Document/Interface.htm
GetIntfMetaData在intfinfo.pas中声明
基本步骤:
procedure GetIntfMetaData(Info: PTypeInfo
var IntfMD: TIntfMetaData
IncludeAllAncMethods: Boolean = False)
overload;
获得IntfMD: TIntfMetaData
TIntfMetaData中包含IID属性
 
张鸿林 帅哥,这个函数只是返回特定类型的接口的信息,而不能返回未定接口类型的信息,就像上面我所说的
 
后退
顶部