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;