Навигация:
<< >> Оглавление Указатель
Текст С++

Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, изменяющих собственную структуру переменных. Библиотека содержит три модели:

Изменения относительно предыдущих версий моделей выделены цветом.

  // Программное изменение структуры переменных
  #include <windows.h>
  #include <RdsDef.h>
  // Подготовка описаний сервисных функций
  
  #include <RdsFunc.h>

  // Глобальная переменная для значения ошибки
  double ;

  //==========  ==========
  int WINAPI ( /*hinst*/,
                           unsigned long reason,
                           void* /*lpReserved*/)
  { if(reason==DLL_PROCESS_ATTACH) // Загрузка DLL
      { // Получение доступа к функциям RDS
        if(!GetInterfaceFunctions())
           // Сообщение: старая версия RDS
        else
          rdsGetHugeDouble(&);
      }
    return 1;
  }
  //========= Конец главной функции =========

  //================================================================================
  // Блок, автоматически изменяющий свою структуру переменных при ее недопустимости
  //================================================================================

// Создать структуру переменных из двух входов x1,x2 и выхода y ( Block) { // Строка описания структуры переменных static char str[]= "struct\nbegin\n" "signal name \"Start\" in run default 0\n" "signal name \"Ready\" out default 0\n" "double name \"x1\" in menu run default 0\n" "double name \"x2\" in menu run default 0\n" "double name \"y\" out menu default 0\n" "end"; dv; // Вспомогательный объект ok; // Создаем объект для работы со структурой переменных dv=(); // Создаем в объекте набор переменных по строке описания ok=(dv,str); if(ok) // Переписываем структуру переменных из объекта в блок ok=(dv,Block,NULL); // Удаляем вспомогательный объект (dv); // Возвращаем успешность операции return ok; } //=========================================
// Модель блока вычитания extern "C" __declspec(dllexport) int TestSub(int CallMode, BlockData, ExtParam) { // #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define x1 (*((double *)(pStart+2*RDS_VSZ_S))) #define x2 (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define y (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D)))
ok;
switch(CallMode) {
// Инициализация case : BlockData->Tag=0; // Сброс флага break;
// Проверка типа переменных case : if(strcmp((char*)ExtParam,"{SSDDD}")==0) return ; // Тип переменных правильный // Тип переменных неправильный if(BlockData->Tag) // Флаг взведен – программное изменение return ; // Ошибка // Модель вызвана не из-за программного изменения // структуры переменных // Взводим флаг на время программного изменения структуры BlockData->Tag=1; // Пытаемся изменить структуру переменных блока ok=(BlockData->Block); // Сбрасываем флаг обратно BlockData->Tag=0; // Возвращаем результат попытки изменения return ok?:;
// Выполнение такта расчета case : // Вычисление значения выхода if(x1== || x2==) y=; else y=x1-x2; break; } return ; // Отмена макроопределений #undef y #undef x2 #undef x1 #undef Ready #undef Start #undef pStart } //========================================= //================================================================================ // Модель блока, включающего сервер (нужна только для обеспечения работы примера) //================================================================================ extern "C" __declspec(dllexport) int Server(int CallMode, BlockData, ExtParam) { int *pConnId; switch(CallMode) { // Инициализация case : // Отводим место под личную область данных размером в int BlockData->BlockData=pConnId=new int; // Запускаем сервер и соединяемся с ним *pConnId=(-1, // Порт по умолчанию "ProgrammersGuide.Server", // Канал FALSE); // Не принимаем данные break; // Очистка case : // Личная область данных – целое число pConnId=(int*)(BlockData->BlockData); // Разрываем связь с сервером (он завершится сам) (*pConnId); // Удаляем личную область delete pConnId; break; } return ; } //========================================= //================================================================================ // Модель блока, передающего по сети все свои переменные, дающего пользователю // менять структуру переменных из функции настройки //================================================================================ // Личная область данных блоков приема и передачи по сети class TNetSendRcvData { public: int Mode; // Режим данного блока: прием или передача #define NETSRMODE_SENDER 0 // Передатчик #define NETSRMODE_RECEIVER 1 // Приемник char *ChannelName; // Имя канала LimitSpeed; // Задан минимальный интервал передачи Delay; // Минимальный интервал в мс
StructInOut; // Этот блок передает или принимает структуру
int ConnId; // Идентификатор соединения // Переменные состояния блока-передатчика Connected; // Соединение установлено DataWaiting; // Передача данных отложена Timer;// Таймер для отсчета интервала WaitingForTimer;// Таймер запущен - ждем LastSendTime; // Время последней отправки // Функции класса void Connect(void); // Установить соединение void Disconnect(void); // Разорвать соединение void SendValue(double value); // Передать число в канал ReceiveValue( *rcv, // Реакция на double *pOut); // пришедшие данные void SendArray(void *input); // Передать массив в канал ReceiveArray( *rcv, // Реакция на void *output); // пришедшие данные
void SendStruct( Block); // Передать структуру ReceiveStruct( *rcv, // Реакция на Block); // пришедшую структуру
void CreateTimer(void); // Создать таймер void DeleteTimer(void); // Удалить таймер CheckSendTimer(void); // Проверить, можно ли передавать, // и запустить таймер, если нельзя int Setup(char *title); // Функция настройки блока void SaveText(void); // Сохранить параметры void LoadText(char *text);// Загрузить параметры // Конструктор класса TNetSendRcvData(int mode) { ConnId=-1; // Нет соединения Connected=DataWaiting=FALSE; LimitSpeed=WaitingForTimer=FALSE;Timer=NULL;Delay=100; ChannelName=NULL; StructInOut=FALSE; Mode=mode; // Режим передается в параметре конструктора }; // Деструктор класса ~TNetSendRcvData() { Disconnect(); // Разорвать соединение DeleteTimer(); // Удалить таймер (ChannelName); // Освободить строку имени канала }; }; //========================================= // Установка соединения void TNetSendRcvData::Connect(void) { char *PrefixedName; // Полное имя канала // Если имя канала пустое, соединение невозможно if(ChannelName==NULL || (*ChannelName)==0) return; // Добавляем префикс к имени канала PrefixedName=("ProgrammersGuide.",ChannelName,FALSE); // Устанавливаем соединение с сервером ConnId=(NULL, // Сервер по умолчанию -1, // Порт по умолчанию PrefixedName,// Имя канала с префиксом Mode==NETSRMODE_RECEIVER); // Прием данных // Освобождаем динамически отведенную строку (PrefixedName); // Создаем или уничтожаем таймер CreateTimer(); } //========================================= // Разорвать соединение void TNetSendRcvData::Disconnect(void) { if(ConnId!=-1) // Соединение было создано (ConnId); // Разорвать // Сбрасываем переменные состояния ConnId=-1; // Соединения больше нет Connected=FALSE; // Связи тоже больше нет } //========================================= // Создать таймер void TNetSendRcvData::CreateTimer(void) { if(Mode!=NETSRMODE_SENDER || // Приемнику таймер не нужен (!LimitSpeed) ) // Интервал передачи не ограничивается { DeleteTimer(); // Удаляем таймер, если он создан return; } if(Timer) // Таймер уже создан return; // Создаем таймер Timer=( NULL, // Создается новый таймер 0, // Задержка задается при запуске | , // Однократный FALSE); // Создается остановленным } //========================================= // Удалить таймер void TNetSendRcvData::DeleteTimer(void) { if(Timer) // Таймер есть { (Timer); Timer=NULL; } WaitingForTimer=FALSE; // Сбрасываем флаг ожидания } //========================================= // Проверить, можно ли передать данные немедленно, и запустить // таймер, если нельзя TNetSendRcvData::CheckSendTimer(void) { interval; if(!Connected) // Нет связи с сервером return TRUE; // Разрешаем отправку, чтобы попытка отправки // была зафиксирована в функции SendValue if(!LimitSpeed) // Интервал не ограничивается return TRUE; if(WaitingForTimer) // Уже запустили таймер и ждем срабатывания return FALSE; // Интервал передачи ограничен, таймер сейчас выключен interval=GetTickCount()-LastSendTime; // Время с прошлой отправки if(interval>=Delay) // Прошло много времени – можно передавать return TRUE; // С прошлой отправки прошло менее Delay мс // Нужно подождать (Delay-interval) WaitingForTimer=TRUE; // Взводим флаг ожидания таймера rdsRestartBlockTimer(Timer,Delay-interval); // Запускаем таймер return FALSE; // Передавать сейчас нельзя – ждем таймера } //========================================= // Передать данные void TNetSendRcvData::SendValue(double value) { if(!Connected) // Нет связи с сервером { // Взводим флаг наличия данных, ожидающих передачи DataWaiting=TRUE; return; } // Связь есть – передаем всем блокам канала (ConnId, // Соединение |, // Флаги 0,NULL, // Не передаем целое число и строку &value, // Указатель на данные sizeof(value)); // Размер данных // Сбрасываем флаг ожидания – мы только что передали данные DataWaiting=FALSE; // Запоминаем время последней передачи LastSendTime=GetTickCount(); } //========================================= // Прием данных TNetSendRcvData::ReceiveValue( *rcv, // Указатель на структуру с данными double *pOut) // Указатель на выход блока { if(rcv==NULL || pOut==NULL) // Нет одного из указателей return FALSE; // Проверяем, есть ли среди принятых данных двоичные, // и равен ли размер этих данных размеру double if(rcv->Buffer==NULL || rcv->BufferSize!=sizeof(double)) return FALSE; // Нет данных или не совпал размер // Копируем принятое числов pOut memcpy(pOut,rcv->Buffer,sizeof(double)); return TRUE; // Приняты правильные данные } //========================================= // Передать массив void TNetSendRcvData::SendArray(void *input) { int N; if(!Connected) // Нет связи с сервером { // Взводим флаг наличия данных, ожидающих передачи DataWaiting=TRUE; return; } // Связь есть – определяем размер массива input N=(input)? ((input)*(input)):0; if(N==0) // Массив пуст – передавать нечего return; // Передаем N чисел double всем блокам канала ( ConnId, // Соединение |, // Флаги N, // Целое число – размер массива NULL, // Строка не передается (input), // Начало данных массива N*sizeof(double)); // Размер массива в байтах // Сбрасываем флаг ожидания – мы только что передали данные DataWaiting=FALSE; // Запоминаем время передачи LastSendTime=GetTickCount(); } //========================================= // Прием массива TNetSendRcvData::ReceiveArray( *rcv, // Указатель на структуру с данными void *output) // Указатель на выход блока (массив) { int N; if(rcv==NULL||output==NULL) // Нет одного из указателей return FALSE; // Проверяем, есть ли среди принятых данных двоичные, // и кратен ли размер блока данных размеру double if(rcv->Buffer==NULL || // Нет буфера с данными rcv->BufferSize%sizeof(double)!=0) // Размер не кратен 8 return FALSE; // Вычисляем число элементов в принятом массиве N=rcv->BufferSize/sizeof(double); // Вычисленное число элементов должно совпасть с переданным if(N!=rcv->Id) return FALSE; // Принято N чисел double – отводим массив под них if(!(output,1,N,FALSE,NULL)) return FALSE; // Копируем принятые данные в отведенный массив выхода memcpy((output),rcv->Buffer,rcv->BufferSize); return TRUE; } //=========================================
// Передать структуру переменных блока void TNetSendRcvData::SendStruct( Block) { void *buf; int len; // Является ли данный блок передатчиком? if(Mode!=NETSRMODE_SENDER) return; // Не является – это ошибка if(!Connected) // Нет связи с сервером { // Взводим флаг наличия данных, ожидающих передачи DataWaiting=TRUE; return; } // Связь с сервером есть // Формируем буфер со всеми переменными блока buf=(Block,-1,TRUE,&len); if(buf==NULL) return; // Не удалось сформировать буфер // Передаем по сети сформированный буфер (ConnId, |, 0,NULL, buf,len); // Освобождаем буфер – он уже передан (buf); // Сбрасываем флаг ожидания – мы только что передали данные DataWaiting=FALSE; // Запоминаем время последней передачи LastSendTime=GetTickCount(); } //=========================================
// Принять структуру переменных TNetSendRcvData::ReceiveStruct( *rcv, Block) { // Проверяем первый параметр и является ли блок приемником if(rcv==NULL || Mode!=NETSRMODE_RECEIVER) return FALSE; // Есть ли среди принятых данных двоичные? if(rcv->Buffer==NULL) return FALSE; // Пытаемся записать принятые данные в структуру переменных блока return (Block,-1,rcv->Buffer,rcv->BufferSize); } //=========================================
// Сохранение параметров блока void TNetSendRcvData::SaveText(void) { ini; // Вспомогательный объект // Создаем вспомогательный объект ini=(TRUE); // Создаем в объекте секцию "[General]" (ini,,0,"General"); // Записываем в эту секцию имя канала (ini,"Channel",ChannelName);
// Записываем режим для приемопередатчика структур if(StructInOut) (ini,"Mode",Mode);
if(Mode==NETSRMODE_SENDER) // Передатчик { // Создаем новую секцию (ini,,0,"Timer"); // Записываем параметры (ini,"On",LimitSpeed); (ini,"Delay",Delay); } // Сохраняем текст, сформированный объектом, как параметры блока (ini,); // Удаляем вспомогательный объект (ini); } //========================================= // Загрузка параметров блока void TNetSendRcvData::LoadText(char *text) { ini; // Вспомогательный объект char *str; // Создаем вспомогательный объект ini=(TRUE); // Записываем в объект полученный текст с параметрами блока (ini,,0,text); // Начинаем чтение секции "[General]", если она есть if((ini,"General")) // Секция есть { // Освобождаем старое имя канала (ChannelName); ChannelName=NULL; // Получаем у объекта указатель на строку с именем str=(ini,"Channel","",NULL); // Если такая строка есть в тексте, копируем ее в ChannelName if(str) ChannelName=(str);
// Считываем режим для приемопередатчика структур if(StructInOut) Mode=(ini,"Mode",Mode);
} if(Mode==NETSRMODE_SENDER && // Передатчик (ini,"Timer")) // Есть секция "[Timer]" { LimitSpeed=(ini,"On",LimitSpeed)!=0; Delay=(ini,"Delay",Delay); } // Удаляем вспомогательный объект (ini); // Поскольку имя канала и режим работы могли измениться, // соединяемся с сервером заново Disconnect(); // Разрываем старое соединение Connect(); // Создаем новое } //=========================================
// Функция обратного вызова окна настройки блока (прототип) void TNetSendRcvData_Setup_Check( window, // Объект-окно data); // Описание события //=========================================
// Функция настройки блока // // // int TNetSendRcvData::Setup(char *title) { win; // Вспомогательный объект-окно ok; // Пользователь нажал "OK"
char *str;
// Создаем окно win=(FALSE,-1,-1,title);
if(StructInOut) // Блок работает со структурами { // Выпадающий список "прием/передача" (win,0,10,, "Действие:",150); (win,10,, "Передача данных\nПрием данных"); (win,10,, (Mode==NETSRMODE_RECEIVER)?1:0); // Получение строки описания переменных блока str=( (NULL,-1,NULL),TRUE,0,NULL); // Установка этой строки как невидимого поля ввода 1000 (win,0,1000,,NULL,0); (win,1000,,str); (str); // Строка больше не нужна // Кнопка редактирования переменных (win,0,11, | , "Переменные:",150); (win,11,,"Изменить..."); }
// Поле ввода имени канала (win,0,1,, "Имя канала:",200); (win,1,,ChannelName); if(Mode==NETSRMODE_SENDER || StructInOut) { // Для передатчика – ввод интервала (win,0,2, | , "Интервал передачи, мс:",80); (win,2,,Delay); (win,2,,LimitSpeed); }
// Открытие окна ok=(win,TNetSendRcvData_Setup_Check);
if(ok) { // Пользователь нажал OK – запись параметров в блок char *NewName=(win,1,); if(ChannelName==NULL || strcmp(NewName,ChannelName)!=0) { // Имя канала изменилось – запоминаем новое (ChannelName); ChannelName=(NewName); } // Флаг ограничения интервала и сам интервал LimitSpeed=(win,2,)!=0; Delay=(win,2,);
if(StructInOut) // Блок работает со структурами { dv; // Объект для работы с переменными flags,mask; vdescr; // Прием или передача Mode=(win,10,)? NETSRMODE_RECEIVER:NETSRMODE_SENDER; // Чтение строки описания переменных из невидимого поля str=(win,1000,); // Создаем объект для работы с переменными dv=(); // Создаем структуру переменных по строке описания if((dv,str)) { // Установка флагов переменных – входы или выходы if(Mode==NETSRMODE_SENDER) // Передатчик (входы) flags=|| |; else // Приемник (выходы) flags=|| ; // Маска изменяемых флагов mask=|| || ; // Получение числа переменных в объекте dv vdescr.servSize=sizeof(vdescr); (dv,-1,&vdescr); // Установка флагов начиная со второй переменной for(int i=2;i<vdescr.StructFields;i++) (dv,i,flags,mask); // Запись переменных из объекта в блок if(!(dv,NULL,NULL)) ("Невозможно установить переменные " "блока","Ошибка", | ); } // Удаление вспомогательного объекта (dv); }
Disconnect(); Connect(); } // Уничтожение окна (win); // Возвращаемое значение return ok?:; } //=========================================
// Функция обратного вызова окна настройки // // // void TNetSendRcvData_Setup_Check( window, data) { dv=NULL; char *descr; vdescr; sender; // Реагируем на событие, из-за которого вызвана функция switch(data->Event) { case : // Нажатие кнопки if(data->CtrlId!=11) // Это не кнопка "Изменить" break; // Создаем объект для манипуляций с переменными dv=(); // Считываем текст описания переменных из поля 1000 descr=(window,1000,); // Заполняем объект dv описанием переменных descr if(!(dv,descr)) break; // Удаляем из объекта две первых переменных (dv,0); // Start (dv,0); // Ready // Открываем окно редактора переменных if(!(dv,FALSE,| |,-1, "Переменные")) break; // Пользователь нажал кнопку "Отмена" // Добавляем сигналы Start и Ready // Ready (dv,0,"Ready",,NULL, || ,0,"0"); // Start (dv,0,"Start",,NULL, || |,0,"0"); // Формируем текст описания получившихся переменных vdescr.servSize=sizeof(vdescr); if(!(dv,-1,&vdescr)) break; descr=(vdescr.Var,TRUE,0,NULL); if(descr) { // Записываем новый текст в невидимое поле (win,1000,,descr); (descr); } break; case : // Изменилось поле // Считываем режим работы блока из выпадающего списка sender=(window,10,)==0; // sender истинно, если блок - передатчик // Ограничение интервала разрешено только для передатчика (window,2,,sender); break; } // Если в процессе работы функции был создан объект, удаляем его if(dv) (dv); } //=========================================
// Модель блока приема/передачи структуры extern "C" __declspec(dllexport) int NetSendRcvStruct(int CallMode, BlockData, ExtParam) { TNetSendRcvData *data=(TNetSendRcvData*)(BlockData->BlockData); // для первых двух переменных блока #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) switch(CallMode) { // Инициализация case : BlockData->BlockData=data= new TNetSendRcvData(NETSRMODE_SENDER); // Взводим флаг работы со структурами data->StructInOut=TRUE; break; // Очистка case : delete data; break; // Установлено соединение с сервером case : data->Connected=TRUE; // Если были данные, ожидающие передачи – передаем их if(data->DataWaiting) data->SendStruct(BlockData->Block); break; // Соединение разорвано case : data->Connected=FALSE; break; // Запуск расчета case : // При первом запуске передаем данные if((()ExtParam)->FirstStart) data->SendStruct(BlockData->Block); break; // Срабатывание таймера case : data->WaitingForTimer=FALSE; // Передаем данные data->SendStruct(BlockData->Block); break; // Такт расчета case : if(data->CheckSendTimer()) data->SendStruct(BlockData->Block); break; // Вызов функции настройки // // // case : return data->Setup("Прием/передача структуры"); // Сохранение параметров case : data->SaveText(); break; // Загрузка параметров case : data->LoadText((char*)ExtParam); break; // По сети получены данные case : // Если данные совместимы с блоком – принимаем и // взводим сигнал готовности Ready=data->ReceiveStruct((*)ExtParam, BlockData->Block)?1:0; // Сбрасываем сигнал запуска Start=0; break; } return ; // Отмена макроопределений #undef Ready #undef Start #undef pStart } //=========================================


<< >> Оглавление Указатель