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

Описания RDS

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

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

§2.6. Динамические переменные

§2.6.4. Работа с несколькими динамическими переменными

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

- TestBlkMoveSetter – блок, записывающий в динамические переменные значения скорости и угла поворота;
- TestBlkMoveObject – блок, перемещающийся в окне подсистемы со скоростью и в направлении, считанными из динамических переменных.

      // Подвижный блок, передача через динамические переменные
      #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;
      }
      //========= Конец главной функции =========

      //=========== Блок управления =============
      // Структура личной области данных блока
      typedef struct
      { // Указатель на структуру подписки на скорость
        RDS_PDYNVARLINK VLink;
        // Указатель на структуру подписки на направление
        RDS_PDYNVARLINK ALink;
      } TestBlkMoveSetterData;

      // Модель блока управления
      extern "C" __declspec(dllexport)
        int RDSCALL TestBlkMoveSetter(int CallMode,
                                      RDS_PBLOCKDATA BlockData,
                                      LPVOID ExtParam)
      {
      // Макроопределения для статических переменных
      #define pStart  ((char *)(BlockData->VarTreeData))
      #define Start (*((char *)(pStart)))
      #define Ready (*((char *)(pStart+RDS_VSZ_S)))
      #define Speed (*((double *)(pStart+2*RDS_VSZ_S)))
      #define Angle (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D)))
        // Вспомогательная переменная – указатель на личную область
        // данных блока, приведенный к правильному типу
        TestBlkMoveSetterData *privdata;

        switch(CallMode)
          { // Инициализация блока
            case RDS_BFM_INIT:
              // Отведение памяти под личную область данных
              privdata=(TestBlkMoveSetterData*)
                        malloc(sizeof(TestBlkMoveSetterData));
              BlockData->BlockData=privdata;
              // Создание переменной для передачи скорости
              privdata->VLink=rdsCreateAndSubscribeDV(
                                RDS_DVPARENT,     // В родительской
                                "BlkMove_Speed",  // Имя переменной
                                "D",              // Тип double
                                TRUE,             // Запрет удаления
                                NULL);            // Без нач.значения
              // Создание переменной для передачи направления
              privdata->ALink=rdsCreateAndSubscribeDV(
                                RDS_DVPARENT,
                                "BlkMove_Angle",
                                "D",
                                TRUE,
                                NULL);
              break;

            // Очистка данных блока
            case RDS_BFM_CLEANUP:
              // Приведение указателя на личную область данных к
              // правильному типу
              privdata=(TestBlkMoveSetterData*)(BlockData->BlockData);
              // Удаление динамических переменных
              rdsDeleteDVByLink(privdata->VLink);
              rdsDeleteDVByLink(privdata->ALink);
              // Освобождение отведенной памяти
              free(privdata);
              break;

            // Проверка типа статических переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSDD}")==0)
                return RDS_BFR_DONE;
              return RDS_BFR_BADVARSMSG;

            // Выполнение такта моделирования
            case RDS_BFM_MODEL:
              // Приведение указателя на личную область данных к
              // правильному типу
              privdata=(TestBlkMoveSetterData*)(BlockData->BlockData);
              // Проверка существования переменной направления
              if(privdata->ALink!=NULL && privdata->ALink->Data!=NULL)
                { // Переменная существует – привести к типу double*
                  double *pa=(double*)privdata->ALink->Data;
                  if(*pa!=Angle) // Значение направления изменилось
                    { // Записать значение в динамическую переменную
                      *pa=Angle;
                      // Уведомить всех подписчиков об изменении
                      rdsNotifyDynVarSubscribers(privdata->ALink);
                    }
                }
              // Проверка существования переменной скорости
              if(privdata->VLink!=NULL && privdata->VLink->Data!=NULL)
                { // Переменная существует – привести к типу double*
                  double *pv=(double*)privdata->VLink->Data;
                  if(*pv!=Speed)
                    { // Записать значение в динамическую переменную
                      *pv=Speed;
                      // Уведомить всех подписчиков об изменении
                      rdsNotifyDynVarSubscribers(privdata->VLink);
                    }
                }
              break;
          }
        return RDS_BFR_DONE;
      // Отмена макроопределений
      #undef Angle
      #undef Speed
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=========================================

      //============ Подвижный блок =============
      // Структура личной области данных блока
      typedef struct
      { // Указатель на структуру подписки на скорость
        RDS_PDYNVARLINK VLink;
        // Указатель на структуру подписки на направление
        RDS_PDYNVARLINK ALink;
        // Указатель на структуру подписки на время
        RDS_PDYNVARLINK Time;

        // Дополнительные поля для хранения значений синуса
        // и косинуса направления движения блока
        double SinA;
        double CosA;
      } TestBlkMoveObjectData;

      // Модель перемещающегося блока
      extern "C" __declspec(dllexport)
        int RDSCALL TestBlkMoveObject(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 y (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D)))
      #define a (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D)))
      #define t0 (*((double *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D)))
        // Вспомогательная переменная – указатель на личную область
        // данных блока, приведенный к правильному типу
        TestBlkMoveObjectData *privdata;
        // Вспомогательные переменные для скорости и времени
        double v,time;

        switch(CallMode)
          { // Инициализация блока
            case RDS_BFM_INIT:
              // Отведение памяти под личную область данных
              privdata=(TestBlkMoveObjectData*)
                        malloc(sizeof(TestBlkMoveObjectData));
              BlockData->BlockData=privdata;
              // Подписка на переменную скорости
              privdata->VLink=rdsSubscribeToDynamicVar(
                              RDS_DVPARENT,    // В родительской
                              "BlkMove_Speed", // Имя переменной
                              "D",             // Тип double
                              FALSE);          // Без поиска
              // Подписка на переменную направления
              privdata->ALink=rdsSubscribeToDynamicVar(
                              RDS_DVPARENT,
                              "BlkMove_Angle",
                              "D",
                              FALSE);
              // Подписка на переменную времени
              privdata->Time=rdsSubscribeToDynamicVar(
                              RDS_DVPARENT,  // В родительской
                              "DynTime",     // Имя переменной
                              "D",           // Тип double
                              TRUE);         // Поиск в иерархии
              break;

            // Очистка данных блока
            case RDS_BFM_CLEANUP:
              // Приведение указателя на личную область данных к
              // правильному типу
              privdata=(TestBlkMoveObjectData*)(BlockData->BlockData);
              // Прекращение подписки на все динамические переменные
              rdsUnsubscribeFromDynamicVar(privdata->VLink);
              rdsUnsubscribeFromDynamicVar(privdata->ALink);
              rdsUnsubscribeFromDynamicVar(privdata->Time);
              // Освобождение отведенной памяти
              free(privdata);
              break;

            // Проверка типа статических переменных
            case RDS_BFM_VARCHECK:
              if(strcmp((char*)ExtParam,"{SSDDDD}")==0)
                return RDS_BFR_DONE;
              return RDS_BFR_BADVARSMSG;

            // Реакция на изменение динамической переменной
            case RDS_BFM_DYNVARCHANGE:
              // Приведение указателя на личную область данных к
              // правильному типу
              privdata=(TestBlkMoveObjectData*)(BlockData->BlockData);
              // Проверка – удалось ли подписаться на все переменные
              // (если хотя бы один указатель – NULL, значит, не удалось)
              if(privdata->VLink==NULL ||  // Скорость
                 privdata->ALink==NULL ||  // Направление
                 privdata->Time==NULL)     // Время
                break;
              // Проверка – существуют ли все переменные
              // (если хотя бы один указатель – NULL, значит, не удалось)
              if(privdata->VLink->Data==NULL ||  // Скорость
                 privdata->ALink->Data==NULL ||  // Направление
                 privdata->Time->Data==NULL)     // Время
                break;
              // Если изменилась переменная направления, нужно вычислить
              // и запомнить новые значения ыинуса и косинуса угла
              if(ExtParam==(void*)(privdata->ALink))
                { // Изменилось направление – привести к типу double*
                  double *pa=(double*)privdata->ALink->Data;
                  // Значение угла в радианах
                  a=(*pa)*M_PI/180.0;
                  // Значения синуса и косинуса
                  privdata->SinA=sin(a);
                  privdata->CosA=cos(a);
                }
              // Записать во вспомогательные переменные v и time значения
              // скорости и времени
              v=*(double*)privdata->VLink->Data;
              time=*(double*)privdata->Time->Data;
              // Вычислить новое смещение изображения блока
              x+=v*(time-t0)*privdata->CosA;
              y-=v*(time-t0)*privdata->SinA;
              // Запомнить значение времени, для которого вычислены
              // новые координаты
              t0=time;
              break;
          }
        return RDS_BFR_DONE;
      // Отмена макроопределений
      #undef t0
      #undef a
      #undef y
      #undef x
      #undef Ready
      #undef Start
      #undef pStart
      }
      //=========================================