IEnumVariant is the common way to enumerate collections in COM interfaces. However this interface is very inconvenient to use in Delphi. So I decided to write simple generic wrapper, to make possible to enumerate such collections in Delphi style, like this:
To do this we need two objects, first one returns our Enumerator:
As you see, I made the GetEnumerator function returning interface, so that we don't need to free wrappers manually.
The second is our enumerator interface and its implementation:
var I: ICollectionItem; begin for I in EnumVariant do I.DoSomething(); end;
To do this we need two objects, first one returns our Enumerator:
TOleEnumerable<T: IInterface> = record private FEnum: IUnknown; public constructor Create(ANewEnum: IUnknown); function GetEnumerator: IOleEnumerator<T>; end; constructor TOleEnumerable<T>.Create(ANewEnum: IInterface); begin FEnum := ANewEnum; end; function TOleEnumerable<T>.GetEnumerator: IOleEnumerator<T>; begin Result := TOleEnumerator<T>.Create(FEnum); end;
As you see, I made the GetEnumerator function returning interface, so that we don't need to free wrappers manually.
The second is our enumerator interface and its implementation:
IOleEnumerator<T: IInterface> = interface function MoveNext: Boolean; function GetCurrent: T; procedure Reset; property Current: T read GetCurrent; end; TOleEnumerator<T: IInterface> = class(TInterfacedObject, IOleEnumerator<T>) private FEnum: IEnumVARIANT; FCurrent: T; public constructor Create(ANewEnum: IUnknown); function GetCurrent: T; function MoveNext: Boolean; procedure Reset; property Current: T read GetCurrent; end; constructor TOleEnumerator<T>.Create(ANewEnum: IInterface); begin FCurrent := nil; if not Supports(ANewEnum, IEnumVariant, FEnum) then raise Exception.Create('Enumeration type not supported'); end; function TOleEnumerator<T>.GetCurrent: T; begin Result := FCurrent; end; function TOleEnumerator<T>.MoveNext: Boolean; var OleVar: OleVariant; Num: Cardinal; begin Result := FEnum.Next(1, OleVar, Num) = S_OK; if Result then IUnknown(OleVar).QueryInterface(GetTypeData(TypeInfo(T)).Guid, FCurrent); end; procedure TOleEnumerator<T>.Reset; begin FEnum.Reset; end;Thats it! Now you could iterate your COM collections like this:
var Man: INetworkManager; I: INetworkConnection; begin Man := CoNetworkManager.Create; for I in TOleEnumerable<INetworkConnection>.Create(Man._NewEnum) do I.DoSomething(); end;
No comments:
Post a Comment