Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, организующих передачу данных между частями схемы через динамическую переменную, имя которой пользователь может задавать в окне настроек блока. Библиотека содержит две модели:
- TestTunnelIn – блок-передатчик;
- TestTunnelOut – блок-приемник.
Изменения, внесенные в старые версии этих же моделей, описанные в §2.6.3, выделены цветом.
// Связь между блоками через динамическую переменную // (добавлена функция настройки) #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; } //========= Конец главной функции ========= //=========== Блок-передатчик ============= extern "C" __declspec(dllexport) int RDSCALL TestTunnelIn(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))) // Вспомогательная переменная – указатель на структуру подписки RDS_PDYNVARLINK Link; // Вспомогательная переменная – структура описания блока RDS_BLOCKDESCRIPTION Descr; // Вспомогательная переменная – указатель на строку char *str; switch(CallMode) { // Очистка case RDS_BFM_CLEANUP: // Запомненный указатель на структуру подписки Link=(RDS_PDYNVARLINK)BlockData->BlockData; // Удалить созданную динамическую переменную rdsDeleteDVByLink(Link); break; // Проверка типа статических переменных case RDS_BFM_VARCHECK: if(strcmp((char*)ExtParam,"{SSD}")==0) return RDS_BFR_DONE; return RDS_BFR_BADVARSMSG; // Переход в режим моделирования case RDS_BFM_CALCMODE: // Запомненный указатель на структуру подписки Link=(RDS_PDYNVARLINK)BlockData->BlockData; if(Link!=NULL) // Динамическая переменная была создана { // Заполнить структуру описания блока Descr.servSize=sizeof(Descr); rdsGetBlockDescription(BlockData->Block,&Descr); // Сравнить имя переменной с текстом комментария if(strcmp(Link->VarName,Descr.BlockComment)!=0) { // Имя переменной не совпадает с комментарием - // переменная будет удалена rdsDeleteDVByLink(Link); // Очистить запомненный указатель на структуру // подписки BlockData->BlockData=NULL; } } break; // Запуск расчета case RDS_BFM_STARTCALC: if(BlockData->BlockData!=NULL) // Переменная была создана break; // Динамической переменной нет (не было или удалена // в реакции на RDS_BFM_CALCMODE) - надо создать новую. // Сначала надо получить комментарий блока Descr.servSize=sizeof(Descr); rdsGetBlockDescription(BlockData->Block,&Descr); if(*Descr.BlockComment==0) // Комментарий пуст break; // Комментарий блока – не пустая строка. Создаем переменную. Link=rdsCreateAndSubscribeDV(RDS_DVROOT, Descr.BlockComment, "D", TRUE, NULL); // Запомнить новый указатель на структуру подписки BlockData->BlockData=Link; // В конце реакции на запуск расчета нет оператора break, // поэтому сразу после нее выполнится реакция на // такт расчета (чтобы начальное значение входа // записалось в динамическую переменную) // Выполнение такта моделирования case RDS_BFM_MODEL: // Запомненный указатель на структуру подписки Link=(RDS_PDYNVARLINK)BlockData->BlockData; // Проверка существования переменной if(Link!=NULL && Link->Data!=NULL) { // Переменная существует – привести указатель // на область данных переменной к типу "double*" double *pV=(double*)Link->Data; if(*pV!=x) // Значение входа изменилось { // Записать в динамическую переменную новое // значение входа *pV=x; // Уведомить всех подписчиков об изменении // переменной rdsNotifyDynVarSubscribers(Link); } } break; // Реакция на функцию настройки case RDS_BFM_SETUP: // Получение текущего текста комментария блока Descr.servSize=sizeof(Descr); rdsGetBlockDescription(BlockData->Block,&Descr); // Открытие диалогового окна для ввода строки str=rdsInputString("Переменная связи", // Заголовок окна "Имя переменной:", // Заголовок поля Descr.BlockComment, // Исходный текст 150); // Ширина поля if(str!=NULL) // Пользователь нажал "OK" { // Установить новый комментарий rdsSetBlockComment(BlockData->Block,str); // Освободить динамическую строку rdsFree(str); // Информировать RDS об изменениях return RDS_BFR_MODIFIED; } break; } return RDS_BFR_DONE; // Отмена макроопределений #undef x #undef Ready #undef Start #undef pStart } //========================================= //============ Блок-приемник ============== extern "C" __declspec(dllexport) int RDSCALL TestTunnelOut(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define y (*((double *)(pStart+2*RDS_VSZ_S))) // Вспомогательная переменная – указатель на структуру подписки RDS_PDYNVARLINK Link; // Вспомогательная переменная – структура описания блока RDS_BLOCKDESCRIPTION Descr; // Вспомогательная переменная – указатель на строку char *str; switch(CallMode) { // Очистка case RDS_BFM_CLEANUP: // Запомненный указатель на структуру подписки Link=(RDS_PDYNVARLINK)BlockData->BlockData; // Прекратить подписку на переменную rdsUnsubscribeFromDynamicVar(Link); break; // Проверка типа статических переменных case RDS_BFM_VARCHECK: if(strcmp((char*)ExtParam,"{SSD}")==0) return RDS_BFR_DONE; return RDS_BFR_BADVARSMSG; // Запуск расчета case RDS_BFM_STARTCALC: // Запомненный указатель на структуру подписки Link=(RDS_PDYNVARLINK)BlockData->BlockData; // Получение описания блока (с комментарием) Descr.servSize=sizeof(Descr); rdsGetBlockDescription(BlockData->Block,&Descr); // Проверка наличия комментария if(*Descr.BlockComment==0) // Пустая строка { // Прекратить подписку на переменную rdsUnsubscribeFromDynamicVar(Link); // Очистить запомненный указатель на структуру подписки BlockData->BlockData=NULL; break; } // Если переменной нет (Link==NULL) или ее имя не // соответствует комментарию блока (strcmp... !=0), // нужно подписаться на новую переменную if(Link==NULL || strcmp(Link->VarName,Descr.BlockComment)!=0) { // Прекратить подписку на старую переменную rdsUnsubscribeFromDynamicVar(Link); // Подписаться на новую Link=rdsSubscribeToDynamicVar(RDS_DVROOT, Descr.BlockComment, "D", FALSE); // Запомнить новый указатель на структуру подписки BlockData->BlockData=Link; } // В конце реакции на запуск расчета нет оператора break, // поэтому сразу после нее выполнится реакция на // изменение динамической переменной (чтобы ее значение // было немедленно передано на выход блока) // Реакция на изменение динамической переменной case RDS_BFM_DYNVARCHANGE: // Запомненный указатель на структуру подписки Link=(RDS_PDYNVARLINK)BlockData->BlockData; // Проверка существования переменной if(Link!=NULL && Link->Data!=NULL) { // Присвоить выходу блока значение динамической // переменной y=*(double*)Link->Data; // Взвести сигнал Ready, чтобы значение выхода // было передано по связям Ready=1; } break; // Реакция на функцию настройки case RDS_BFM_SETUP: // Получение текущего текста комментария блока Descr.servSize=sizeof(Descr); rdsGetBlockDescription(BlockData->Block,&Descr); // Открытие диалогового окна для ввода строки str=rdsInputString("Переменная связи", // Заголовок окна "Имя переменной:", // Заголовок поля Descr.BlockComment, // Исходный текст 150); // Ширина поля if(str!=NULL) // Пользователь нажал "OK" { // Установить новый комментарий rdsSetBlockComment(BlockData->Block,str); // Освободить динамическую строку rdsFree(str); // Информировать RDS об изменениях return RDS_BFR_MODIFIED; } break; } return RDS_BFR_DONE; // Отмена макроопределений #undef y #undef Ready #undef Start #undef pStart } //=========================================