Содержание материала

 

Пишем GetIdsOfNames

В методе GetIdsOfNames мы должны проверить наличие запрошенного свойства и вернуть адрес его структуры TPropInfo, если такое свойство найдено.

Свойства компонентов VCL

Code:

function TVCLProxy.GetIDsOfNames(const IID: TGUID; Names: Pointer;

NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;

var

S: String;

Info: PPropInfo;

begin

Result := S_OK;

// Получаем имя функции или свойства

S := PNamesArray(Names)[0];

// Проверяем, есть ли VCL свойство с таким-же именем

Info := GetPropInfo(FOwner.ClassInfo, S);

if Assigned(Info) then begin

   // Свойство есть, возвращаем в качестве DispId

   // адрес структуры PropInfo

   PDispIdsArray(DispIds)[0] := Integer(Info);

end

 

 

 

Дополнительные функции

Дополним нашу реализацию возможностью вызова некоторых дополнительных функций:

Controls

Для наследников TWinControl возвращает ссылку на дочерний компонент с именем или индексом, заданным в параметре

Count

Для компонентов TWinControl возвращает количество дочерних компонентов

Для TCollection возвращает количество элементов

Для TStrings возвращает количество строк

Add

Для компонентов TWinControl создает дочерний компонент

Для TCollection добавляет элемент в коллекцию

Для TStrings добавляет строку

HasProperty

Возвращает истину, если у объекта есть свойство с заданным именем

Для этого дополним метод GetIdsOfNames следующим кодом:

Code:

else

// Нет такого свойства, проверяем, не имя ли это

// одной из определенных нами функций

if CompareText(S, 'CONTROLS') = 0 then begin

   if (FOwner is TWinControl) then

     PDispIdsArray(DispIds)[0] := DISPID_CONTROLS

   else

     Result := DISP_E_UNKNOWNNAME;

end

else

if CompareText(S, 'COUNT') = 0 then begin

   if (FOwner is TCollection) or (FOwner is TStrings)

      or (FOwner is TWinControl) then

     PDispIdsArray(DispIds)[0] := DISPID_COUNT

   else

     Result := DISP_E_UNKNOWNNAME;

end

else

if CompareText(S, 'ADD') = 0 then begin

   Result := S_OK;

   if (FOwner is TCollection) or (FOwner is TStrings) or

      (FOwner is TWinControl) then

     PDispIdsArray(DispIds)[0] := DISPID_ADD

   else

     Result := DISP_E_UNKNOWNNAME;

end

else

if CompareText(S, 'HASPROPERTY') = 0 then

   PDispIdsArray(DispIds)[0] := DISPID_HASPROPERTY

else

   Result := DISP_E_UNKNOWNNAME;

end;

 

 

 

Константы DISPID_CONTROLS, DISPID_COUNT и т.д. определены как целые числа из диапазона 1 … 1 000 000. Это вполне безопасно, т.к. адрес структуры TPropInfo никак не может оказаться ниже 1 Мб

 

Пишем Invoke

Первая часть задачи выполнена мы проинформировали OLE о наличии в нашем сервере автоматизации поддерживаемых функций. Теперь необходимо реализовать метод Invoke для выполнения этих функций. Из соображений модульности Invoke выполняет подготовительную работу со списком параметров и вызывает метод DoInvoke, в котором мы осуществляем трансляцию DispID в обращения к методам класса VCL.

В методе используются три служебных функции:

CheckArgCount проверяет количество переданных аргументов

_ValidType проверяет соответствие аргумента с заданным индексом заданному типу

_IntValue получает целое число из аргумента с заданным индексом

 

Code:

function TVCLProxy.DoInvoke(DispID: Integer; const IID: TGUID;

LocaleID: Integer; Flags: Word; var dps: TDispParams;

pDispIds: PDispIdList; VarResult, ExcepInfo, ArgErr: Pointer

): HResult;

var

S: String;

Put: Boolean;

I: Integer;

P: TPersistent;

B: Boolean;

OutValue: OleVariant;

begin

Result := S_OK;

case DispId of

 

 

 

 

Для функции Controls мы должны проверить, что передан один параметр. Если он строковый дочерний компонент ищется по имени, иначе по индексу. Если компонент найден вызывается функция FScriptControl.GetProxy, которая проверяет, есть ли уже «представитель» у этого компонента, при необходимости создает его и возвращает интерфейс IDispatch. Такой алгоритм необходим для корректной работы оператора VBScript Is, который сравнивает две ссылки на объект и выдает истину, если это один и тот же объект, например:

 

Code:

Dim A

Dim B

 

Set A = C

Set B = C

 

If A is B Then ...

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить