Полный исходный текст на языке C++ для библиотеки (DLL) с моделями блоков, выводящих сообщения пользователю или записывающих эти сообщения в заданный файл и иллюстрирующих регистрацию исполнителя функции. Библиотека содержит три модели:
- MessageFuncBlock_Box – блок-исполнитель функции, показывающий сообщение пользователю;
- MessageFuncBlock_File – блок-исполнитель функции, выводящий сообщение в файл;
- ShowMessage – блок, передающий зарегистрированному исполнителю сообщение для вывода.
// Регистрация исполнителя функции #include <windows.h> #include <stdio.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 PROGGUIDEMESSAGEFUNC "ProgrammersGuide.UserMessage" // Структура параметров функции typedef struct { DWORD servSize; // Размер этой структуры char *MessageStr; // Текст сообщения int Level; // Уровень важности (0, 1 или 2) } TProgGuideMessageFuncParams; //========================================= // Глобальная переменная для идентификатора функции int MessageFunc=0; //========================================= //==================================================================== // Блок-исполнитель функции, показывающей сообщение пользователю //==================================================================== extern "C" __declspec(dllexport) int RDSCALL MessageFuncBlock_Box(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { RDS_PFUNCTIONCALLDATA func; switch(CallMode) { // Инициализация case RDS_BFM_INIT: // Регистрируем функцию if(MessageFunc==0) MessageFunc=rdsRegisterFunction(PROGGUIDEMESSAGEFUNC); // Объявляем этот блок ее исполнителем rdsRegisterFuncProvider(MessageFunc,FALSE); break; // Очистка case RDS_BFM_CLEANUP: // Отменяем регистрацию данного блока как исполнителя rdsUnregisterFuncProvider(MessageFunc); break; // Вызов функции case RDS_BFM_FUNCTIONCALL: // Приводим ExtParam к правильному типу func=(RDS_PFUNCTIONCALLDATA)ExtParam; if(func->Function==MessageFunc) { // Вызвана "ProgrammersGuide.UserMessage" TProgGuideMessageFuncParams *params= (TProgGuideMessageFuncParams*)(func->Data); DWORD icon; char *caption; // Проверяем наличие параметров и их размер if(params==NULL || params->servSize<sizeof(TProgGuideMessageFuncParams)) break; // Параметров нет или неверный размер // В зависимости от уровня важности сообщения // устанавливаем иконку и заголовок // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" switch(params->Level) { case 0: icon=MB_ICONINFORMATION; caption="Информация"; break; case 1: icon=MB_ICONWARNING; caption="Предупреждение"; break; default: icon=MB_ICONERROR; caption="Ошибка"; } // Показываем сообщение пользователю rdsMessageBox(params->MessageStr,caption,icon | MB_OK); } break; } return RDS_BFR_DONE; } //========================================= //==================================================================== // Блок, вызывающий функцию вывода сообщения //==================================================================== // Личная область данных блока, выводящего сообщение class TMessageFuncUserData { public: // Указатель на структуру подписки RDS_PFUNCPROVIDERLINK Link; // Функция настройки блока BOOL Setup(RDS_BHANDLE Block,int NumTypeVar,int NumMessVar); // Конструктор класса TMessageFuncUserData(void) { // Регистрируем функцию if(MessageFunc==0) MessageFunc=rdsRegisterFunction(PROGGUIDEMESSAGEFUNC); // Подписываемся на блок-исполнитель Link=rdsSubscribeToFuncProvider(MessageFunc); }; // Деструктор класса ~TMessageFuncUserData() { // Прекращаем подписку rdsUnsubscribeFromFuncProvider(MessageFunc); }; }; //========================================= // Блок, выводящий сообщение по сигналу extern "C" __declspec(dllexport) int RDSCALL ShowMessage(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { // Указатель на личную область данных TMessageFuncUserData *data= (TMessageFuncUserData*)(BlockData->BlockData); // Макроопределения для статических переменных #define pShow ((char *)(BlockData->VarTreeData)) #define Show (*((char *)(pShow))) #define Ready (*((char *)(pShow+RDS_VSZ_S))) #define Message (*((char **)(pShow+2*RDS_VSZ_S))) #define Type (*((RDSINT32 *)(pShow+2*RDS_VSZ_S+RDS_VSZ_A))) switch(CallMode) { // Инициализация – создание личной области case RDS_BFM_INIT: BlockData->BlockData=new TMessageFuncUserData(); break; // Очистка – удаление личной области case RDS_BFM_CLEANUP: delete data; break; // Проверка типов переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSAI}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Настройка блока case RDS_BFM_SETUP: return data->Setup(BlockData->Block,3,2)?1:0; // Такт расчета (реакция на сигнал Show) case RDS_BFM_MODEL: if(data->Link!=NULL) // Есть структура подписки { TProgGuideMessageFuncParams params; // Готовим структуру параметров функции params.servSize=sizeof(params); params.MessageStr=Message; params.Level=Type; // Вызываем функцию по данным подписки rdsCallBlockFunction(data->Link->Block, data->Link->FuncId,¶ms); } break; } return RDS_BFR_DONE; // Отмена макрооперделений #undef Type #undef Message #undef Ready #undef Show #undef pShow } //========================================= // Функция настройки блока // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" BOOL TMessageFuncUserData::Setup(RDS_BHANDLE Block, int NumTypeVar,int NumMessVar) { RDS_HOBJECT window; // Объект-окно BOOL ok; // Пользователь нажал "OK" char *defval; // Создание окна window=rdsFORMCreate(FALSE,-1,-1,"Сообщение"); // Важность сообщения // Получение значения переменной по умолчанию defval=rdsGetBlockVarDefValueStr(Block,NumTypeVar,NULL); // Добавление поля – выпадающий список rdsFORMAddEdit(window,0,1,RDS_FORMCTRL_COMBOLIST,"Тип:",150); // Установка списка вариантов rdsSetObjectStr(window,1,RDS_FORMVAL_LIST, "Информация\nПредупреждение\nОшибка"); // Установка текущего значения поля rdsSetObjectStr(window,1,RDS_FORMVAL_ITEMINDEX,defval); // Освобождение defval rdsFree(defval); // Текст сообщения // Получение значения переменной по умолчанию defval=rdsGetBlockVarDefValueStr(Block,NumMessVar,NULL); // Добавление поля – многострочное rdsFORMAddEdit(window,0,2,RDS_FORMCTRL_MULTILINE,"Текст:",80); // Установка текущего значения поля rdsSetObjectStr(window,2,RDS_FORMVAL_VALUE,defval); // Установка высоты поля в точках экрана (~3 строки) rdsSetObjectInt(window,2,RDS_FORMVAL_MLHEIGHT,3*24); // Освобождение defval rdsFree(defval); // Открытие окна ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Пользователь нажал OK – запись измененных параметров defval=rdsGetObjectStr(window,1,RDS_FORMVAL_ITEMINDEX); rdsSetBlockVarDefValueStr(Block,NumTypeVar,defval); defval=rdsGetObjectStr(window,2,RDS_FORMVAL_VALUE); rdsSetBlockVarDefValueStr(Block,NumMessVar,defval); } // Уничтожение окна rdsDeleteObject(window); return ok; } //========================================= //==================================================================== // Блок-исполнитель функции, записывающий сообщение в файл //==================================================================== // Функция настройки блока вывода сообщения в файл // ВАЖНО: Исходный текст программы должен быть записан в UTF8, // в противном случае необходимо использовать версии функций // с суффиксом "W" и символьные константы с префиксом "L" BOOL MessageFuncBlockFileSetup( RDS_BHANDLE Block, // Идентификатор блока int NumFileVar, // Номер переменной имени файла int NumClearVar) // Номер переменной флага очистки { RDS_HOBJECT window;// Идентификатор объекта-окна BOOL ok; // Пользователь нажал "OK" char *defval; // Создание окна window=rdsFORMCreate(FALSE,-1,-1,"Запись в файл"); // Поле ввода для имени файла // Чтение значения переменной по умолчанию defval=rdsGetBlockVarDefValueStr(Block,NumFileVar,NULL); // Поле ввода – выбор файла с диалогом сохранения rdsFORMAddEdit(window,0,1,RDS_FORMCTRL_SAVEDIALOG,"Файл:",300); // Фильтр типов файлов для диалога сохранения rdsSetObjectStr(window,1,RDS_FORMVAL_LIST, "Текстовые файлы (*.txt)|*.txt\nВсе файлы|*.*"); // Запись значения в поле ввода rdsSetObjectStr(window,1,RDS_FORMVAL_VALUE,defval); // Освобождение defval rdsFree(defval); // Очистка при загрузке схемы // Чтение значения переменной по умолчанию defval=rdsGetBlockVarDefValueStr(Block,NumClearVar,NULL); // Поле ввода - флаг rdsFORMAddEdit(window,0,2,RDS_FORMCTRL_CHECKBOX, "Очищать при загрузке схемы",0); // Запись значения в поле ввода rdsSetObjectStr(window,2,RDS_FORMVAL_VALUE,defval); // Освобождение defval rdsFree(defval); // Открытие окна ok=rdsFORMShowModalEx(window,NULL); if(ok) { // Пользователь нажал OK – запись измененных значений defval=rdsGetObjectStr(window,1,RDS_FORMVAL_VALUE); rdsSetBlockVarDefValueStr(Block,NumFileVar,defval); defval=rdsGetObjectStr(window,2,RDS_FORMVAL_VALUE); rdsSetBlockVarDefValueStr(Block,NumClearVar,defval); } // Уничтожение окна rdsDeleteObject(window); return ok; } //========================================= // Блок-исполнитель функции, выводящий сообщение в файл // ВАЖНО: в модели используются функции Windows API для работы с файлом. // Поскольку в Windows используется кодировка UTF16, в модели вызываются // сервисные функции RDS для перевода UTF8 в UTF16. extern "C" __declspec(dllexport) int RDSCALL MessageFuncBlock_File(int CallMode, RDS_PBLOCKDATA BlockData, LPVOID ExtParam) { RDS_PFUNCTIONCALLDATA func; // Макроопределения для статических переменных #define pStart ((char *)(BlockData->VarTreeData)) #define Start (*((char *)(pStart))) #define Ready (*((char *)(pStart+RDS_VSZ_S))) #define FileName (*((char **)(pStart+2*RDS_VSZ_S))) #define ClearOnLoad (*((char *)(pStart+2*RDS_VSZ_S+RDS_VSZ_A))) switch(CallMode) { // Инициализация case RDS_BFM_INIT: // Регистрация функции if(MessageFunc==0) MessageFunc=rdsRegisterFunction(PROGGUIDEMESSAGEFUNC); // Объявляем данный блок ее исполнителем rdsRegisterFuncProvider(MessageFunc,FALSE); break; // Очистка case RDS_BFM_CLEANUP: // Отмена регистрации блока как исполнителя rdsUnregisterFuncProvider(MessageFunc); break; // Проверка типов статических переменных case RDS_BFM_VARCHECK: return strcmp((char*)ExtParam,"{SSAL}")? RDS_BFR_BADVARSMSG:RDS_BFR_DONE; // Вызов функции настройки case RDS_BFM_SETUP: return MessageFuncBlockFileSetup(BlockData->Block,2,3)?1:0; // Загрузка схемы только что завершилась case RDS_BFM_AFTERLOAD: if(ClearOnLoad) // Включена очистка файла при загрузке { // Формируем в fullpath полный путь к файлу, т.к. // введенный пользователем может быть неполным char *fullpath=rdsGetFullFilePath(FileName,NULL,NULL); if(fullpath) // Полный путь существует { // Преобразуем в UTF16 RDSWSTR fullpath_w=rdsUTF8toUTF16(fullpath,FALSE); DeleteFileW(fullpath_w); // Удаляем файл // Освобождаем память rdsFree(fullpath_w); rdsFree(fullpath); } } break; // Вызов функции case RDS_BFM_FUNCTIONCALL: func=(RDS_PFUNCTIONCALLDATA)ExtParam; if(func->Function==MessageFunc) { // Вызвана наша функция – приводим параметры к правильному типу TProgGuideMessageFuncParams *params= (TProgGuideMessageFuncParams*)(func->Data); char *levelstr,*fullpath; RDSWSTR fullpath_w; // Для имени файла в UTF16 if(params==NULL || params->servSize<sizeof(TProgGuideMessageFuncParams)) break; // Параметров нет или неверный размер // Записываем в переменную levelstr строку, // соотвествующую важности сообщения switch(params->Level) { case 0: levelstr="Информация"; break; case 1: levelstr="Предупреждение"; break; default: levelstr="Ошибка"; } // Формируем в fullpath полный путь к файлу fullpath=rdsGetFullFilePath(FileName,NULL,NULL); if(fullpath) // Полный путь сформирован { HANDLE h; // Преобразуем в UTF16 fullpath_w=rdsUTF8toUTF16(fullpath,FALSE); // Открываем файл fullpath на запись h=CreateFileW(fullpath_w,GENERIC_WRITE,0,NULL, OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if(h!=INVALID_HANDLE_VALUE) { // Файл открыт char buf[100]; DWORD temp; SYSTEMTIME time; // Перемещаем указатель файла в конец SetFilePointer(h,0,NULL,FILE_END); // Получаем текущую дату и время GetLocalTime(&time); // Формируем строку с датой и временем в buf sprintf(buf,"%02d-%02d-%04d %02d:%02d:%02d " "%s: ",time.wDay,time.wMonth,time.wYear, time.wHour,time.wMinute,time.wSecond, levelstr); // Записываем дату, время и важность WriteFile(h,buf,strlen(buf),&temp,NULL); // Записываем текст сообщения if(params->MessageStr) WriteFile(h,params->MessageStr, strlen(params->MessageStr),&temp,NULL); // Записываем перевод строки WriteFile(h,"\r\n",2,&temp,NULL); // Закрываем файл CloseHandle(h); } // Освобождаем память, отведенную под полный путь rdsFree(fullpath_w); rdsFree(fullpath); } } break; } return RDS_BFR_DONE; // Отмена макроопределений #undef ClearOnLoad #undef FileName #undef Ready #undef Start #undef pStart } //=========================================