Ниже приведен интерфейсный модуль для разработки DLL доступа к данным в среде Borland Delphi. Этот модуль содержит описания используемых интерфейсов.
//////////////////////////////////////////////////////////////////////////////// // // Описание интерфейсов для взаимодействия OPC сервера и DLL доступа к данным. // DLL доступа к данным реализует доступ у специфичному оборудованию. // //////////////////////////////////////////////////////////////////////////////// unit PluginInterface; interface uses Windows, SysUtils, OPCDA, OPCtypes; const // Коды ошибок при работе с устройством(специфичные): // ошибка инициализации E_COMPORT_INVALID_PORT_INIT = HResult($CFFF0000); // ошибка таймаута E_COMPORT_TIMEOUT = HResult($CFFF0001); // неверная контрольная сумма E_INVALID_CRC = HResult($CFFF0002); // ошибка конфигурации GSM модема E_GSM_ERROR_CONFIG = HResult($CFFF0003); // SMS сообщение забуферизировано E_GSM_SMS_BUFFERED = HResult($CFFF0004); // Неизвестный формат ответа E_UNCKNOWN_ANSWER = HResult($CFFF0005); // Значения качества(специфичные->младший байт-стандартный, старший байт-специфичный) // ошибка инициализации COM порта OPC_QUALITY_INVALID_PORT_INIT = $0118; // OPC_QUALITY_COMM_FAILURE = $18; // ошибка таймаута OPC_QUALITY_TIMEOUT = $0218; // OPC_QUALITY_COMM_FAILURE = $18; // неверная контрольная сумма OPC_QUALITY_INVALID_CRC = $0318; // OPC_QUALITY_COMM_FAILURE = $18; // ошибка конфигурации GSM модема OPC_QUALITY_GSM_ERROR_CONFIG = $0418; // OPC_QUALITY_COMM_FAILURE = $18; // SMS сообщение забуферизировано OPC_QUALITY_GSM_SMS_BUFFERED = $0518; // OPC_QUALITY_COMM_FAILURE = $18; // Неизвестный формат ответа OPC_QUALITY_UNCKNOWN_ANSWER = $0618; // OPC_QUALITY_COMM_FAILURE = $18; // Сообщения WM_USER = $0400; // Сообщения для формы конфигурации // сообщение - изменена конфигурация WM_CONFIGMESS_CHANGE = WM_USER+300; // сообщение - сохранить текущую конфигурацию WM_CONFIGMESS_SAVE = WM_USER+301; // сообщение - обновить поля формы WM_CONFIGMESS_REFRESH = WM_USER+303; // сообщение - закрытие формы WM_CONFIGMESS_CLOSE = WM_USER+304; // Сообщения для формы параметров узла при добавлении узла // сообщение - кнопка "Добавить" недоступна WM_ADDNODEMESS_DISABLE_ADD = WM_USER+310; // сообщение - кнопка "Добавить" недоступна WM_ADDNODEMESS_ENABLE_ADD = WM_USER+311; // сообщение - добавить узел WM_ADDNODEMESS_ADD_NODE = WM_USER+312; // сообщение - закрыть форму WM_ADDNODEMESS_CLOSE_FORM = WM_USER+313; // сообщение - добавить/изменить узел WM_ADDNODEMESS_ADD_CHANGE_NODE = WM_USER+314; // сообщение - закрытие формы WM_ADDNODEMESS_CLOSE = WM_USER+304; // Сообщения для формы параметров переменной при добавлении переменной // сообщение - кнопка "Добавить" недоступна WM_ADDITEMMESS_DISABLE_ADD = WM_USER+320; // сообщение - кнопка "Добавить" недоступна WM_ADDITEMMESS_ENABLE_ADD = WM_USER+321; // сообщение - добавить переменную WM_ADDITEMMESS_ADD_ITEM = WM_USER+322; // сообщение - закрыть форму WM_ADDITEMMESS_CLOSE_FORM = WM_USER+323; // сообщение - добавить/изменить переменную WM_ADDITEMMESS_ADD_CHANGE_ITEM = WM_USER+324; // сообщение - закрытие формы WM_ADDITEMMESS_CLOSE = WM_USER+304; // Сообщения для формы параметров узла при изменении узла // сообщение - изменить параметры узла WM_CHANGENODEMESS_CHANGE_NODE = WM_USER+330; // сообщение - обновить поля формы WM_CHANGENODEMESS_REFRESH = WM_USER+331; // Сообщения для формы параметров переменной при изменении переменной // сообщение - изменить параметры переменной WM_CHANGEITEMMESS_CHANGE_ITEM = WM_USER+340; // сообщение - обновить поля формы WM_CHANGEITEMMESS_REFRESH = WM_USER+341; type // свойство переменной PItemProperty = ^TItemProperty; TItemProperty = record vtDataType: TVarType; wReserved: Word; dwPropertyID: DWORD; szItemID: ShortString; szDescription: ShortString; vValue: OleVariant; hrErrorID: HResult; dwReserved: DWORD; end; PItemAttributes = ^TItemAttributes; TItemAttributes = record szAccessPath: ShortString; szItemID: ShortString; bActive: BOOL; hClient: OPCHANDLE; hServer: OPCHANDLE; dwAccessRights: DWORD; dwBlobSize: DWORD; pBlob: PByteArray; // указатель на массив байтов (array[0..32767] of Byte) vtRequestedDataType: TVarType; vtCanonicalDataType: TVarType; dwEUType: OPCEUTYPE; vEUInfo: OleVariant; end; ILcsItem = interface; TItemProperties = array of TItemProperty; // свойства переменной PItemProperties = ^TItemProperties; TTask = (tNone, tSyncRead, tSyncWrite, tAsyncRead, tAsyncWrite); TPriority = (prNormal, prHigh, prHighest); PResult = ^HRESULT; // параметры задачи TTaskDef = record Task: TTask; // тип задачи Item: ILcsItem; // переменная TransactID: Cardinal; // идентификатор транзакции ptrItemStr: PChar; // имя переменной ptrItemState: POPCITEMSTATE; // состояние переменной ptrNodeProperties: PItemProperties; // свойства узла для данной переменной ptrItemProperties: PItemProperties; // свойства переменной ptrReturnState: POPCITEMSTATE; // состояние в которое возвращается значение переменной // (используется в специфичных ситуациях) ptrResult: PResult; // результат выполнения задачи (для синхронных задач) ptrItemID: PChar; // полное имя end; PTaskDef = ^TTaskDef; // права на изменение переменной (узла) TAccessChange = ( acChangeProps, // изменение свойств acAddNode, // добавление узлов acAddItem, // добавление переменных acDelete, // удаление переменной(узла) acCopy // копирование переменной(узла) ); TAccessChangeItem = set of TAccessChange; ILcsOPCServer = interface; ILcsComPort = interface; //----------------------------------------------------------------- // Интерфейс предоставляющий набор функций библиотеки, реализующей доступ // к данным, для OPC сервера (реализуется в DLL) ILcsDriver = interface ['{31DE528E-EA4E-4AC4-86A4-5E73D18A4FCA}'] // Инициализация драйвера // Вход: AOPCServer - указатель на интерфейс ILcsOPCServer, // AComPort - указатель на интерфейс ILcsComPort // Выход: AName - имя DLL доступа к данным, // ADescript - описание DLL доступа к данным, // AHelpFileName - имя файла помощи (без пути, // расположен в одном каталоге с DLL, если нет помощи - '') // P.S. Вызывается два раза. В начале работы чтобы передать указатели на // интерфейсы и получить описание драйвера. И в конце, тогда передаются // AOPCServer = nil и AComPort = nil. В последнем случае необходжимо // обнулить указатели (nil) на интерфейсы ILcsOPCServer и ILcsComPort, // иначе произойдет исключение при обнулении указателей на интерфейсы // если объекты реализующие эти интерфейсы удалены. procedure Initial(AOPCServer: ILcsOPCServer; AComPort: ILcsComPort; out AName, ADescript, AHelpFileName: ShortString); stdcall; // Создание формы конфигурации // Вход: AParentHandle - хэндл родительского визуального контейнера // Выход: AChildHandle - хэндл дочерней формы, // AWidthChild - ширина дочерней формы, // AHeightChild - высота дочерней формы, // Result - True -> форма конфигурации включена, False -> не включена // P.S. 1) На сервере форма отображается с размерами AWidthChild, AHeightChild // 2) Связь между формами через сообщения (см. WM_CONFIGMESS_XXX) // передаваемые окну AChildHandle(обязательно SendMessage) function ConfigCreate(AParentHandle: THandle; out AChildHandle: THandle; out AWidthChild, AHeightChild: integer): boolean; stdcall; // Создание формы добавления узла (группа переменных) // Вход: AParentHandle - хэндл родительского визуального контейнера, // AItem - родительская переменная // Выход: AChildHandle - хэндл дочерней формы, // AWidthChild - ширина дочерней формы, // AHeightChild - высота дочерней формы, // Result - True -> форма конфигурации включена, False -> не включена // P.S. 1) На сервере форма отображается с размерами AWidthChild, AHeightChild // 2) Связь между формами через сообщения (см. WM_ADDNODEMESS_XXX) // передаваемые окну AChildHandle(обязательно SendMessage) function AddNodeCreate(AParentHandle: THandle; AItem: ILcsItem; out AChildHandle: THandle; out AWidthChild, AHeightChild: integer): boolean; stdcall; // Создание формы добавления переменной // Вход: AParentHandle - хэндл родительского визуального контейнера, // AItem - родительская переменная, // AProps - свойства родителькой переменной // Выход: AChildHandle - хэндл дочерней формы, // AWidthChild - ширина дочерней формы, // AHeightChild - высота дочерней формы, // Result - True -> форма конфигурации включена, False -> не включена // P.S. 1) На сервере форма отображается с размерами AWidthChild, AHeightChild // 2) Связь между формами через сообщения (см. WM_ADDITEMMESS_XXX) // передаваемые окну AChildHandle(обязательно SendMessage) function AddItemCreate(AParentHandle: THandle; AItem: ILcsItem; AProps: PItemProperties; out AChildHandle: THandle; out AWidthChild, AHeightChild: integer): boolean; stdcall; // Изменение параметров переменной // Вход: AParentHandle - хэндл родительского визуального контейнера, // AItem - родительская переменная, // AItemName - имя переменной, // AFlag - признак узла (OPC_BROWSE_HASCHILDREN -> переменная является узлом, иначе простая переменная), // ANodeProps - свойства родителькой переменной, // AProps - свойства переменной // Выход: AChildHandle - хэндл дочерней формы, // AWidthChild - ширина дочерней формы, // AHeightChild - высота дочерней формы, // Result - True -> форма конфигурации включена, False -> не включена // P.S. 1) На сервере форма отображается с размерами AWidthChild, AHeightChild // 2) Связь между формами через сообщения (см. WM_CHANGENODEMESS_XXX или WM_CHANGEITEMMESS_XXX) // передаваемые окну AChildHandle(обязательно SendMessage) function ChangeChildItem(AParentHandle: THandle; AItem: ILcsItem; AItemName: PChar; AFlag: DWORD; ANodeProps, AProps: PItemProperties; out AChildHandle: THandle; out AWidthChild, AHeightChild: integer): boolean; stdcall; // Добавление задачи (чтение синхронное/асинхронное, запись синхронная/асинхронная) // Вход: ATaskDef - задача // Выход: Result - S_OK->успешное добавление function AddTask(ATaskDef: TTaskDef): HResult; stdcall; // Выполнение ранее добавленых задач // Вход: APriority - приоритет выполнения function RunTasks(APriority: TPriority): HResult; stdcall; // Загрузка параметра конфигурации // Вход: AParamName - имя параметра, // AParamValue - значение параметра function LoadConfig(AParamName, AParamValue: ShortString): boolean; stdcall; // Очистить операции связанные с переменной AItem // Вход: AItem - переменная procedure PurgeAction(AItem: ILcsItem); stdcall; // Получение строки - значение данного свойства // Вход: APropID-идентификатор пользовательского свойства, // AValue-значение свойства // Выход: AStr - строка procedure GetPropStr(APropID: DWORD; AValue: OleVariant; out AStr: ShortString) stdcall; // Сброс состояния устройства связанного с задачей ATaskDef // Вход: ATaskDef - задача function ResetDeviceState(ATaskDef: TTaskDef): HResult; stdcall; // Очистить все текущие операции procedure PurgeActions; stdcall; // Установка режима вывода отладочных сообщений // Вход: AValue - True->вывод отладочных сообщений, False->не выводить procedure SetDebugMode(AValue: boolean) stdcall; // Получение времени сброса (watchdog) // Вход: ANodeProps - свойства узла, // AProps - свойства переменной // Выход: ATimeout - таймаут (мс) function GetWatchdogTimeout(ANodeProps, AProps: PItemProperties; out ATimeout: integer): boolean; stdcall; end; //----------------------------------------------------------------- // Интерфейс предоставляющий набор функций OPC сервера для драйвера // (реализован на OPC сервере) ILcsOPCServer = interface ['{81ED8EB3-BC76-443E-8722-0B004B49C4EF}'] // Сохранить параметр конфигурации // Вход: AParamName - имя параметра, // AParamValue - значение параметра function SaveConfig(AParamName, AParamValue: string): boolean; stdcall; // Вывод сообщения в лог // Вход: AMess - сообщение, // AWiteTime - True->записывать время, False->не записывать время procedure WriteToLog(AMess: PChar; AWriteTime: boolean); stdcall; // Отладочное сообщение // Вход: AName - имя отладочного параметра, // AValue - значение параметра procedure DebugValue(AName: PChar; AValue: PChar); stdcall; // Сброс watchdog таймера для транзакции // Вход: ATransactID - идентификатор транзакции procedure ResetWatchdogTimer(ATransactID: Cardinal); stdcall; // Присвоение значения переменной с данным набором свойств // Вход: AProps-набор свойств, // AItemState-состояние переменной function SetItemValue(AProps: TItemProperties; AItemState: OPCITEMSTATE): HResult; stdcall; end; //----------------------------------------------------------------- // Интерфейс предоставляющий набор функций OPC сервера для доступа // к переменной (реализован на OPC сервере) ILcsItem = interface ['{F2B0EFCD-411F-4E2A-B63D-46A1BBE1C921}'] // Добавление дочерней переменной // Вход: AItemAttrib - атрибуты(описание) переменной // AFlag - 0бит(OPC_BROWSE_HASCHILDREN) =1 -> узел, // 1бит(OPC_BROWSE_ISITEM) =1 -> переменная, // AAccessChange - права на изменение переменной (узла), // AProps - свойства переменной // ALcsDriver - интерфейс доступа к драйверу function AddChildItem(AItemAttrib: TItemAttributes; AFlag: DWORD; AAccessChange: TAccessChangeItem; AProps: PItemProperties; ALcsDriver: ILcsDriver): HResult; stdcall; // Завершение чтения значения переменной (при асинхронном чтении) // Вход: ATransactID-идентификатор транзакции, // AResult-результат выполнения операции // P.S. Значение передается через ATaskDef.ptrItemState передаваемое через // функцию ILcsDriver.AddTask procedure OnReadComplete(ATransactID: Cardinal; AResult: HResult); stdcall; // Завершение записи значения переменной (при асинхронной записи) // Вход: ATransactID-идентификатор транзакции, // AItemState-состояние(в т.ч. значение) переменной, // AResult-результат выполнения операции procedure OnWriteComplete(ATransactID: Cardinal; AResult: HResult); stdcall; // Изменение параметров переменной // Вход: AItemAttrib - атрибуты(описание) переменной, // AProps - свойства переменной // Выход: Result - результат операции function ChangeItem(AItemAttrib: TItemAttributes; AProps: PItemProperties): HResult; stdcall; // Передача кол-ва запросов к устройству // Вход: ASuccess - кол-во успешных запросов, // AFail - кол-во не успешных запросов, // ANewQuery - True->новый запрос, False->нет // P.S. Если ANewQuery = True, то для всех групп сбрасывается блокировка увеличения счетчика. // Если ANewQuery = False, то счетчик увеличивается только один раз и затем становиться на блокировку. // В простейшем случае ANewQuery всегда True. procedure OnCountQuery(ASuccess, AFail: integer; ANewQuery: boolean); stdcall; end; // тип результата выполнения операции TResultAction = ( rwSuccess, // успешная операция rwErrorInit, // ошибка инициализации порта rwBusy, // порт занят другим драйвером устройства rwFailed // ошибка при записи ); // Номер порта TComPortNum = ( pnCOM1, pnCOM2, pnCOM3, pnCOM4, pnCOM5, pnCOM6, pnCOM7, pnCOM8, pnCOM9, pnCOM10, pnCOM11, pnCOM12, pnCOM13, pnCOM14, pnCOM15, pnCOM16 ); ILcsReceiveData = interface; //----------------------------------------------------------------- // Интефейс для доступа к COM портам (реализован на OPC сервере) ILcsComPort = interface ['{740C49CF-02A2-4427-B343-2A76B945E9D9}'] // Запись данных в порт (асинхронная операция) // Вход: AComPortNumber-номер СOM порта, // AData-указатель на данные, // ACount-кол-во байтов данных, // AReceiveData-интерфейс для получения данных // Выход: Result - rwSuccess->успешная запись, rwFailed->ошибка при записи, // rwErrorInit->ошибка инициализации порта, rwBusy->порт занят // P.S. Ответ возвращается через интерфейс IReceiveData function Write(AComPortNum: TComPortNum; const AData: Pointer; const ACount: Cardinal; AReceiveData: ILcsReceiveData): TResultAction; stdcall; // Занять СОМ порт (используется для разграничения доступа к одному СОМ порту нескольких драйверов устройств) // Вход: AComPortNum - СОМ порт // AReceiveData - интерфейс для получения данных // Выход: Result - True->удалось занять порт, False->не удалось занять СОМ порт // P.S. В простейшем случае(когда используется только один драйвер имеющий доступ // к СОМ порту) можно использовать только ILcsComPort.Write без функций // ILcsComPort.OccupyPort и ILcsComPort.ReleasePort function OccupyPort(AComPortNum: TComPortNum; AReceiveData: ILcsReceiveData): boolean; stdcall; // Освободить СОМ порт (используется для разграничения доступа к одному СОМ порту нескольких драйверов устройств) // Вход: AComPortNum - СОМ порт // AReceiveData - объект для получения данных // Выход: Result - True->удалось освободить порт, False->ошибка при освобождении СОМ порта // P.S. В простейшем случае(когда используется только один драйвер имеющий доступ // к СОМ порту) можно использовать только ILcsComPort.Write без функций // ILcsComPort.OccupyPort и ILcsComPort.ReleasePort function ReleasePort(AComPortNum: TComPortNum; AReceiveData: ILcsReceiveData): boolean; stdcall; end; //----------------------------------------------------------------- // Интерфейс для получения данных (реализуется в DLL) ILcsReceiveData = interface ['{FACC000A-9C12-46B9-A91B-254F02BA51F6}'] // Получение данных от СОМ порта // Вход: AComPort-СОМ порт, // ADataPtr-данные, // ADataSize-размер данных(байт) procedure OnReceiveData(AComPortNum: TComPortNum; ADataPtr: Pointer; ADataSize: Integer); stdcall; // Порт освободился // Вход: AComPort-СОМ порт procedure OnReleasePort(AComPortNum: TComPortNum); stdcall; end; implementation end.