Текущий раздел:

Описания RDS

Руководство программиста

Глава 2. Создание моделей блоков

§2.7. Настройка параметров блока

§2.7.4. Хранение настроечных параметров в переменных блока

Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока, вычисляющего значение выхода «y» по формуле «y=K×x+C» и хранящего настроечные параметры в значениях по умолчанию входов «K» и «C»

      // Хранение настроек в значениях входов по умолчанию
      #include <windows.h>
      #include <math.h>
      #include <RdsDef.h>
      // Подготовка описаний сервисных функций
      #define RDS_SERV_FUNC_BODY GetInterfaceFunctions
      #include <RdsFunc.h>

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

      // Проверка наличия связи у входа блока
      BOOL CheckBlockInputConnection(
        RDS_BHANDLE Block,              // Идентификатор блока
        int num,                        // Номер входа
        RDS_PVARDESCRIPTION pVarDescr)  // Указатель на структуру
                // описания переменной
      { RDS_CHANDLE c;                // Идентификатор связи
        RDS_POINTDESCRIPTION PtDescr; // Структура описания точки связи

        // Заполнение служебных полей структур их размерами
        PtDescr.servSize=sizeof(PtDescr);
        pVarDescr->servSize=sizeof(RDS_VARDESCRIPTION);

        // Получение описания переменной блока по номеру
        if(rdsGetBlockVar(Block,num,pVarDescr)==NULL)
          return FALSE; // Нет такой переменной

        // Перебор всех связей, подключенных к этому блоку
        c=NULL;
        for(;;)
          { // Найти связь, следующую за c, и заполнить структуру
            // описания точки соединения PtDescr
            c=rdsGetBlockLink(Block,c,TRUE,FALSE,&PtDescr);
            if(c==NULL) // Больше нет связей
              break;
            // Найдена очередная связь – сравнение имени заданной
            // переменной с именем переменной точки этой связи
            if(strcmp(PtDescr.VarName,pVarDescr->Name)==0)
              return TRUE; // Имена совпали – есть связь, соединенная
                           // с переменной блока
          }
        // Все подключенные связи перебраны, а связь, подключенная
        // к заданной переменной так и не была найдена
        return FALSE;
      }
      //=========================================

      // Добавление поля для ввода или индикации вещественного параметра
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      BOOL AddWinEditOrDisplayDouble(
        RDS_HOBJECT window, // Идентификатор объекта-окна
        RDS_BHANDLE Block,  // Блок
        int varnum,         // Номер переменной в блоке
        int ctrlnum,        // Идентификатор поля ввода в окне
        char *title)        // Заголовок поля или NULL
      { // Структура описания переменной блока
        RDS_VARDESCRIPTION VarDescr;
        // Проверка наличия связи у переменной varnum в блоке Block
        // и заполнение структуры VarDescr описанием переменной
        BOOL conn=CheckBlockInputConnection(Block,varnum,&VarDescr);

        if(conn) // К переменной подключена связь
          { // Вспомогательные переменные
            char *caption;  // Заголовок поля
            double *cur;    // Указатель на данные переменной
            // Заголовок поля формируется из имени переменной и
            // текста "подключена связь"
            caption=rdsDynStrCat(title?title:VarDescr.Name,
                                 " (подключена связь)",
                                 FALSE);
            // Добавление поля для индикации текущего значения
            rdsFORMAddEdit(window,0,ctrlnum,RDS_FORMCTRL_DISPLAY,
                           caption,80);
            // Освобождение динамически сформированной строки
            // заголовка поля
            rdsFree(caption);
            // Получение указателя на данные переменной
            cur=(double*)rdsGetBlockVarBase(Block,varnum,NULL);
            // Проверка – переменная должна существовать и иметь тип double
            if(cur!=NULL && VarDescr.Type=='D')
              // Занесение текущего значения переменной в поле
              rdsSetObjectDouble(window,ctrlnum,RDS_FORMVAL_VALUE,*cur);
          }
        else // К переменной не подключена связь
          { // Вспомогательная переменная для значения по умолчанию
            char *defval;
            // Получение строки со значением переменной по умолчанию
            // (необходимо потом освободить при помощи rdsFree)
            defval=rdsGetBlockVarDefValueStr(Block,varnum,NULL);
            // Добавление поля для ввода параметра
            rdsFORMAddEdit(window,0,ctrlnum,RDS_FORMCTRL_EDIT,
                           title?title:VarDescr.Name,80);
            // Занесение в поле ввода значения перменной по умолчанию
            rdsSetObjectStr(window,ctrlnum,RDS_FORMVAL_VALUE,defval);
            // Освобождение динамически сформированной строки
            rdsFree(defval);
          }
        // Возврат: TRUE – есть связь, FALSE – нет связи
        return conn;
      }
      //=========================================

      // Функция настройки K и C для модели блока y=Kx+C
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      BOOL TestKxCSetup(
        RDS_BHANDLE Block,  // Идентификатор блока
        int numK,           // Номер переменной K в блоке
        int numC)           // Номер переменной C в блоке
      { RDS_HOBJECT window; // Идентификатор вспомогательного объекта
        BOOL ok;            // Пользователь нажал "OK"
        BOOL K_conn,C_conn; // Флаги наличия связей у K и C

        // Создание окна
        window=rdsFORMCreate(FALSE,-1,-1,"Kx+C");

        // Добавление полей для ввода или индикации K и C
        // (в зависимости от наличия связей)
        K_conn=AddWinEditOrDisplayDouble(window,Block,numK,1,NULL);
        C_conn=AddWinEditOrDisplayDouble(window,Block,numC,2,NULL);

        // Открытие окна
        ok=rdsFORMShowModalEx(window,NULL);
        if(ok)
          { // Нажата кнопка OK – запись параметров в блок
            if(!K_conn) // У K нет связи
              { // Получение строки из поля ввода
                char *str=rdsGetObjectStr(window,1,RDS_FORMVAL_VALUE);
                // Установка значения переменной K по умолчанию
                rdsSetBlockVarDefValueStr(Block,numK,str);
              }
            if(!C_conn) // У С нет связи
              { // Получение строки из поля ввода
                char *str=rdsGetObjectStr(window,2,RDS_FORMVAL_VALUE);
                // Установка значения переменной C по умолчанию
                rdsSetBlockVarDefValueStr(Block,numC,str);
              }
          }
        // Уничтожение окна
        rdsDeleteObject(window);
        // Возвращаемое значение – истина, если нажата "OK"
        return ok;
      }
      //=========================================

      // Функция модели блока
      extern "C" __declspec(dllexport)
        int RDSCALL TestKxC(int CallMode,
                            RDS_PBLOCKDATA BlockData,
                            LPVOID ExtParam)
      {
      // Макроопределения для статических переменных
      #define pStart ((char *)(BlockData->VarTreeData))
      #define Start (*((char *)(pStart)))
      #define Ready (*((char *)(pStart+RDS_VSZ_S)))
      #define x (*((double *)(pStart+2*RDS_VSZ_S)))
      #define K (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D)))
      #define C (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D)))
      #define y (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D)))
        switch(CallMode)
          { // Проверка типа переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSDDDD}")==0)
                return RDS_BFR_DONE;
              return RDS_BFR_BADVARSMSG;

            // Запуск расчета
            case RDS_BFM_STARTCALC:
              // Если это запуск с начала, взвести Start
              if(((RDS_PSTARTSTOPDATA)ExtParam)->FirstStart)
                Start=1; // Модель запустится в первом же такте
              break;

            // Такт расчета
            case RDS_BFM_MODEL:
              y=K*x+C;
              break;

            // Функция настройки
            case RDS_BFM_SETUP:
              if(TestKxCSetup(BlockData->Block,3,4))
                { // Нажата “OK"
                  Start=1; // Запустить модель в следующем такте
                  return RDS_BFR_MODIFIED;
                }
          }
        return RDS_BFR_DONE;
      // Отмена макроопределений
      #undef y
      #undef C
      #undef K
      #undef x
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=========================================