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

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

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

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


  //=========================================
  // Модель блока, включающего сервер
  //=========================================
  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; // Имя канала

      int ConnId; // Идентификатор соединения

      // Переменные состояния блока-передатчика
       Connected;   // Соединение установлено
       DataWaiting; // Передача данных отложена

      // Функции класса
      void Connect(void);    // Установить соединение
      void Disconnect(void); // Разорвать соединение

      void SendValue(double value); // Передать число в канал
       ReceiveValue( *rcv, // Реакция на
                        double *pOut);            // пришедшие данные

      int Setup(char *title);    // Функция настройки блока
      void SaveText(void);       // Сохранить параметры
      void LoadText(char *text); // Загрузить параметры

      // Конструктор класса
      TNetSendRcvData(int mode)
        { ConnId=-1; // Нет соединения
          Connected=DataWaiting=FALSE;
          ChannelName=NULL;
          Mode=mode; // Режим передается в параметре конструктора
        };
      // Деструктор класса
      ~TNetSendRcvData()
        { Disconnect(); // Разорвать соединение
          (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);
  }
  //=========================================

  // Разорвать соединение
  void TNetSendRcvData::Disconnect(void)
  { if(ConnId!=-1) // Соединение было создано
      (ConnId); // Разорвать
    // Сбрасываем переменные состояния
    ConnId=-1;       // Соединения больше нет
    Connected=FALSE; // Связи тоже больше нет
  }
  //=========================================

  // Передать данные
  void TNetSendRcvData::SendValue(double value)
  {
    if(!Connected) // Нет связи с сервером
      { // Взводим флаг наличия данных, ожидающих передачи
        DataWaiting=TRUE;
        return;
      }

    // Связь есть – передаем всем блокам канала
    (ConnId, // Соединение
                        |, // Флаги
                        0,NULL, // Не передаем целое число и строку
                        &value, // Указатель на данные
                        sizeof(value)); // Размер данных
    // Сбрасываем флаг ожидания – мы только что передали данные
    DataWaiting=FALSE;
  }
  //=========================================

  // Прием данных
   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::SaveText(void)
  {  ini; // Вспомогательный объект
    // Создаем вспомогательный объект
    ini=(TRUE);
    // Создаем в объекте секцию "[General]"
    (ini,,0,"General");
    // Записываем в эту секцию имя канала
    (ini,"Channel",ChannelName);
    // Сохраняем текст, сформированный объектом, как параметры блока
    (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);
      }
    // Удаляем вспомогательный объект
    (ini);

    // Поскольку имя канала могло измениться, соединяемся с
    // сервером заново
    Disconnect(); // Разрываем старое соединение
    Connect();    // Создаем новое
  }
  //=========================================

  // Настройка параметров
  // 
  // 
  // 
  int TNetSendRcvData::Setup(char *title)
  { char *NewName;

    // Запрос строки у пользователя
    NewName=(
              title,         // Заголовок окна
              "Имя канала:", // Текст перед полем
              ChannelName,   // Исходное значение
              200);          // Ширина поля

    if(NewName==NULL) // Нажата кнопка "Отмена"
      return 0;

    if(ChannelName!=NULL && strcmp(NewName,ChannelName)==0)
      { // Имя канала не изменилось
        (NewName); // Освобождаем вовращенную строку
        return 0;
      }

    // Освобождаем старое имя канала
    (ChannelName);
    // Запоминаем новое
    ChannelName=NewName;
    // Имя канала изменилось – устанавливаем связь заново
    Disconnect();
    Connect();
    return 1; // Параметры блока изменены
  }
  //=========================================

  //=========================================
  // Блок-передатчик
  //=========================================
  extern "C" __declspec(dllexport)
    int  NetSend(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)))
  #define x (*((double *)(pStart+2*RDS_VSZ_S)))

    switch(CallMode)
      { // Инициализация
        case :
          // Создаем объект класса TNetSendRcvData с
          // Mode==NETSRMODE_SENDER (передатчик)
          BlockData->BlockData=new TNetSendRcvData(NETSRMODE_SENDER);
          break;

        // Очистка
        case :
          delete data;
          break;

        // Проверка типов переменных
        case :
          return strcmp((char*)ExtParam,"{SSD}")?
            :;

        // Связь с сервером установлена
        case :
          // Взводим флаг наличия связи
          data->Connected=TRUE;
          // Если были данные, ожидающие отправки,
          // посылаем значение входа блока
          if(data->DataWaiting)
            data->SendValue(x);
          break;

        // Связь с сервером разорвана
        case :
          // Сбрасываем флаг наличия связи
          data->Connected=FALSE;
          break;

        // Запуск расчета
        case :
          // Если это – первый запуск после сброса,
          // передаем значение входа
          if((()ExtParam)->FirstStart)
            data->SendValue(x);
          break;

        // Такт расчета
        case :
          data->SendValue(x); // Передаем значение входа
          break;

        // Вызов настройки
        // 
        // 
        // 
        case :
          return data->Setup("Передача double");

       // Сохранение параметров в текстовом виде
       case :
          data->SaveText();
          break;

       // Загрузка параметров в текстовом виде
       case :
          data->LoadText((char*)ExtParam);
          break;
      }
    return ;
  // Отмена макроопределений
  #undef x
  #undef Ready
  #undef Start
  #undef pStart
  }
  //=========================================

  //=========================================
  // Блок-приемник
  //=========================================
  extern "C" __declspec(dllexport)
    int  NetReceive(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)))
  #define y (*((double *)(pStart+2*RDS_VSZ_S)))

    switch(CallMode)
      { // Инициализация
        case :
          // Создаем объект класса TNetSendRcvData с
          // Mode==NETSRMODE_RECEIVER (приемник)
          BlockData->BlockData=
            new TNetSendRcvData(NETSRMODE_RECEIVER);
          break;

        // Очистка
        case :
          delete data;
          break;

        // Проверка типов переменных
        case :
          return strcmp((char*)ExtParam,"{SSD}")?
            :;

        // По сети получены данные
        case :
          if(data->ReceiveValue((*)ExtParam,&y))
            Ready=1; // Если данные верны, взводим флаг готовности
                     // для передачи выхода по связям
          break;

        // Вызов настройки
        // 
        // 
        // 
        case :
          return data->Setup("Прием double");

       // Сохранение параметров в текстовом виде
       case :
          data->SaveText();
          break;

       // Загрузка параметров в текстовом виде
       case :
          data->LoadText((char*)ExtParam);
          break;
      }
    return ;
  // Отмена макроопределений
  #undef y
  #undef Ready
  #undef Start
  #undef pStart
  }
  //=========================================


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