Как определить, есть ли у потомка IInterface свойство? - PullRequest
3 голосов
/ 10 июня 2011

У меня много интерфейсов в результате импорта библиотеки типов. Итак, интерфейсы такие:

  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 type - и сделайте приведенный выше код один раз. Я не знаю ни имени, ни GUID интерфейса во время компиляции.

Obs: тег delphi-xe потому что я хочу знать механизм, даже если он работает только на Delphi XE (даже если мне нужно купить версию для начинающих только для этого). Я использую D2010.

EDIT: Моя попытка использовать 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;

Ответы [ 2 ]

3 голосов
/ 10 июня 2011

Попробуйте использовать стандартный метод 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;
3 голосов
/ 10 июня 2011

Вы на правильном пути. RTTI Delphi может найти методы интерфейса, но интерфейс должен генерировать RTTI для этих методов. Это не делает это по умолчанию; Вы должны включить это. Поместите директиву {$M+} в верхней части модуля импорта библиотеки типов, и она должна работать.

...