Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Все по ФБ (VS6).doc
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
210 Кб
Скачать
☆

Последовательность разработки функциональных блоков

  1. Вставьте в проект новый COM- объект Simple Object , Задайте его имя, например, NewObj, на страничке “Attributes” поставьте флажки: Free, Dual, Yes, Free Threaded Marshaler. Можно еще в поле Type задать русское имя, которое будет отображаться в палитре. В idl- файле проекта в конструкцию coclass нового объекта вставьте следующую строку:

[source] dispinterface _IFunkBlockEvents;

  1. Скомпилируйте idl- файл.

  2. В список наследования класса ФБ (CNewObj) добавить шаблон, аналогичный

public CFBImpl< CNewObj>

  1. Имплементируйте Connection Point контрола. Для этого щелчком правой клавиши мыши по классу контрола вызвать локальное меню Класс-Инспектора, и в нем выбрать пункт Implement Connection Point. В появляющемся диалоге Connection Point Wizard’а отметить интерфейс _IFunkBlockEvents. Нажать кнопку ОК, в результате создаются Proxy- классы, реализующие оповещение о событиях контрола.После этого в список наследования класса ФБ добавится строка, аналогичная следующей:

public CProxy_IFuncBlockEvents< CNewObj >

  1. В h-файл блока добавьте строку #include "FBImpl.h"

  2. В разделе BEGIN_COM_MAP(CNewObj) добавить макрос

COM_FB_ENTRY

  1. Поскольку блок реализует два dual-интерфейса, необходимо разрешить неоднозначность, возникающую для декларации в COM MAP интерфейса IDispatch. Это можно сделать, заменив вводящий его макрос COM_INTERFACE_ENTRY(IDispatch) на макрос COM_INTERFACE_ENTRY2, наподобие следующего:

COM_INTERFACE_ENTRY2(IDispatch, INewObj)

  1. В декларацию класса контрола вставить (или заменить существующие) декларации:

public:

HRESULT FinalConstruct() {InitPinMap();return S_OK;} void FinalRelease() {ReleasePinMap();}

HRESULT UpdatePoutData( long lWave);

  1. Декларация имен входов и выходов

BEGIN_PIN_NAMES_DEF

PinName1,

PinName2,

…..

PinNameN,

END_PIN_NAMES_DEF

Декларация имен групп входов и групп выходов

BEGIN_GROUP_NAMES_DEF

GroupName1,

GroupName2,

…..

GroupNameN,

END_GROUP_NAMES_DEF

Замечание: избегайте использования идентификаторов IN и OUT, так как они уже определены в системном h-файле.

Далее описывается структура ФБ внутри определения класса в следующем виде:

BEGIN_FB_MAP

PIN_DEF( DUMMY, "Dummy", VT_R8, 12.45)

POUT_DEF( INTVAL, "IntVal", VT_I4)

POUTGROUP_DEF( SINGROUP, "SinGroup", "Sin", NSin, VT_R8)

FREE_PINGROUP_DEF (GROUP_ID, "Group Name")

END_FB_MAP

 

Макрос PIN_DEF(id, strName, vt, value) определяет вход.

  • id – идентификатор входа, определенный ранее в разделе BEGIN_PIN_NAMES_DEF. Этот идентификатор передается в функцию GetPinData.

  • strName – имя входа, которое отображается в дереве MasterSCADA. (Нельзя давать одинаковые имена входам и выходам одного уровня!)

  • vt – тип переменной (VT_I4, VT_R8, …). Если указать VT_EMPTY, то вход будет наследовать тип связанного с ним выхода.

  • value – значение входа по умолчанию (назначается входу при старте runtime).

 

Макрос POUT_DEF(id, strName, vt) определяет выход.

  • id – идентификатор выхода, определенный ранее в разделе BEGIN_PIN_NAMES_DEF. Этот идентификатор передается в функцию SetPoutData.

  • strName – имя выхода, которое отображается в дереве MasterSCADA

  • vt – тип переменной (VT_I4, VT_R8, …).

 

Макрос PINGROUP_DEF(id, strName, strPinName, vt, Prop, value)

  • id – идентификатор группы входов, определенный ранее в разделе BEGIN_GROUP_NAMES_DEF. Этот идентификатор передается в функцию GetPinData.

  • strName – имя группы, которое отображается в дереве MasterSCADA

  • strPinName – строка, на основе которой строится имена входов этой группы по формату strPinNameN, где N – номер входа ( 0, 1, 2, 3 ...). Если указать в качестве strPinName пустую строчку, то для формирования имени входа будет использоваться функция GetCustomPinName.

  • vt – тип переменных в этой группе (VT_I4, VT_R8, …). Если указать VT_EMPTY, то входы будут наследовать типы связанных с ними выходов. Если указать в качестве типа VT_USERDEFINED, то для получения типа входа будет использоваться функция GetCustomPinVarType.

  • Prop – название свойства объекта FB, которое определяет количество входов в группе. После изменения этого свойства, для того, чтобы в дереве MasterSCADA изменилось число входов, необходимо вызвать Fire_PinSpaceChanged().

  • value – значение по умолчанию для входов этой группы (назначается входам при старте runtime).

 

Макрос POUTGROUP_DEF(id, strName, strPoutName, vt, Prop)

  • id – идентификатор группы выходов, определенный ранее в разделе BEGIN_GROUP_NAMES_DEF. Этот идентификатор передается в функцию SetPoutData.

  • strName – имя группы, которое отображается в дереве MasterSCADA

  • strPoutName – строка, на основе которой строится имена выходов этой группы по формату strPoutNameN, где N – номер выхода (0, 1, 2, 3 ...). Если указать в качестве strPinName пустую строчку, то для формирования имени выхода будет использоваться функция GetCustomPinName.

  • vt – тип переменных в этой группе (VT_I4, VT_R8, …). Если указать в качестве типа VT_USERDEFINED, то для получения типа входа будет использоваться функция GetCustomPinVarType.

  • Prop – название свойства объекта FB, которое определяет количество выходов в группе. После изменения этого свойства, для того, чтобы в дереве MasterSCADA изменилось число выходов, необходимо вызвать Fire_PinSpaceChanged().

Макрос FREE_PINGROUP_DEF описан в разделе «Использование групп, набор входов которых определяется пользователем».

  1. Если необходимо, чтобы вход функционального блока имел такой же тип, как у присоединенного к нему входа, то в качестве vt необходимо прописать значение VT_EMPTY. При этом, если вход ни с чем не связан, то он при переходе в Runtime получит значение value (как и в случае входов, имеющих свой тип). При этом тип константы определится автоматически исходя из значения value.

  2. В .cpp- файле класса контрола реализовать функцию UpdatePoutData. Эта функция выполняет преобразование входных значений в выходные.

UpdatePoutData(long lWave)

Эта функция должна пересчитывать значения на всех выходах ФБ.

 Для установки значений на выходах можно использовать функции

HRESULT SetPoutData(long lPoutIndex, VARIANT varVal, long lWave = -1, FILETIME ftTimeStamp = DEFAULT_TIME, DWORD dwValidity = DEFAULT_VALIDITY) – если выход не находится в группе.

HRESULT SetPoutData(long lGroupIndex, long lGroupPoutIndex, VARIANT varVal, long lWave = -1, FILETIME ftTimeStamp = DEFAULT_TIME, DWORD dwValidity = DEFAULT_VALIDITY) – если выход находится в группе.

  • lGroupIndex – идентификатор группы выходов

  • lGroupPoutIndex – номер выхода в группе (0, 1, 2...)

  • lPoutIndex – идентификатор выхода

  • lWave – номер волны, который был передан в UpdateData. Если значение на выходе устанавливатся не из функции UpdateData, то нужно использовать значение по умолчанию - -1.

  • ftTimeStamp – метка времени. Если DEFAULT_TIME, то на выходе устанавливается метка времени входа, который не обновлялся дольше всего. Если CURRENT_TIME, то устанавливается текущее время.

  • dwValidity – признак недостоверности. Список признаков недостоверности приводится в разделе «Признаки качества в Функциональных блоках».

 

Для получения значений входов можно использовать функции

HRESULT GetPinData(long lPinIndex, VARIANT *pvarVal, FILETIME* pftTimeStamp = NULL, DWORD* pdwValidity = NULL) – если вход не находится в группе.

HRESULT GetPinData(long lGroupIndex, long lGroupPinIndex, VARIANT *pvarVal, FILETIME* pftTimeStamp = NULL, DWORD* pdwValidity = NULL) - если вход находится в группе.

  • lGroupIndex – идентификатор группы входов

  • lGroupPinIndex – номер входа в группе (0, 1, 2...)

  • lPinIndex – идентификатор входа

  • pvarVal – текущее значение на входе, pftTimeStamp – его метка времени, pdwValidity – его достоверность.

Для работы с входами группы, описанной как FREE_PINGROUP_DEF, имеется функция get_ItemCount (GROUP_ID, &nCount), которая возвращает количество входов в группе. Чтение осуществляется как у обычных групп через GetPinData.

Также для получения значений входов можно пользоваться функциями

bool GetPinBool (long nPinIndex)

bool GetPinBool (long nGroupIndex, long nPinIndex)

long GetPinLong (long nPinIndex)

long GetPinLong (long nGroupIndex, long nPinIndex)

double GetPinDouble (long nPinIndex)

double GetPinDouble (long nGroupIndex, long nPinIndex)

 

 ФБ может выполнять некоторые инициализационные операции при переходе в Runtime, и возврате из него. Например, он может производить инициализацию таймеров и их уничтожение.

Для этого нужно переопределить следующие функции (одну, обе, или ни одной):

BOOL ToRuntime() – вызывается при переходе в режим runtime

void ToDesign() – вызывается при возврате из режима runtime

  1. Если в карте BEGIN_FB_MAP была объявлена хотя бы одна группа с пустым шаблоном имени переменной, то в классе ФБ необходимо переопределить следующую функцию -

CString GetCustomPinName(long lGroup, long lPin)

Она должна возвращать действительное имя переменной с индексом lPin в группе с идентификатором lGroup

  1. Если в карте BEGIN_FB_MAP была объявлена хотя бы одна группа с типом значений VT_USERDEFINED, то в классе ФБ необходимо переопределить следующую функцию -

VARTYPE GetCustomPinVarType(long lGroup, long lPin, CComVariant& varDefValue)

Она должна возвращать действительный тип переменной с индексом lPin в группе с идентификатором lGroup. В varDefValue можно установить значение входа по умолчанию.

  1. Добавьте в декларацию класса CATEGORY_MAP, в которой укажите категории, имплементируемые данным объектом. В перечень категорий обязательно должна включаться категория CATID_FB. Кроме того, для дополнительных функциональных блоков необходимо указать категорию CATID_OTHER.

BEGIN_CATEGORY_MAP(CNewObj)

IMPLEMENTED_CATEGORY(CATID_FB)

IMPLEMENTED_CATEGORY(CATID_OTHER)

END_CATEGORY_MAP()

  1. В ресурсы проекта добавить два растровых изображения (Bitmap), отображающих объект в палитре и в дереве проекта, одна иконка- для нормального, вторая для выбранного состояния элемента. Обе иконки имеют размер 16 * 16.

  2. В rgs- файл контрола добавить следующие записи. Значения, проставляемые в этих записях, равны идентификаторам соответствующих ресурсов.

'Images'

{

val 'MainImage' = d '234'

val 'SelectedImage' = d '235'

}

  1. В rgs- файл контрола в строчке, аналогичной

ForceRemove {BEE9D142-396D-11d4-A0A7-006008677772} = s 'Switch Class'

заменить Switch Class на полное русское имя блока. (Если уже само не заменилось).

  1. Страницы свойств.

В системе MasterSCADA для настройки функционального блока есть стандартная страничка свойств, на которой отображаются все свойства ФБ(определенные в его интерфейсе) с возможностью редактирования (если это get-put свойство). Кроме того можно разработать собственные странички свойств для специфичной настройки. Для этого надо:

    1. Разработать объекты-странички свойств для настройки свойств функционального блока. (New ATL Object Controls  Property Page, на закладке Strings в поле Title задать русское имя закладки)

    2. Добавить в список наследования ФБ ISpecifyPropertyPagesImpl<CnewObj>

    3. В COM_MAP класса добавить COM_INTERFACE_ENTRY(ISpecifyPropertyPages)

    4. В раздел BEGIN_PROP_MAP функционального блока добавить (для каждой странички свойств): PROP_PAGE(CLSID_CnewObjPP) где CLSID_CnewObjPP – CLSID странички свойств

  1. Обеспечьте персистентность свойств объекта. Например, следующим образом:

    1. В список наследования добавить public IPersistStreamInitImpl<CNewObj>

    2. В COM_MAP класса добавить COM_INTERFACE_ENTRY(IPersistStreamInit)

    3. Добавить переменную-член класса BOOL m_bRequiresSave;

    4. И, наконец добавить макросы BEGIN_PROP_MAP(CNewObj) END_PROP_MAP()

Если вы аккуратно выполнили все рекомендации, функциональный блок готов!