| ||||||||||||||||
| ||||||||||||||||
| ||||||||||||||||
Удобным средством, предоставляемым VBScript, является оператор For Each, организующий цикл по всем элементам заданной коллекции. Добавим поддержку этого оператора в наш компонент. Реализация For Each предусматривает следующее:
Интерфейс IEnumVariant определен как: IEnumVariant = (IUnknown) ['{00020404-0000-0000-C000-000000000046}'] Next(celt: LongWord; rgvar: OleVariant; pceltFetched: PLongWord): HResult; ; Skip(celt: LongWord): HResult; ; Reset: HResult; ; Clone(out Enum: IEnumVariant): HResult; ; ; В модуле ActiveX.pas в оригинальной поставке Delphi5 ошибочно определен метод Next Next(celt: LongWord; rgvar: OleVariant; pceltFetched: LongWord): HResult; ; поэтому для корректной реализации интерфейс должен быть переопределен. Создадим класс, инкапсулирующий функциональность IEnumVariant. TVCLEnumerator = (TInterfacedObject, IEnumVariant) FEnumPosition: Integer; FOwner: TPersistent; FScriptControl: TVCLScriptControl; { IEnumVariant } Next(celt: LongWord; rgvar: OleVariant; pceltFetched: PLongWord): HResult; ; Skip(celt: LongWord): HResult; ; Reset: HResult; ; Clone(Enum: IEnumVariant): HResult; ; Create(AOwner: TPersistent; AScriptControl: TVCLScriptControl); ; Конструктор устанавливает свойства FOwner и FScriptControl. TVCLEnumerator.Create(AOwner: TPersistent; AScriptControl: TVCLScriptControl); Create; FOwner := AOwner; FScriptControl := AScriptControl; FEnumPosition := 0; ; Метод Reset подготавливает реализацию интерфейса к началу перебора. TVCLEnumerator.Reset: HResult; FEnumPosition := 0; Result := S_OK; ; Главная функциональность сосредоточена в методе Next, который получает следующие переменные:
Метод должен заполнить запрошенное количество элементов rgvar и вернуть S_OK, если это удалось, и S_FALSE, если элементов не хватило. TVariantList = [0..0] OleVariant; TVCLEnumerator.Next(celt: LongWord; rgvar: OleVariant; pceltFetched: PLongWord): HResult; I: Cardinal; Result := S_OK; I := 0; Для объекта TWinControl возвращаем интерфейсы IDispatch для компонентов из свойства Controls. FOwner TWinControl TWinControl(FOwner) (FEnumPosition < ControlCount) (I < celt) TVariantList(rgvar)[I] := FScriptControl.GetProxy(Controls[FEnumPosition]); Inc(I); Inc(FEnumPosition); ; ; Для TCollection организуется перебор элементов коллекции. FOwner TCollection TCollection(FOwner) (FEnumPosition < Count) (I < celt) TVariantList(rgvar)[I] := FScriptControl.GetProxy(Items[FEnumPosition]); Inc(I); Inc(FEnumPosition); ; ; Для TStrings перебираются строки и возвращаются их значения. FOwner TStrings TStrings(FOwner) (FEnumPosition < Count) (I < celt) TVariantList(rgvar)[I] := TStrings(FOwner)[FEnumPosition]; Inc(I); Inc(FEnumPosition); ; ; Result := S_FALSE; I <> celt Result := S_FALSE; Assigned(pceltFetched) pceltFetched^ := I; ; Метод Skip пропускает запрошенное количество элементов и возвращает S_OK, если еще остались элементы для перебора. TVCLEnumerator.Skip(celt: LongWord): HResult; Total: Integer; Result := S_FALSE; FOwner TWinControl Total := TWinControl(FOwner).ControlCount FOwner TCollection Total := TCollection(FOwner).Count FOwner TStrings Total := TStrings(FOwner).Count Exit; FEnumPosition + celt <= Total Result := S_OK; Inc(FEnumPosition, celt) ; ; Метод Clone клонирует объект, возвращая интерфейс его копии. TVCLEnumerator.Clone( Enum: IEnumVariant): HResult; NewEnum: TVCLEnumerator; NewEnum := TVCLEnumerator.Create(FOwner, FScriptControl); NewEnum.FEnumPosition := FEnumPosition; Enum := NewEnum IEnumVariant; Result := S_OK; ; Для того чтобы класс TVCLProxy мог вернуть интерфейс IEnumVariant, требуется дополнить метод Invoke следующим кодом: DispId DISPID_NEWENUM: // У объекта запрашивают интерфейс IEnumVariant для ForEach // создаем класс, реализующий этот интерфейс OleVariant(VarResult^) := TVCLEnumerator.Create(FOwner, FScriptControl) IEnumVariant; ; Текст этого компонента приведен на CD-ROM. Данный компонент является наследником TScriptControl и реализует функциональность по работе с TVCLProxy. Microsoft ScriptControl – качественное решение для задач, требующих включения в программу интерпретирующего ядра. Интегрировав его с VCL, мы получаем мощный и гибкий инструмент, позволяющий наращивать возможности в любом направлении. Приведенной в данной статье информации вполне достаточно, чтобы на основе помещенного на компакт-диске компонента TVCLScriptControl создать решение, удовлетворяющее любой конкретной задаче. [Назад] |
|
| ||||||||||||||||
|