У меня много интерфейсов в результате импорта библиотеки типов. Итак, интерфейсы такие:
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
(это точно так же, как for-in
в Delphi) коллекции 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 интерфейса во время компиляции.
Замечания: тег delphi-xe связан с тем, что я хочу знать механизм, даже если он работает только на Delphi XE (даже если мне нужно купить Starter Edition только для этого). Я использую 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;
IDispatch
для получения значения свойства с dispid -4. - person Ondrej Kelle   schedule 10.06.2011_NewEnum
и получаетеIUnknown
. Вы неявно конвертируете его вOleVariant
, когда передаете его вGetAs
, и в этой функции вы выполняете приведение типа обратно кIUnknown
перед приведением (небезопасно) к типу интерфейса, который вам действительно нужен. Delphi поддерживает прямой способ сделать это, начиная с версии 3. Используйте операторas
:EnumCollection := Object.SomeCollection._NewEnum as IEnumVariant
. - person Rob Kennedy   schedule 10.06.2011IDispatch.Invoke
. О каком ИДН вы говорите? - person Ondrej Kelle   schedule 10.06.2011