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

1.4. Процедуры работы с БД ElectroCNF

2. Стандартные компоненты (*.OCX, *.DLL)

2.3. Electro.DLL – набор базовых функций

Программа Electro.dll содержит набор функций и процессов (threads), обеспечивающих доступ и поддержку целостности БД ElectroCNF

  • проверка структуры БД ElectroCNF, Electro - VerifyDB();
  • идентификация пользователя -GetRights(),AddUser(),CloseUser(),GetUserInfo();
  • ведение журнала работы пользователей – Log();
  • работа с базой данных - ODBC_Open(), ODBC_Close(), ODBC_Execute(), ODBC_GetData(), ODBC_Fetch(), ODBC_PutLongData(), ODBC_GetLongData(), ODBC_GetError(),ODBC_Add2Trend(),ODBC_FlushTrend();
  • работа с метками времени - SystemTime2Second(), Second2SystemTime(), ReduceSecond(), Second2Ind();
  • работа с драйвером устройства - DLL_Open(), DLL_Close(), DLL_Control(), DLL_CheckMsg(), DLL_GetError();
  • мультиязыковая поддержка – ML();
  • визуальная компонента навигации БД – SelectObj(), ElSetEvent().

Перечисленные выше функции могут быть подключены к проектируемому прикладному модулю через библиотеку Electro.LIB

Описание функций Electro.DLL (приведен синтаксис для языка MS Visual C).

2.3.1. Проверка структуры БД

Функция
int __stdcall VerifyDB() ;
Выполняет следующие действия:
- проверяет наличие ODBC-источников данных “ElectroCNF” и “Electro”. При их отсутствии делается попытка создания;
- проверяет наличие таблиц и необходимых полей в каждой таблице.
Функцию следует вызывать в начале работы программы.

2.3.2. Идентификация пользователя

Функции данной группы используются в программе для интерактивной регистрации пользователя и работы с диспетчером пользователей системы Электро.

int __stdcall GetRights(char *titul, int query, int mask);

titul - текст окна запроса пароля;
query - управление запросом пароля;
mask - маска на битовый вектор прав доступа (поле Rigths таблицы TB_User).

Алгоритм:
if (query==0) {
if ( имеется_зарегистрированный_пользователь ) {
if ( (права_пользователя_соответствуют mask) или (mask==0))
return Права_текущего_пользователя;
Вывести_диалоговое_окно;
if ( имеется_зарегистрированный_пользователь ) {
return Права_текущего_пользователя;
return 0;

int __stdcall CloseUser();
Функция деактивирует текущего пользователя.

 

int __stdcall AddUser(char *name, char *shname, char *password, int rigths);
Функция создает новую учетную запись для пользователя.

2.3.3. Работа с БД

Данная группа функций является надстройкой ODBC API:

DWORD __stdcall ODBC_Open (char *dsn, int *err);
- открывает соединение с ODBC-источником данных dsn (обычно “ElectroCNF” либо “Electro”). В *err возвращается код ошибки (0 при успешном открытии). Возвращается номер открытого соединения (используется в остальных функциях в качестве параметра qb).

BOOL __stdcall ODBC_Close (DWORD qb);

  • закрывает ранее открытое соединение.

BOOL __stdcall ODBC_Execute (DWORD qb, char *sql);
- выполнение SQL- оператора.

Short __stdcall ODBC_Fetch (DWORD qb);
- получение следующей строки результата выполнения последней функции ODBC_Execute(). Возвращается значение:
0 – результат получен. Можно использовать ODBC_GetData() для извлечения элементов;
100 – данных нет.
Значение отличное от 0 и 100 – ошибка выполнения.

Short __stdcall ODBC_GetData (DWORD qb, int n, int *len, void *rez);
- получение элемента n из строки результата, полученного последней функцией ODBC_Fetch(). Элемент размещается по адресу rez. Перед вызовом функции переменной *len необходимо присвоить максимальный размер поля rez. В свою очередь, функция записывает в *len действительную длину данных.
Возвращаемое значение: <0 – ошибка.
Аргумент n нумеруется от 1. Специальные значения n используются для получения служебной информации:
n=0 : *(int*)rez присваивается количество элементов строки результата
n=-1,-2, … -i : возвращается информация об элементе i:

  • по адресу rez записывается имя элемента
  • *len присваивается тип элемента
  • возвращается размер элемента.

n=-100 : возвращается количество строк результата.

Int __stdcall ODBC_GetLongData (DWORD qb, char *sql, char *fname);
- перенос бинарных данных из таблицы БД в файл. Например
GetLongData(qb, “SELECT source FROM TB_Reports WHERE repid=5”, “C:\filename”);

Short __stdcall ODBC_PutLongData (DWORD qb, char *sql, char *fname);
- перенос данных из файла в таблицу БД. Например
PutLongData(qb, “UPDATE TB_Reports SET source=? WHERE repid=5”, “C:\filename”);

Short __stdcall ODBC_GetError (DWORD qb, int len, char *errtxt);
- получение текста ошибки

BOOL __stdcall ODBC_Add2Trend (DWORD qb, DWORD oid, DWORD tm, double val, char *flag);
- ускоренное занесение информации в таблицу Trend. Следует пользоваться именно этой функцией (а не ODBC_Execute(“INSERT … INTO Trend ..”).

BOOL __stdcall ODBC_FlushTrend (DWORD qb);
- форсирование выполнения предыдущих функций Add2Trend().

 

Для Дельфи-программистов разработана компонента Electro.pas, упрощающая работу с функциями семейства ODBC_xxx(). Для С++ имеется класс electro (ElectroDB.cpp + Electro.h)

2.3.4. Работа с метками времени

Данная группа функций облегчает работу программы с метками времени. В системе Электро используются следующие принципы:
- метка времени (mrk) – это беззнаковое 4-х-байтовое целое, секунды с 01.01.1970 00:00:00 по Гринвичу (например, библиотечная функция mrk=time(NULL) возвращает текущее время).
- измерительные параметры, имеющие период (см. описание TB_Objects.Period) снабжаются меткой, соответствующей началу периода. Например, значение месячного параметра для сентября 2003года имеет метку 01.09.2003 00:00:00.
Иногда это может вызвать недоразумения, например когда смысл месячного параметра – показание расхода энергии на КОНЕЦ месяца, на конец сентября, по сути на 01 октября.

void __stdcall Second2SystemTime(DWORD mrk, SYSTEMTIME *STm);
- преобразует метку времени mrk в структуру Win32 SYSTEMTIME (локальное время). Другими словами, данная функция позволяет получить структурированное представление даты-времени.

DWORD __stdcall SystemTime2Second(SYSTEMTIME *STm);
- преобразует содержимое структуры Win32 SYSTEMTIME (локальное время) в метку времени.

Функции Second2SystemTime() и SystemTime2Second() являются взаимообратными.

DWORD __stdcall Second2Ind(DWORD mrk, DWORD period);
- преобразует метку mrk к индексу для заданного периода period.
Индекс – это порядковый номер периода. Например, индекс суточного параметра – это порядковый номер дня.
Индекс вычисляется в контексте локального времени.

DWORD __stdcall ReduceSecond(DWORD mrk, DWORD period, int shift);
Выполняется в два этапа:

  • Метка mrk приводится к началу соответствующего локального периода. Например, метка времени, соответствующая локальному времени 08:59:00 17MAY2005, будет приведена к значению, соответствующему локальному времени 00:00:00 17MAY2005.
  • после этого метка сдвигается вперед/назад на заданное значение периодов (shift).

Для значения периода указанного в секундах (period >= 10) расчет производится по упрощенному алгоритму
Результат = (mrk / period) * period + period*shift

Пример
ReduceSecond(mrk, 1, 0) вернет значение метки времени mrk, измененное к началу соответствующих локальных суток;
ReduceSecond(mrk, 1, -1) вернет метку предыдущих локальных суток.

Функции визуализации справочника БД

DWORD __stdcall SelectObj(HWND hParent, int RepObj, int EnableEdit, int Selection, char *Server);
- на окно hParent накладивается стандартный фрейм навигации по базе данных Электро. Аргументы:
RepObj: 0 – навигатор параметров; 1 – навигатор отчетов; 2 – навигатор параметров с checkbox.
EnableEdit: разрешить режим редактирования
Selection: установить фокус на указанный элемент
Server: имя сервера БД

int __stdcall ElSetEvent(int mode, void *proc, void *Self, HWND hParent);
mode=1 – указание адреса call-back процедуры для ранее созданного фрейма навигации (идентифицируемого hParent). Electro.dll инициирует вызов этой процедуры по двойному щелчку на элементе. Self используется в качестве параметра call-back процедуры. Синтаксис *proc :
typedef int (CALLBACK* proc)(void *Self, int oid, char *name, char *server);

Демонстрация использования функций – см. Дельфи-компоненту ElectroView.pas

2.3.6. Прочие функции

int __stdcall Log(int category, char *action);
Функция добавляет запись в журнал событий (см. описание ElectroCNF.TB_Log).
Используется идентификатор текущего пользователя.
Приоритет (Prior) сообщения кодируется в начале *action символом ‘@’:
Log(1, “@1Сообщение с Prior=1”);
Log(1, “Сообщение с Prior=0 (по умолчанию)”);

 

char * __stdcall ML(char *text);
Функция мультиязычной поддержки. Может быть использована в приложениях при для автоматического перевода фразы text на целевой язык. Функция проверяет наличие text в словаре (файлы LANGxxxx.INI) и возвращает указатель на новый текст.

int __stdcall ElectroXML(int action, char *fname1, char *fname2, OnEvent event, char *opt);

Для xml-документа fname1выполняется действие action. Дополнительные опции м.б. заданы в строке opt. Возникающие в процессе работы сообщения м.б. перехвачены call-back функцией event. Результат выполнения помещается в xml-документ fname2.
Определение для call-back функция event -
typedef int (__stdcall * OnEvent)(char*);

Функция ElectroXML() является базовой для оконного приложения ElectroXML.exe и консольного приложения XmlGen.exe.


ACTION

INPUT

OUTPUT

opt

0 – экспорт данных

queryàselectàdeviceàpar
задание на експорт

dataàselectàdeviceàparàv
данные

SERVER=name
FROM=tm
TO=tm
FINFO=b
FALLPAR=b

1 – экспорт конфигурации

 

Profileàelectrocnfàtable
Конфигурация системы Electro

SERVER=name

2 – замена конфигурации

Profileàelectrocnfàtable
Устанавливаемая конфигурация

Profileàelectrocnfàtable
Backup перед заменой

SERVER=name

3 – импорт данных

dataàselectàdeviceàparàv
данные

Протокол работы

SERVER=name

4 - Дамп БД (обратное к ACTION=13)

 

 

DSN=dbname
IGNORE

5 – опрос устройств

queryàselectàdeviceàpar
задание на опрос

Протокол работы

SERVER=name
FROM=tm
TO=tm
FDEBUG=b
FALLPAR=b
FSMART=b

6 – обновление данных в БД

queryàselectàdeviceàpar
задание

Протокол работы

SERVER=name

7 – удаление данных из БД

queryàselectàdeviceàpar
задание

Протокол работы

SERVER=name
FROM=tm
TO=tm

9 – генератор макетов

 

 

 

10 – новый вариант экспорта данных

 

 

 

11 – архивирование данных

 

 

 

12 – УППД-клиент

 

 

 

13 - замена БД (обратное к ACTION=4)

 

 

 

 

 

 

 

В опциях FROM, TO метка времени tm может иметь формат
ггггммддTччммсс 20040114T123000 == 2004 Январь,14 12:30:00
ггггммддTччмм 20040114T1230 == 2004 Январь,14 12:30:00
ггггммддTчч 20040114T12 == 2004 Январь,14 12:00:00
ггггммдд 20040114 == 2004 Январь,14 00:00:00
ггггмм 200401 == 2004 Январь,01 00:00:00
гггг 2004 == 2004 Январь,01 00:00:00
CURRENT время на момент выполнения действия
DAY0 начало текущих суток
DAY1, DAY2 и т.д. начало предыдущих суток
MONTH0 начало текущего месяца
MONTH1, MONTH2 .. начало предыдущих месяцев

В опции OUTPUT имя файла fname2 может содержать специальные знаки, обрабатываемые стандартной библиотечной функцией strftime(), в частности
%a Abbreviated weekday name
%A Full weekday name
%b Abbreviated month name
%B Full month name
%d Day of month as decimal number (01 – 31)
%H Hour in 24-hour format (00 – 23)
%I Hour in 12-hour format (01 – 12)
%j Day of year as decimal number (001 – 366)
%m Month as decimal number (01 – 12)
%M Minute as decimal number (00 – 59)
%S Second as decimal number (00 – 59)
%U Week of year as decimal number, with Sunday as first day of week (00 – 51)
%w Weekday as decimal number (0 – 6; Sunday is 0)
%W Week of year as decimal number, with Monday as first day of week (00 – 51)
%y Year without century, as decimal number (00 – 99)
%Y Year with century, as decimal number

Например, вызов ElectroXML(0, “Job.xml”, “Data_%Y_%m_%d.xml”, NULL,NULL); создаст выходной файл Data_2004_02_24.xml (в зависимости от текущей даты).

Также, аргументы fname1, fname2 могут указывать на специальную структуру
typedef struct {
char sign[4]; // "@@@@" - признак mem
DWORD sz; // размер bf[]
DWORD len; // фактический размер данных в bf[]
BYTE *bf; // указ-ль на бинарные данные
char *err; // текст последней ошибки
mem;
В этом случае используется «файл в памяти» (см. mem.cpp). Режим работы «файл в памяти» распознается по наличию символов "@@@@" соответственно по адресам fname1 и/или fname2 с помощью функции MemIs().
Пример.

#include “mem.h”

mem IM, OM;

MemInit(&IM); MemInit(&OM); // создание пустых обьектов mem
// имитируем формирование входного XML-документа
MemPrintf(&IM, “<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<electroxml>\n”);
MemPrintf(&IM, “<query from=\"DAY%d\" to=\"CURRENT\" finfo=\"1\" fsmart=\"1\" fdebug=\"0\">\n”, 2);
MemPrintf(&IM, “<select><device serialnumb=\"CTK3_022022\"><par memind=\"30000\"/></device></select>\n”);
MemPrintf(&IM, “</query></electroxml>”);

int rz = ElectroXML(0, (char*)&IM, (char*)&OM, NULL, NULL);

char *result = (char*)MemPtr(&OM); // ссылка на строку – вых.документ