Dmitry Streblechenko writes:
Quote
If _NewEnum is not explicitly exposed, it might still be available by
callign IDispatch::Invoke() with dispId = -4. AFAIK that is what VB
does, and "for each" for the Selection collection works fine in all
versions of Outlook.
Great! This works even on the Selection (though it does not appear to
be noticeably faster than the regular for to loop).
I have also found that now that the iteration itself has become pretty
fast (<200ms for ~3000 items) the real bottleneck is accessing the
Selection property in the first place: For the ~3000 items mentioned
before this alone takes about 1600ms... and it doesn't seem to get
faster by using late binding. Yet, when I call the essentially
identical VBA macro (see previous posts) that penalty does not seem to
apply... i.e. I get the result in less than a second.
Anyway, I have now wrapped yours and Chris' suggestions about the Foreach
iteration into an enumerator so you can use for-in loops on such
collections in Delphi (see below). Feel free to comment and/or share.
Usage would be something like:
for lItem in EnumOleCollection(OutlookApp.ActiveExplorer.Selection) do
...
Here's the code:
type
TOleCollectionEnum = class
private
FElem: OleVariant;
FEnum: IEnumVariant;
public
constructor Create(const AEnum: IEnumVARIANT);
function MoveNext: Boolean;
property Current: OleVariant read FElem;
end;
IOleCollectionEnumFactory = interface
function GetEnumerator: TOleCollectionEnum;
end;
TOleCollectionEnumFactory = class(TInterfacedObject,
IOleCollectionEnumFactory)
private
FEnum: IEnumVariant;
public
constructor Create(const ACollection: IDispatch);
function GetEnumerator: TOleCollectionEnum;
end;
function EnumOleCollection(const ACollection: IDispatch):
IOleCollectionEnumFactory;
begin
Result := TOleCollectionEnumFactory.Create(ACollection);
end;
{ TOleCollectionEnumFactory }
{ inspired by a newsgroup posting by Dmitry Streblechenko:
nntp://newsgroups.codegear.com/borland.public.delphi.oleautomation/65167
}
constructor TOleCollectionEnumFactory.Create(const ACollection:
IDispatch);
begin
inherited Create;
if not Supports(GetDispatchPropValue(ACollection, -4), IEnumVariant,
FEnum) then
raise EIntfCastError.Create('Interface does not support OLE
enumeration.');
end;
function TOleCollectionEnumFactory.GetEnumerator: TOleCollectionEnum;
begin
Result := TOleCollectionEnum.Create(FEnum);
end;
{ TOleCollectionEnum }
constructor TOleCollectionEnum.Create(const AEnum: IEnumVARIANT);
begin
inherited Create;
FEnum := AEnum;
end;
{ inspired by a newsgroup posting by Chris Cheney:
nntp://newsgroups.codegear.com/borland.public.delphi.oleautomation/65159
}
function TOleCollectionEnum.MoveNext: Boolean;
var
lFetched: Cardinal;
lResult: Cardinal;
begin
Result := False;
if FEnum <>nil then
begin
lFetched := 0;
lResult := FEnum.Next(1, OleVariant(FElem), lFetched);
case lResult of
S_OK: Result := (lFetched>0);
S_FALSE: ;
else
OleCheck(lResult);
end;
end;
end;
--