среда, 11 апреля 2012 г.

Шпаргалка. Использование Microsoft Script Control в приложениях - #3

Создание функции

В данной заметке продолжим разбираться с работой Script Control, мы разобрались, как создавать процедуры, теперь научимся создавать функции. На самом деле функции мы уже имеем создавать, как там, а очень просто – вспомним, чем отличается функция от процедуры. А тем, что процедура не возвращает никаких данных, значит, добавив в процедуру возможность, возвращение результата мы превратим ее в функцию.
И это очень просто. Если вы обратили внимание на заголовок метода Invoke, вы можете увидеть там параметр VarResult. Для процедур он возвращает NIL, для функций он возвращает любое отличное от NIL значение – строку, логическое поле, число и т.п.

Проиллюстрируем это на примере, добавим в наш класс обработку метода GETRANDOMNUMBER – который будет возвращать нам случайно сгенерированное число в диапазоне от 1..100. Доработаем наш пример:

case DispID of
       * * *
       DISPID_GetRandomNumber :
        begin
          // Проверка на кол-во параметров
          if not CheckArgCount(P.cArgs, 0, ExcepInfo) then
          begin
             Result := DISP_E_EXCEPTION;
             Exit;
          end;
          Randomize;
          OleVariant(VarResult^) := Random(100);
        end;
  end;

Запустим проект и введем такой скрипт:

Sub Main()
Dim Number
Number = MyCLASS.GetRandomNumber
MyCLASS.MessageInformation(CStr(Number))
End Sub

Проверим его работу – работает, функция GetRandomNumber стала возвращать случайно сгенерированное число. Правда, ничего сложного.
Итак с процедурами и функциями мы разобрались.Однако остался очень непростой вопрос – “А что делать в случае когда функция должна вернуть несколько значений” Ответ на него прост – используем var-параметры функции. По аналогии с var параметрами в Delphi.

Работа с var-параметрами в функции или процедуре

Прежде чем мы разберем механизм работы Var-параметров в Script Control сделаю маленькую ремарку.
Как вы уже помнили, в первом примере MessageInformation мы работали с передаваемым параметром строкой, а именно P.rgvarg^[0]. Если мы посмотрим в документацию по методу Invoke более внимательным взглядом, то обратим внимание, что параметр Params метода Invoke представляет собой массив указателей на Variant-типы. Т.к. в первом примере у нас был только один параметр то мы, и использовали указатель на индекс массива [0].
В случае если в процедуру или функцию передаются несколько параметров,то следует обратить внимание вот на что, т.к. соглашение вызовов для метода Invoke имеет тип stdcall что характерно практически для всех функций winapi, то параметры передаются через стек, справа налево.

Т.е. если мы делаем процедуру например Concat

Sub Main()
Dim Number
MyCLASS.Concat(“Строка 1”, “Строка 2” , “Строка 3”)
End Sub

то в массиве параметр “Cтрока 1” , будет идти под идексом 2, а “Строка 3” – 0. Не забывайте об этом. Переработает немного наш метод GetRandomNumber и допишем на основе него новый метод GetRandomNumberStr. Единственное отличие которого будет состоять в том что помимо возврата случайного числа в виде текста, в параметре будет возвращаться само число в числовом виде. Неказистый пример, но до понимания пойдет. Прототипом метода будет служить такое описание, если перевести его на Delphi:

function GetRandomNumberStr(var Number : Integet) : String;

Смотрим
case DispID of
* * *
       DISPID_GetRandomNumberSTR :
        begin
          // Проверка на кол-во параметров
          if not CheckArgCount(P.cArgs, 1, ExcepInfo) then
          begin
             Result := DISP_E_EXCEPTION;
             Exit;
          end;
          if IsValidType(P.rgvarg^[0], VT_VARIANT or VT_BYREF) then
          begin
             Randomize;
             Number :=  Random(100);

             // Устанавливаем тип возвращаемого значения
             P.rgvarg^[0].vt := VT_I4;
             P.rgvarg^[0].pvarVal^ := Number;   // число вернем в параметре

             OleVariant(VarResult^)   := IntToStr(Number); // строку в виде результата функции
          end
          else
          begin
              SetErrorCheckParamsType(ExcepInfo, fn_MESSAGEINFORMATION);
              Result := DISP_E_EXCEPTION;
          end;
        end;

Проверим работу на VBS-скрипте

Sub Main()
Dim NumberStr
Dim Number
Number = -1
NumberStr = MyCLASS.GetRandomNumberStr(Number)
MyCLASS.MessageInformation(NumberStr + " - " + CStr(Number) )
End Sub

Работает. Давайте разберем, что конкретно у нас поменялось.
Первое на что нужно обратить внимание это на проверку типа параметра на VT_VARIANT or VT_BYREF Флаг говорит VT_BYREF обычно комбинируется с другой константой VT_XXX и показывает, что в параметре хранится не само значение, а ссылка на это значение, хранящееся где-либо ещё, то есть, поменяв по представленной ссылке значение, мы можем передать из методы наши данные. Для этого желательно нужно установить тип возвращаемого значения (что бы Script Control знал тип Variant-переменной) и в соответвующее поле структуры tagVARIANT вписать новое значение .

// Устанавливаем тип возвращаемого значения
     P.rgvarg^[0].vt := VT_I4;
     P.rgvarg^[0].pvarVal^ := Number;   // число вернем в параметре pvarVal, для типа VT_I4

Вот в принципе и все, как видите тоже ничего особо сложного.

Продолжение следует…

Комментариев нет:

Отправить комментарий