Использование Microsoft ScriptControl

Оператор For Each

Удобным средством, предоставляемым VBScript, является оператор For Each, организующий цикл по всем элементам заданной коллекции. Добавим поддержку этого оператора в наш компонент.

В начало В начало

Интерфейс IEnumVariant

Реализация For Each предусматривает следующее:

  1. Исполняющее ядро ScriptControl вызывает метод Invoke объекта, по элементам которого должен производиться цикл с DispID = DISPID_NEWENUM (-4).
  2. Объект должен вернуть интерфейс IenumVariant.
  3. Далее ядро использует методы IEnumVariant для получения элементов коллекции.

Интерфейс 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; ;  

поэтому для корректной реализации интерфейс должен быть переопределен.

В начало В начало

Класс TVCLEnumerator

Создадим класс, инкапсулирующий функциональность 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, который получает следующие переменные:

  • celt – количество запрашиваемых элементов;
  • rgvar – адрес первого элемента массива переменных типа OleVariant;
  • pceltFetched – адрес переменной, в которую должно быть записано количество реально переданных элементов. Этот адрес может быть равен NIL, в этом случае не потребуется ничего записывать.

Метод должен заполнить запрошенное количество элементов 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;
       ;  
В начало В начало

Компонент TVCLScriptControl

Текст этого компонента приведен на CD-ROM. Данный компонент является наследником TScriptControl и реализует функциональность по работе с TVCLProxy.

В начало В начало

Заключение

Microsoft ScriptControl – качественное решение для задач, требующих включения в программу интерпретирующего ядра. Интегрировав его с VCL, мы получаем мощный и гибкий инструмент, позволяющий наращивать возможности в любом направлении. Приведенной в данной статье информации вполне достаточно, чтобы на основе помещенного на компакт-диске компонента TVCLScriptControl создать решение, удовлетворяющее любой конкретной задаче.

КомпьютерПресс 7'2001

Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует