Полный исходный текст на языке C++ для библиотеки (DLL) с моделью блока, иллюстрирующей прямой вызов функции у всех блоков подсистемы. В модель EditControlFrame (блок с прозрачным для щелчков мыши «окном», см. §2.12.3) добавлена возможность одновременного «открытия» и «закрытия» всех таких блоков в подсистеме. Изменения относительно предыдущей версии модели выделены цветом).
// Прямой вызов функции всех блоков подсистемы #include <windows.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; } //========= Конец главной функции =========//========================================= // Функция управления состоянием блока //========================================= // Имя функции #define PROGGUIDEEDITCTRLFUNC_SET \ "ProgrammersGuide.EditCtrlFrame.Set" // Структура параметров функции typedef struct { DWORD servSize; // Размер этой структуры для проверки int Command; // Команда блоку (0, 1 или 2) } TProgGuideEditCtrlSetParams; //=========================================// Идентификатор функции PROGGUIDEEDITCTRLFUNC_SET int EditCtrlFuncSet=0;//============================================================================ // Блок с "окном" //============================================================================ extern "C" __declspec(dllexport) int RDSCALL EditControlFrame(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_ext (*((double *)(pStart+2*RDS_VSZ_S))) #define x_int (*((double *)(pStart+2*RDS_VSZ_S+RDS_VSZ_D))) #define out (*((double *)(pStart+2*RDS_VSZ_S+2*RDS_VSZ_D))) #define bypass (*((char *)(pStart+2*RDS_VSZ_S+3*RDS_VSZ_D))) const int fr=20; // Толщина рамки // Вспомогательные переменные RDS_PMOUSEDATA mouse; RDS_PDRAWDATA draw; int frz,x1,y1,x2,y2,xi1,yi1,xi2,yi2;RDS_PFUNCTIONCALLDATA func; // Описание вызванной функции RDS_PMENUFUNCDATA menu; // Описание выбранного пункта меню TProgGuideEditCtrlSetParams callparams; // Параметры функцииswitch(CallMode) {// Инициализация блока case RDS_BFM_INIT: if(!EditCtrlFuncSet) EditCtrlFuncSet=rdsRegisterFunction(PROGGUIDEEDITCTRLFUNC_SET); break;// Проверка типов статических переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSDDDL}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Реакция на нажатие кнопки мыши case RDS_BFM_MOUSEDOWN: mouse=(RDS_PMOUSEDATA)ExtParam; // Толщина рамки с учетом масштаба frz=fr*mouse->DoubleZoom; // В открытом состоянии при попадании курсора внутрь // прозрачного окна на щелчок реагировать не нужно if(bypass==0 && mouse->x>mouse->Left+frz && mouse->y>mouse->Top+frz && mouse->x<mouse->Left+mouse->Width-frz && mouse->y<mouse->Top+mouse->Height-frz) return RDS_BFR_NOTPROCESSED; // Если не левая кнопка - не обрабатываем щелчок // и разрешаем вывести контекстное меню, если нужно if(mouse->Button!=RDS_MLEFTBUTTON) return RDS_BFR_SHOWMENU; // Нажата левая кнопка мыши, причем курсор попал // в рамку или блок в закрытом состоянии bypass=!bypass; // Переключаем состояние Ready=1; // Взводим сигнал готовности // Здесь намеренно не поставлен оператор break: необходимо // выполнить действия в следующем case (такт расчета) // Один такт расчета case RDS_BFM_MODEL: // В зависимости от состояния, подаем на выход один из входов out=bypass?x_ext:x_int; break; // Рисование внешнего вида блока case RDS_BFM_DRAW: draw=(RDS_PDRAWDATA)ExtParam; // Координаты описывающего прямоугольника блока x1=draw->Left; x2=draw->Left+draw->Width; y1=draw->Top; y2=draw->Top+draw->Height; // Толщина рамки с учетом масштаба frz=fr*draw->DoubleZoom; // Координаты окна внутри блока xi1=x1+frz; xi2=x2-frz; yi1=y1+frz; yi2=y2-frz; if(bypass) { // Закрытое состояние int w; char *text; // Рисуем красный прямоугольник с черной рамкой rdsXGSetPenStyle(0,PS_SOLID,1,0,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_SOLID,0xff); rdsXGRectangle(x1,y1,x2,y2); // Устанавливаем шрифт выстой в окно внутри блока rdsXGSetFont(0,"Arial",yi2-yi1,0, DEFAULT_CHARSET,0,FALSE,FALSE,FALSE,FALSE); // Преобразуем значение выхода в динамическую строку text=rdsDtoA(out,-1,NULL); // Определяем ширину получившейся строки на экране rdsXGGetTextSize(text,&w,NULL); // Выводим значение выхода туда, где в открытом // состоянии находится прозрачное окно rdsXGTextOut(xi2-w,yi1,text); // Освобождаем динамическую строку rdsFree(text); } else { // Открытое состояние rdsXGSetBrushStyle(0,RDS_GFS_SOLID,0xff00); // Рисуем рамку вокруг прозрачного окна из четырех // зеленых прямоугольников rdsXGFillRect(x1,y1,x2,yi1); rdsXGFillRect(x1,yi2,x2,y2); rdsXGFillRect(x1,yi1,xi1,yi2); rdsXGFillRect(xi2,yi1,x2,yi2); // Обрамляем черными линиями rdsXGSetPenStyle(0,PS_SOLID,1,0,R2_COPYPEN); rdsXGSetBrushStyle(0,RDS_GFS_EMPTY,0); rdsXGRectangle(x1,y1,x2,y2); rdsXGRectangle(xi1,yi1,xi2,yi2); } break; // Проверка возможности выбора блока мышью case RDS_BFM_MOUSESELECT: mouse=(RDS_PMOUSEDATA)ExtParam; frz=fr*mouse->DoubleZoom; // Толщина рамки // Проверка попадания в прозрачное окно if(bypass==0 && mouse->x>mouse->Left+frz && mouse->y>mouse->Top+frz && mouse->x<mouse->Left+mouse->Width-frz && mouse->y<mouse->Top+mouse->Height-frz) return RDS_BFR_NOTPROCESSED; // В окно не попали - функция вернет RDS_BFR_DONE break; // Открытие контекстного меню блока case RDS_BFM_CONTEXTPOPUP: // Добавление временных пунктов меню // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" rdsAdditionalContextMenuItemEx(bypass?"Открыть":"Закрыть",0,1,2);rdsAdditionalContextMenuItemEx(NULL,RDS_MENU_DIVIDER,0,0); rdsAdditionalContextMenuItemEx("Открыть все",0,2,1); rdsAdditionalContextMenuItemEx("Закрыть все",0,2,0); rdsAdditionalContextMenuItemEx("Переключить все",0,2,2);break; // Выбор пункта меню пользователем case RDS_BFM_MENUFUNCTION: menu=(RDS_PMENUFUNCDATA)ExtParam; // Данные пункта меню switch(menu->Function) { case 1: // Открыть/закрыть bypass=!bypass; // Переключить режим out=bypass?x_ext:x_int; // Подать на выход Ready=1; // Взвести флаг готовности break; case 2: // Один из новых пунктов // Заполняем структуру параметров функции callparams.Command=menu->MenuData; callparams.servSize=sizeof(callparams); // Вызываем у всех блоков родительской подсистемы rdsBroadcastFunctionCallsEx(BlockData->Parent, EditCtrlFuncSet, &callparams, 0); break; } break;// Вызов функции блока case RDS_BFM_FUNCTIONCALL: // Приведение ExtParam к правильному типу func=(RDS_PFUNCTIONCALLDATA)ExtParam; // Проверяем, какая функция вызвана if(func->Function==EditCtrlFuncSet) { // Вызвана нужная нам функция TProgGuideEditCtrlSetParams *params; // Приводим указатель на параметры к нужному типу // и проверяем размер переданной структуры params=(TProgGuideEditCtrlSetParams*)(func->Data); if(params->servSize<sizeof(TProgGuideEditCtrlSetParams)) break; // Размер недостаточен // В зависимости от Command меняем режим блока switch(params->Command) { case 0: bypass=1; break; // Закрыть case 1: bypass=0; break; // Открыть case 2: bypass=!bypass; break; // Переключить default: return RDS_BFR_DONE; // Ошибка } // Взводим сигнал готовности и передаем нужный вход // на выход Ready=1; out=bypass?x_ext:x_int; } break;} return RDS_BFR_DONE; // Отмена макроопределений #undef bypass #undef out #undef x_int #undef x_ext #undef Ready #undef Start #undef pStart } //=========================================