如何确定 IInterface 后代是否具有属性?

发布于 2024-11-14 15:33:59 字数 2262 浏览 6 评论 0原文

由于导入类型库,我有很多接口。因此,接口如下所示:

  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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忘东忘西忘不掉你 2024-11-21 15:33:59

尝试标准的 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;

Try the standard IDispatch method (not tested, you may need to tweak it):

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;
寄人书 2024-11-21 15:33:59

你走在正确的轨道上。 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文