Таким образом, мы реализовали полную функциональность по трансляции вызовов OLE в обращения к свойствам VCL. Наш компонент может динамически создавать другие компоненты на форме, обращаться к их свойствам и даже обрабатывать возникающие в них события.
Оператор For Each
Удобным средством, предоставляемым VBScript, является оператор For Each, организующий цикл по всем элементам заданной коллекции. Добавим поддержку этого оператора в наш компонент.
Интерфейс IEnumVariant
Реализация For Each предусматривает следующее:
1. | Исполняющее ядро ScriptControl вызывает метод Invoke объекта, по элементам которого должен производиться цикл с DispID = DISPID_NEWENUM (-4). |
2. | Объект должен вернуть интерфейс IEnumVariant |
3. | Далее ядро использует методы IEnumVariant для получения элементов коллекции. |
Интерфейс IEnumVariant определен как:
Code: |
type IEnumVariant = interface(IUnknown) ['{00020404-0000-0000-C000-000000000046}'] function Next(celt: LongWord; var rgvar: OleVariant; pceltFetched: PLongWord): HResult; stdcall; function Skip(celt: LongWord): HResult; stdcall; function Reset: HResult; stdcall; function Clone(out Enum: IEnumVariant): HResult; stdcall; end; |
В модуле ActiveX.pas в оригинальной поставке Delphi5 ошибочно определен метод Next
Code: |
function Next(celt: LongWord; var rgvar: OleVariant; out pceltFetched: LongWord): HResult; stdcall; |
поэтому для корректной реализации интерфейс должен быть переопределен.
Класс TVCLEnumerator
Создадим класс, инкапсулирующий функциональность IEnumVariant
Code: |
type TVCLEnumerator = class(TInterfacedObject, IEnumVariant) private FEnumPosition: Integer; FOwner: TPersistent; FScriptControl: TVCLScriptControl; { IEnumVariant } function Next(celt: LongWord; var rgvar: OleVariant; pceltFetched: PLongWord): HResult; stdcall; function Skip(celt: LongWord): HResult; stdcall; function Reset: HResult; stdcall; function Clone(out Enum: IEnumVariant): HResult; stdcall; public constructor Create(AOwner: TPersistent; AScriptControl: TVCLScriptControl); end; |
Конструктор устанавливает свойства FOwner и FScriptControl
Code: |
constructor TVCLEnumerator.Create(AOwner: TPersistent; AScriptControl: TVCLScriptControl); begin inherited Create; FOwner := AOwner; FScriptControl := AScriptControl; FEnumPosition := 0; end; Метод Reset подготавливает реализацию интерфейса к началу перебора function TVCLEnumerator.Reset: HResult; begin FEnumPosition := 0; Result := S_OK; end; |
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!