Доступ к .NET сборкам в Vijeo Citect 2015

Hello World (Cicode)

Завершив работу над созданием .NET сборки "HelloWorld" на C#, можно перейти к написанию некоторого объема cicode, чтобы получить доступ к .NET сборке в Vijeo Citect 2015. Ниже будет показано два примера как это сделать. В первом примере создадим экземпляр класса "HelloWorld", получим значение свойства "Message" и, используя cicode функцию "Message", отобразим стандартное модальное диалоговое окно, которое вызовем из .NET сборки для отображения сообщения "Hello World!". Во втором примере также создадим экземпляр класса "HelloWorld", установим значение свойства "Message" в "Hello World!!!!!" и вызовем метод "DisplayMessage" для отображения стандартное модальное диалоговое окна с сообщением из .NET сборки. Используемые в обоих примерах сicode функций очень похожи.

Полный исходный текст обеих функций на cicode находится в Приложении Б: "Hello World!" код на cicode (Vijeo Citect 2015).

Создание экземпляра класса

Cicode функциям в обоих примерах необходимо создать экземпляр класса "HelloWorld" используя cicode функцию "DllClassCreate". Этой функции в качестве аргумента необходимо передать полный путь к .NET сборке и имя класса. Т.к. конструктор класса в сборке "HelloWorld" не содержит аргументов, передавать какие-либо аргументы в функцию "DllClassCreate" нет необходимости. После завершения вызова cicode функции "DllClassCreate", необходимо проверить с помощью cicode функции "DllClassIsValid" был ли успешно создан экземпляр класса "HelloWorld" .

FUNCTION HelloWorld1()

    //Хендл экземпляра класса hello world
    OBJECT hHelloWorld;
    …
    //Создаем экземпляр класса hello world
    hHelloWorld = DllClassCreate(PathToStr("[RUN]:HelloWorld.dll"), "HelloWorld");
    //Проверяем успешность создания экземпляр класса
    IF DllClassIsValid(hHelloWorld) = 1 THEN
    …

Получение значения свойства

Значения свойств экземпляра класса могут быть получены через вызов cicode функции "DllClassGetProperty". Т.к. в нашем классе свойство строкового типа, то его значение может быть получено в cicode строку "sMessage".

    IF DllClassIsValid(hHelloWorld) = 1 THEN
        //Получаем значение свойства Message
        sMessage = DllClassGetProperty(hHelloWorld, "Message");
        Message("Значение свойства .NET класса", sMessage, 0);

Запись значения в свойство

Запись значений в свойства экземпляра класса могут быть произведены через вызов cicode функции "DllClassSetProperty". Т.к. в нашем классе свойство строкового типа, то можно записать в свойство значение cicode строки "sMessage".

    IF DllClassIsValid(hHelloWorld) = 1 THEN
        //Записываем строковое значение в свойство Message
        DllClassSetProperty(hHelloWorld, "Message", sMessage);

Вызов метода

Методы экземпляра класса могут быть вызваны через вызов cicode функции "DllClassCallMethod", которая в качестве аргумента принимает имя метода. В наше случае для отображения диалогового окно используем метод "DisplayMessage".

    IF DllClassIsValid(hHelloWorld) = 1 THEN
        //Записываем строковое значение в свойство Message
        DllClassSetProperty(hHelloWorld, "Message", sMessage);
        //и отображаем диалоговое окно через вызов метода DisplayMessage
        DllClassCallMethod(hHelloWorld, "DisplayMessage");

Заметим, что данный вызов метода является блокирующим, т.е. пока диалоговое окно не будет закрыто, cicode не продолжит выполняться.

Ограничения

Cicode функции предназначенные для работы с .NET сборками не поддерживают работу со статическими методами и классами и не поддерживают события. По этой причине не рекомендуется c помощью них создавать экземпляры классов с пользовательским интерфейсом.

Вызов предопределенных функций в Windows

Не всегда требуется создавать сборки с классам на C#, чтобы использовать их функциональность в Vijeo Citect 2015 с помощью соответствующих cicode функций. В простых случаях можно вызывать методы напрямую из .NET Framework. Дальше будем использовать функциональность, которая уже встроена в .NET Framework, которая позволяет измерять использование процессора компьютером. Воспользуемся классом "PerformanceCounter" из пространства имен "System.Diagnostics" для измерения использования процессора компьютером, задействовав счетчик производительности "Processor / % Processor Time".

OBJECT oPerformanceCounter;

REAL FUNCTION GetPercentProcessorTime()

    STRING sDllPath;
    STRING sCategoryName = "Processor";
    STRING sCounter = "% Processor Time";
    STRING sInstance = "_Total";
    REAL rProcessorTime = -1;
    STRING sCounterHelp;
    INT iError;

    //Включаем контроль ошибок
    ErrSet(1);

    sDllPath = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\system.dll";

    //Создаем экземпляр класса PerformanceCounter пространства имен System.Diagnostics
    //(добавлять пространство имен, которому принадлежит класс, нет необходимости)
    oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter, sInstance);
    //Проверяем успешность создания экземпляра класса
    IF DllClassIsValid(oPerformanceCounter) THEN
        //Вызываем требуемый метод
        rProcessorTime = DllClassCallMethod(oPerformanceCounter, "NextValue");
        //Получаем значение свойства
        sCounterHelp = DllClassGetProperty(oPerformanceCounter, "CounterHelp");
        ErrLog(sCategoryName + "\" + sCounter + "\" + sInstance+": " + RealToStr(rProcessorTime, 4, 1));
        ErrLog(sCounterHelp);
    ELSE
        ErrLog("GetPercentProcessorTime: Экземпляр класса не создан");
    END
    //Контроль наличия ошибки
    iError = IsError();
    IF iError <> 0 THEN
        ErrLog("GetPercentProcessorTime: Возвращен код ошибки " + iError:# + ".");
    END
    DllClassDispose(oPerformanceCounter);
    RETURN rProcessorTime;
END

Создание объекта

В примере выше, cicode функция "DllClassCreate" вызывалась чтобы создать экземпляр класса "PerformanceCounter" из пространства имен "System.Diagnostics". Ниже приведен cicode, который выполнил эту задачу:

    sDllPath = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\system.dll";
    //Создаем экземпляр класса PerformanceCounter пространства имен System.Diagnostics
    //(добавлять пространство имен, которому принадлежит класс, нет необходимости)
    oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter, sInstance);

По информации из MSDN, класс "PerformanceCounter" имеет шесть конструкторов:

  • PerformanceCounter();
  • PerformanceCounter(string categoryName, string counterName);
  • PerformanceCounter(string categoryName, string counterName, bool readOnly);
  • PerformanceCounter(string categoryName, string counterName, string instanceName);
  • PerformanceCounter(string categoryName, string counterName, string instanceName, bool readOnly);
  • PerformanceCounter(string categoryName, string counterName, string instanceName, string machineName);

Cicode функции "DllClassCreate" (и "DllClassCallMethod") в отличии от других аналогичных cicode функций Vijeo Citect 2015, например, таких как "DllOpen" или "TaskNew", могут принимать переменное количество аргументов. Это значит, что нет необходимости объединять все аргументы функций в одну строку, отделяя каждый аргумент знаком "^".

Таким образом, при использовании cicode функции "DllClassCreate", ей просто передается столько аргументов сколько необходимо для вызова конкретного конструктора класса. Т.е. при создании экземпляра класса "PerformanceCounter" для вызова каждого из конструкторов перечисленных выше, необходимо выполнить соответственно следующий cicode:

  • oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter");
  • oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter);
  • oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter, 1);
  • oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter,sInstance);
  • oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter,sInstance, 1);
  • oPerformanceCounter = DllClassCreate(sDllPath, "PerformanceCounter", sCategoryName, sCounter,sInstance, sMachineName);

В первом аргументе cicode функции "DllClassCreate" необходимо передать полный путь к актуальной сборке содержащей класс, экземпляр которого необходимо создать. Если планируется осуществлять прямой вызов .NET сборок, то необходимо точно знать в какой сборке находится требуемый класс. Более подробно узнать о том, в какой сборке находятся требуемый класс можно на сайте MSDN.

Необходимо помнить, что для каждого созданного экземпляр класса, после завершения его использования, необходимо вызывать cicode функцию "DllClassDispose", которая завершает работу с экземпляром класса.

Поддерживаемые типы данных

.NET Framework поддерживает огромное количество числовых типов данных, намного больше чем поддерживается cicode. Следующая таблица показывает как .NET типы данных могут быть приведены к cicode типам данных. Эти преобразования применимы к cicode функциям "DllClassCallMethod", "DllClassGetProperty" и "DllClassSetProperty".

  int Real
Bool True False
Byte True False
Decimal False False
Double False False
Float False True
Int True False
Long True False
SByte True False
UINT True False
Ulong True False
Ushort True False
Int16 True False
Int32 True False
Uint16 True False
Uint32 True False
Uint64 False False
short True False

Функции .NET сборок не поддерживают приведение числовых .NET типов к строковому типу данных в cicode. Для преобразования числовых типов в строки используются cicode функции "IntToStr" или "RealToStr".

Пример: Создание пейджинговой системы алармов

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

  • Конфигурирование полей "Paging" и "Paging Group";
  • Настройка очереди событий алармов;
  • Отправка оповещений об алармах по электронной почте.

Конфигурирование полей "Paging" и "Paging Group"

Каждый тип аларма в Vijeo Citect содержит два поля, которые могут быть сконфигурированы для слежения за срабатыванием аларма.

  • Поле "Paging" - может принимать значение true/false, что определяет включено (true) или выключено (false) слежение за срабатыванием аларма;
  • Поле "Paging Group" - строковое поле, которое используется для индикации какой пейджинговой группе принадлежит аларм. Это поле можно использовать для задания группы пользователей, которые будет получать информацию о срабатывании аларма или алармов.

Поля "Paging" и "Paging Group" находятся в расширенной части формы конфигурирования для всех типов алармов Vijeo Citect 2015 SP1. В нашем примере не будем использовать поле "Paging Group".

Доступ к .NET сборкам в Vijeo Citect 2015. Расширенная форма конфигурирования дискретных алармов
Рис. 7. Расширенная форма конфигурирования дискретных алармов

Очередь событий алармов

Очередь событий алармов - это элемент программной архитектуры Vijeo Citect, связанный с обработкой алармов. Суть данного элемента в том, что при обнаружении сервером алармов выполнения условия аларма создается событие, которое может быть помещено в очередь и к очереди может быть получен программный доступ для чтения этих событий. Очередь событий алармов может быть включена путем установки следующего параметра в файле "citect.ini":

[Alarm]
EventQue = 1

Формат очереди событий алармов может конфигурироваться через задания значения следующему параметру в файле "citect.ini":

[Alarm]
EventFmt = {Name,48},{Time,12},{Category,3},{STATE,16},{PAGING,4},{PAGINGGROUP,80}

Более детальное описание этих параметров находится во встроенной или онлайн помощи Vijeo Citect.

Для обработки очереди событий алармов напишем cicode функцию, которая будет выполняться на сервере алармов. Функция будет читать содержимое очереди событий алармов, разбирать содержимое очереди и затем, или посылать письмо по электронной почте, или отправлять СМС основываясь на следующих условиях:

  • Paging = 1, State = ON, PagingGroup = Email
  • Paging = 1, State = ON, PagingGroup = SMS

Для доступа к содержимому очереди событий алармов в Vijeo Citect существуют следующие функции:

  • QueOpen;
  • QueRead;
  • QueLength;

Более детально описание этих фунций содержиться во встроенной или онлайн помощи Vijeo Citect. Полный исходный код на cicode, который используется для чтения и разбора очереди событий алармов может быть найден в Приложение В: ProcessEventQue(), код на cicode (Vijeo Citect 2015).

WHILE 1 DO
    //Использование функции QueOpen для открытия очереди событий алармов
    hQueue = QueOpen("EventQue", 0);
    Sleep(1);
    IF hQueue<> -1 THEN
        //Если очередь не пустая
        iQueLength = QueLength(hQueue);
        IF iQueLength > 0 THEN
            iQueStatus = 0;
            WHILE iQueStatus = 0 DO
                //Чтение каждой записи очереди
                iQueStatus = QueRead(hQueue, iRecord, sAlarmFmt, 1);

В нашем примере в переменной "sAlarmFmt" будет находится строка в формате указанном в параметре "[Alarm] EventQueFmt". Теперь осталось разобрать данную строку на поля используя строковые функции Vijeo Citect.

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

IF ((sPaging = "TRUE") AND (iCategory = 2) AND (sState = "ON")) THEN
    SendEmail("forum(AT)proasutp.com", sAlarmName, "TIME: " + sTime + " STATE: " + sState);
END

Отправка оповещения об аларме по электронной почте

В примере ниже будет показано как использовать функции из .NET сборки для отправки электронной почты. Предварительно необходимо иметь или создать учетную запись на одном из публичных почтовых серверов, например, yandex.ru, mail.ru, inbox.ru и т.д. Отправка электронной почты будет осуществляться путем прямого вызова функций из сборки .NET Framework.

INT FUNCTION SendEmail(STRING sTo, STRING sSubject, STRING sMessage, STRING sFrom, STRING sPassword, STRING sSMTPServer)

    STRING sPath = "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client\System.dll";
    OBJECT hCredentialsProxy;
    OBJECT hSmtpClientProxy;
    INT result;
    INT iError = 0;

    hSmtpClientProxy = DllClassCreate(sPath, "SmtpClient", sSMTPServer);
    IF DllClassIsValid(hSmtpClientProxy) = 1 THEN
        DllClassSetProperty(hSmtpClientProxy, "Port", 587)
        DllClassSetProperty(hSmtpClientProxy, "UseDefaultCredentials", 0)
        DllClassSetProperty(hSmtpClientProxy, "EnableSsl", 1);
        hCredentialsProxy = DllClassCreate(sPath, "NetworkCredential", sFrom, sPassword);
        IF DllClassIsValid(hCredentialsProxy) THEN
            DllClassSetProperty(hSmtpClientProxy, "Credentials", hCredentialsProxy);
            result = DllClassCallMethod(hSmtpClientProxy, "Send", sFrom, sTo, sSubject, sMessage);
            iError = IsError();
        END
    END

    DllClassDispose(hSmtpClientProxy);
    DllClassDispose(hCredentialsProxy);

    RETURN iError;
END

Cicode функция "SendEmail" отправляет электронное письмо путем создания экземпляра класса "SMTPClient" из пространства имен "System.Net.Mail" и "NetworkCredentials" из "System.Net", для передачи имени пользователя и пароля. Более подробно об этих классах можно узнать по следующим ссылкам:

В вышеприведенной cicode функции "SendEmail", сначала создан экземпляр класса "SMTPClient" с использованием cicode функции "DllClassCreate" с передачей в качестве аргумента адреса SMTP сервера. Затем, после успешного создания экземпляра класса, присвоение соответствующим свойствам параметров соединения с SMTP сервером.

hSmtpClientProxy = DllClassCreate(sPath, "SmtpClient", sSMTPServer);

После создания экземпляра класса, необходимо проверить успешно ли он создан или нет. Это можно сделать используя cicode функцию "DllClassIsValid". Эта функция возвращает 1, если экземпляр класса был успешно создан.

IF DllClassIsValid(hSmtpClientProxy) = 1 THEN

После успешного создания класса можно присвоить значения свойствам отвечающие за настройку связи с SMTP сервером с помощью cicode функции "DllClassSetProperty". В приведенном выше коде cicode функции "SendEmail" присвоено значение четырем свойствам. Первые три свойства - это простые типы данных, поэтому они могут быть записаны непосредственно используя cicode функцию "DllClassSetProperty", как показано ниже:

DllClassSetProperty(hSmtpClientProxy, "Port", 587);
DllClassSetProperty(hSmtpClientProxy, "UseDefaultCredentials", 0);
DllClassSetProperty(hSmtpClientProxy, "EnableSsl", 1);
Свойство Тип данных Значение
EnableSsl Boolean True
Port Int 587
UseDefaultCredentials Boolean False
Credentials System.Net.NetworkCredential *

Четвертое свойство "Credentials" должно содержать ссылку на экземпляр класса, в нашем случае на экземпляр класса "System.Net.NetworkCredentials". Таким образом, необходимо сначала создать с помощью cicode функции "DllClassCreate" экземпляр класса "System.Net.NetworkCredentials" с передачей функции в качестве дополнительных аргументов имени пользователя и пароля. После проверки на успешность создания экземпляра класса, хэндл созданного экземпляра класса может быть передан в качестве значения четвертого свойства, т.е. свойства "Credentials" с помощью cicode функции "DllClassSetProperty".

hCredentialsProxy = DllClassCreate(sPath, "NetworkCredential", sFrom, sPassword);
IF DllClassIsValid(hCredentialsProxy) THEN
    DllClassSetProperty(hSmtpClientProxy, "Credentials", hCredentialsProxy);
    …

Теперь можно отправить электронное письмо используя метод Send, передав необходимую информацию с помощью cicode функции "DllClassCallMethod".

result = DllClassCallMethod(hSmtpClientProxy, "Send", sFrom, sTo, sSubject, sMessage);

И, наконец, необходимо завершить использование экземпляров классов "SMTPClient" и "NetworkCredential" с помощью вызова cicode функции "DllClassDispose".

DllClassDispose(hSmtpClientProxy);
DllClassDispose(hCredentialsProxy);

Использование вызываемых напрямую из сборок .NET Framework функций рекомендуется только для решения простых задач. В большинстве случаев создание своих собственных .NET классов и вызов методов и свойств с помощью соответствующих cicode функций Vijeo Citect 2015 более эффективно и эффективно по следующим причинам:

  • Приходится писать меньший объем кода;
  • Существенно проще отладка написанного кода;
  • Есть доступ к широкому кругу классов и типов данных;
  • Есть доступ к статическим классам и методам.

Страницы

Теги: