如何确定 IInterface 后代是否具有属性?
由于导入类型库,我有很多接口。因此,接口如下所示:
ISomeCollection = dispinterface
['{6592E851-3D65-4D04-B5F3-B137667B816A}']
procedure Remove(Identifier: OleVariant); dispid 2;
function Add(Name: OleVariant; DatabaseType_ID: OleVariant): ERSModel; dispid 3;
property _NewEnum: IUnknown readonly dispid -4;
property Item[Identifier: OleVariant]: ERSModel readonly dispid 4;
property _Item[Identifier: OleVariant]: ERSModel readonly dispid 0; default;
property Count: Integer readonly dispid 1;
end;
_NewEnum
是 Visual Basic for-each
循环语句消耗的习惯用法(它与 Delphi 的 for-in
完全相同) ) 的 COM 对象集合 - 尽管声明为 IUnknown,但它实际上是一个 IEnumVARIANT
接口。由于这是枚举集合项的唯一方法,因此我通过以下方法解决了这个问题:
{This class have just this class function}
class function TVariantUtils.GetAs<T>(pModeloOleVar: OleVariant): T;
begin
Result := (T(IUnknown(pModeloOleVar)));
end;
使用:
var
EnumColecction: IEnumVariant;
// TEnumeratorObjects: This is a generic class to implement an enumerator over
// an IEnumVARIANT interface
ListOfSubObjects: TEnumaretorObjects;
begin
...
EnumCollection := TVariantUtils.GetAs<IEnumVariant>(Object.SomeCollection._NewEnum);
ListOfSubObects := TEnumeratorObjects<ItemofSomeCollection>.Create(EnumCollection);
...
End;
构造函数接收 IEnumVariant 参数。我想要的是创建一个构造函数 接收 IInterface 并确定 ISomeCollection 是否具有 _NewEnum 属性 IUnknown 类型 - 并执行一次上述代码。 我不知道编译时接口的名称或 GUID。
Obs:delphi-xe标签是因为我想知道其机制,即使仅适用于Delphi XE (即使我需要为此购买入门版)。 我用的是D2010。
编辑: 我尝试使用 RTTI(它可以编译但不起作用):
constructor TEnumeratorVariant<T>.Create(pEnumeraVariante: IInterface);
var
EnumVar: IEnumVariant;
Contexto: TRttiContext;
InfoTipo: TRttiType ;
PropInfo: TRttiProperty;
pTipo: PTypeInfo;
begin
Contexto.Create;
pTipo := TypeInfo(pEnumeraVariante);
InfoTipo := Contexto.GetType(TypInfo(pEnumeraVariante));
PropInfo := InfoTipo.GetProperty('_NewEnum');
if Assigned(PropInfo) then
begin
Supports(PropInfo.GetValue(pEnumeraVariante), IEnumVariant, EnumVar);
Create(EnumVar);
end;
Contexto.Free;
PropInfo.Free;
InfoTipo.Free;
end;
I have a lot of interfaces as a result of importing an type library. So, the interfaces are like this:
ISomeCollection = dispinterface
['{6592E851-3D65-4D04-B5F3-B137667B816A}']
procedure Remove(Identifier: OleVariant); dispid 2;
function Add(Name: OleVariant; DatabaseType_ID: OleVariant): ERSModel; dispid 3;
property _NewEnum: IUnknown readonly dispid -4;
property Item[Identifier: OleVariant]: ERSModel readonly dispid 4;
property _Item[Identifier: OleVariant]: ERSModel readonly dispid 0; default;
property Count: Integer readonly dispid 1;
end;
_NewEnum
is a idiom for Visual Basic for-each
loop statement consumption ( it's exactly like Delphi's for-in
) of COM collection of objects - despite the declaration of being IUnknown, it's really an IEnumVARIANT
interface. Since it's the only way to enumerate the collection' items, I got around it with:
{This class have just this class function}
class function TVariantUtils.GetAs<T>(pModeloOleVar: OleVariant): T;
begin
Result := (T(IUnknown(pModeloOleVar)));
end;
Use:
var
EnumColecction: IEnumVariant;
// TEnumeratorObjects: This is a generic class to implement an enumerator over
// an IEnumVARIANT interface
ListOfSubObjects: TEnumaretorObjects;
begin
...
EnumCollection := TVariantUtils.GetAs<IEnumVariant>(Object.SomeCollection._NewEnum);
ListOfSubObects := TEnumeratorObjects<ItemofSomeCollection>.Create(EnumCollection);
...
End;
The constructor receives an IEnumVariant parameter. What I want is create an constructor
that receive IInterface and determine if the ISomeCollection have an _NewEnum property of
IUnknown type - and do the above code once.
I don't know the name or the GUID of the interface on compile-time.
Obs: the delphi-xe tag is because I want to know the mechanism even if works only on Delphi XE
(even if I need to buy an Starter Edition just for this).
I use D2010.
EDIT:
My attempt using RTTI (it compiles but doesn't work):
constructor TEnumeratorVariant<T>.Create(pEnumeraVariante: IInterface);
var
EnumVar: IEnumVariant;
Contexto: TRttiContext;
InfoTipo: TRttiType ;
PropInfo: TRttiProperty;
pTipo: PTypeInfo;
begin
Contexto.Create;
pTipo := TypeInfo(pEnumeraVariante);
InfoTipo := Contexto.GetType(TypInfo(pEnumeraVariante));
PropInfo := InfoTipo.GetProperty('_NewEnum');
if Assigned(PropInfo) then
begin
Supports(PropInfo.GetValue(pEnumeraVariante), IEnumVariant, EnumVar);
Create(EnumVar);
end;
Contexto.Free;
PropInfo.Free;
InfoTipo.Free;
end;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试标准的 IDispatch 方法(未经测试,您可能需要调整它):
Try the standard
IDispatch
method (not tested, you may need to tweak it):你走在正确的轨道上。 Delphi的RTTI可以找到接口的方法,但是接口必须为这些方法生成RTTI。默认情况下它不会这样做;你必须启用它。将
{$M+}
指令放在类型库导入单元的顶部,它应该可以工作。You're on the right track. Delphi's RTTI can find methods of an interface, but the interface has to generate RTTI for those methods. It doesn't do that by default; you have to enable it. Put a
{$M+}
directive at the top of your type library import unit and it should work.