Hello Wilfried,

Before you typecast a variant to an interface, you must typecast it to
Iunknown or Idispatch:

      Loc := IDispatch(Vertex) as Location; 

FYI, Below is a unit that allows you to create a 'for each' statement in
Delphi. You'd use it as follows:

with ForEach(shape.Vertices) do
  while Next(Location, Loc) do
  begin
    //Process Loc
  end;

Here the unit:

unit uForEach;
{$WEAKPACKAGEUNIT ON}
interface

uses
  ActiveX, ComObj, Variants;

type
  { The IEnumVariant definition in the ActiveX unit erroneously declares the
  Next method as

    function Next(celt: LongWord; var rgvar : OleVariant;
      out pceltFetched: LongWord): HResult; stdcall;

  According to Microsoft documentation, it should be:

     function Next(celt: LongWord; pvar : POleVariant;
       pceltFetched: PLongWord): HResult; stdcall;

  See Borland case in http://qc.borland.com/wc/qcmain.aspx?d=4512 }
  IEnumVariant = interface(IUnknown)
    ['{00020404-0000-0000-C000-000000000046}']
    function Next(celt: LongWord; pvar : PVariantArgList;
      pceltFetched: PLongWord): HResult; stdcall;
    function Skip(celt: LongWord): HResult; stdcall;
    function Reset: HResult; stdcall;
    function Clone(out Enum: IEnumVariant): HResult; stdcall;
  end;

  {!~IForEach implemented a 'For Each' feature, similar to Visual Basic, in
  Delphi. Obtain the interface by calling the ForEach function.

  Typical use (Excel workbooks):

  with ForEach(Workbooks) do
    while Next(_Workbook, WB) do
      ... }
  IForEach = interface(IUnknown)
    ['{33531233-B908-459E-8F05-09B7758052DA}']

    function Next(const IID: TGUID; out Obj): Boolean;
    function NextVar(out Obj: OleVariant): Boolean;
  end;

function ForEach(const ACollection: IDispatch): IForEach;

implementation

type
  TForEach = class(TInterfacedObject, IForEach)
  private
    FEnum: IEnumVariant;
  protected

    //IForEach
    function Next(const IID: TGUID; out Obj): Boolean;
    function NextVar(out Obj: OleVariant): Boolean;
  public
    constructor Create(const ACollection: IDispatch); reintroduce;
  end;

function ForEach(const ACollection: IDispatch): IForEach;
begin
  Result := TForEach.Create(ACollection);
end;

{ TForEach }

constructor TForEach.Create(const ACollection: IDispatch);
var
  EnumUnk: OleVariant;
  DispParamNoArgs: TDispParams;
  ArgErr: Cardinal;
begin
  inherited Create;

  { We must obtain an interface to the enumerator, which is returned by the
    NewEnum method, which must be called by DispID }
  FillChar(DispParamNoArgs, SizeOf(DispParamNoArgs), 0);
  OleCheck(ACollection.Invoke(DISPID_NEWENUM, GUID_NULL, 0,
    DISPATCH_METHOD or DISPATCH_PROPERTYGET, DispParamNoArgs, @EnumUnk, nil,
      @ArgErr));
  FEnum := IUnknown(EnumUnk) as IEnumVariant;
end;

function TForEach.Next(const IID: TGUID; out Obj): Boolean;
var
  Fetched: Cardinal;
  Element: OleVariant;
  Sts: HRESULT;
begin
  Sts := FEnum.Next(1, PVariantArgList(@Element), @Fetched);
  Result := (Sts = S_OK);
  OleCheck(Sts);
  if Result then
    OleCheck(IUnknown(Element).QueryInterface(IID, Obj));
end;

function TForEach.NextVar(out Obj: OleVariant): Boolean;
var
  Disp: IDispatch;
begin
  Result := Next(IDispatch, Disp);
  if Result then
    Obj := Disp
  else
    Obj := Unassigned;
end;

end.


__________________________________________________
Delphi-Talk mailing list -> Delphi-Talk@elists.org
http://www.elists.org/mailman/listinfo/delphi-talk

Reply via email to