如何确定IInterface后代是否有财产?

时间:2011-06-09 21:27:25

标签: delphi generics interface delphi-2010 delphi-xe

导入类型库后,我有很多接口。所以,接口是这样的:

  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,但它确实是{ {1}}界面。因为它是枚举集合项目的唯一方法,所以我得到了:

IEnumVARIANT

使用:

{This class have just this class function} 
class function TVariantUtils.GetAs<T>(pModeloOleVar: OleVariant): T;
begin
  Result := (T(IUnknown(pModeloOleVar)));
end;

构造函数接收IEnumVariant参数。我想要的是创建一个构造函数 接收IInterface并确定ISomeCollection的_NewEnum属性是否为 IUnknown类型 - 并执行上面的代码一次。 我不知道编译时接口的名称或GUID。

Obs:delphi-xe标签是因为我想知道机制,即使只适用于Delphi XE (即使我需要为此购买简化版)。 我用D2010。

修改 我尝试使用RTTI(它编译但不起作用):

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;

2 个答案:

答案 0 :(得分:3)

你走在正确的轨道上。 Delphi的RTTI可以找到接口的方法,但接口必须为这些方法生成RTTI。它默认不这样做;你必须启用它。将{$M+}指令放在类型库导入单元的顶部,它应该可以工作。

答案 1 :(得分:3)

尝试使用标准的IDispatch方法(未经过测试,您可能需要对其进行调整):

function GetEnumerator(const Disp: IDispatch): IEnumVariant;
var
  DispParams: TDispParams;
  ExcepInfo: TExcepInfo;
  Status: Integer;
  VarResult: OleVariant;
begin
  Result := nil;
  FillChar(DispParams, SizeOf(DispParams), 0);
  FillChar(ExcepInfo, SizeOf(ExcepInfo), 0);
  Status := Disp.Invoke(DISPID_NEWENUM, GUID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, DispParams, @VarResult, @ExcepInfo, nil);
  if Succeeded(Status) then
    Result := IUnknown(VarResult) as IEnumVariant
  else
    DispatchInvokeError(Status, ExcepInfo);
end;