Навигация:
<< >> Оглавление Указатель
Текст С++

Полный исходный текст на языке C++ для библиотеки (DLL) с примером модуля автокомпиляции моделей блоков для языка C. В пример добавленв возможность подключения моделей к блокам и редактирование моделей. Компиляция пока не реализована.

Изменения относительно §3.2 выделены цветом.

  #include <windows.h>
  #include <RdsDef.h>
  // Подготовка описаний сервисных функций
  
  #include <RdsFunc.h>

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

// Имена секций файла модели // Начало файла #define TCTEXTSECTION_START "$TESTCMODEL" // Секция переменных #define TCTEXTSECTION_VARS "$VARS" // Секция исходного текста #define TCTEXTSECTION_PROG "$PROG" //=========================================
// Класс личной области данных модуля автокомпиляции class { private: // Пути char *CompPath; // к компилятору char *LinkPath; // к редактору связей (link) char *IncludePath; // к файлам заголовков char *LibPath; // к библиотекам // Нужно ли добавлять путь к exe-файлу компилятора и редактора связей CompSetPath,LinkSetPath; // Параметры командной строки char *CompParams; // компилятора char *LinkParams; // редактора связей // Параметры исходного текста char *DllMainName; // имя главной функции DLL char *ModelFuncHdr; // заголовок функции модели char *Exported; // экспортированное имя функции // Освободить все динамические строки void FreeAllStrings(void) { (CompPath); (LinkPath); (IncludePath); (LibPath); (CompParams); (LinkParams); (DllMainName); (ModelFuncHdr); (Exported); };
// Сообщение об ошибке в модели static void (char *modelname,int errorcode);
public: // Чтение параметров модуля из INI-файла void ReadFromIni(const char *IniFileName); // Запись параметров модуля в INI-файл void WriteToIni(const char *IniFileName); // Настройка параметров модуля void Setup(const char *IniFileName);
// Создать новую пустую модель void (void); // Выбрать существующий файл модели void (const char *oldmodel); // Проверить возможность подключения модели к блоку int ( *param); // Открыть редактор модели void ( *param);
// Конструктор класса TCAutoCompData(void) { IncludePath=LibPath=NULL; CompSetPath=LinkSetPath=TRUE; #ifdef CompPath=( "$RDS$\\mingw-w64\\bin\\g++.exe"); LinkPath=(CompPath); CompParams=( "-Wall -m64 -g -I\"$RDSINCLUDE$\" -c \"$TEMP$\\$NAME$.cpp\" -o \"$TEMP$\\$NAME$.o\"" ); LinkParams=( "-shared -static -static-libgcc -static-libstdc++ -Wl,--dll \"$TEMP$\\$NAME$.o\" -o \"$TEMP$\\$NAME$.dll\" -s -m64 -luser32" ); DllMainName=("extern \"C\" __declspec(dllexport) BOOL APIENTRY DllMain"); ModelFuncHdr=( "extern \"C\" __declspec(dllexport) int RDSCALL autocompModelFunc" ); Exported=("autocompModelFunc"); #else CompPath=( "$RDS$\\tdm-gcc\\bin\\g++.exe"); LinkPath=(CompPath); CompParams=( "-shared -fpermissive -c -I\"$RDSINCLUDE$\" \"$TEMP$\\$NAME$.cpp\"" ); LinkParams=( "-shared -static -static-libgcc -static-libstdc++ -o \"$TEMP$\\$NAME$.dll\" \"$TEMP$\\$NAME$.o\"" ); DllMainName=("extern \"C\" BOOL WINAPI DllMain"); ModelFuncHdr=( "extern \"C\" __declspec(dllexport) int RDSCALL autocompModelFunc"); Exported=("autocompModelFunc@12"); #endif }; // Деструктор класса ~TCAutoCompData(){ FreeAllStrings(); }; }; //========================================= // Запись параметров модуля в INI-файл void TCAutoCompData::WriteToIni(const char *IniFileName) { ini=(TRUE); // Загружаем старый текст из файла во вспомогательный объект, если он есть if((IniFileName,NULL,NULL,NULL)) (ini,RDS_HINI_LOADFILE,0,IniFileName); // Создаем секцию [Paths...] (ini,,0,"Paths" ); // Записываем в нее пути (ini,"Compiler",CompPath); (ini,"Linker",LinkPath); (ini,"Include",IncludePath); (ini,"Lib",LibPath); (ini,"CompilerToPaths",CompSetPath); (ini,"LinkerToPaths",LinkSetPath); // Создаем секцию [Params...] (ini,,0,"Params" ); // Записываем в нее параметры командной строки (ini,"Compiler",CompParams); (ini,"Linker",LinkParams); // Создаем секцию [Func...] (ini,,0,"Func" ); // Записываем в нее остальные параметры (ini,"DllMain",DllMainName); (ini,"ModelFunc",ModelFuncHdr); (ini,"Exported",Exported); // Сохраняем получившееся в файл (ini,,0,TCAUTOCOMP_INI); // Уничтожение вспомогательного объекта (ini); } //========================================= // Чтение параметров модуля из INI-файла void TCAutoCompData::ReadFromIni(const char *IniFileName) { ini=(TRUE); // Загружаем текст из файла во вспомогательный объект (ini,,0,IniFileName); // Проверяем, нет ли ошибок if((ini,)) // Ошибка return; // Читаем строки из секции [Paths...] if((ini,"Paths" )) { char *CompPath_old=CompPath, // Старые значения *LinkPath_old=LinkPath, *IncludePath_old=IncludePath, *LibPath_old=LibPath; // Загружаем новые строки CompPath=((ini,"Compiler",CompPath_old,NULL)); LinkPath=((ini,"Linker",LinkPath_old,NULL)); IncludePath=((ini,"Include",IncludePath_old,NULL)); LibPath=((ini,"Lib",LibPath_old,NULL)); // Освобождаем старые строки (CompPath_old); (LinkPath_old); (IncludePath_old); (LibPath_old); // Добавление в пути CompSetPath=(ini,"CompilerToPaths",CompSetPath); LinkSetPath=(ini,"LinkerToPaths",LinkSetPath); } // Читаем строки из секции [Params...] if((ini,"Params" )) { char *CompParams_old=CompParams, // Старые значения *LinkParams_old=LinkParams; // Загружаем новые строки CompParams=((ini,"Compiler",CompParams_old,NULL)); LinkParams=((ini,"Linker",LinkParams_old,NULL)); // Освобождаем старые строки (CompParams_old); (LinkParams_old); } // Читаем строки из секции [Func...] if((ini,"Func" )) { char *DllMainName_old=DllMainName, // Старые значения *ModelFuncHdr_old=ModelFuncHdr, *Exported_old=Exported; // Загружаем новые строки DllMainName=((ini,"DllMain",DllMainName_old,NULL)); ModelFuncHdr=((ini,"ModelFunc",ModelFuncHdr_old,NULL)); Exported=((ini,"Exported",Exported_old,NULL)); // Освобождаем старые строки (DllMainName_old); (ModelFuncHdr_old); (Exported_old); } // Вспомогательный объект больше не нужен (ini); } //========================================= // Настройка модуля автокомпиляции // // // void TCAutoCompData::Setup(const char *IniFileName) { window; // Объект-окно const char exefilter[]= // Фильтр для диалога выбора файла "Исполняемые файлы (*.exe)|*.exe\nВсе файлы|*.*"; // Создание окна window=(TRUE,-1,-1,"Параметры модуля"); // Создание вкладки (window,0,"Пути"); // Поле ввода выбора EXE-файла компилятора (window,0,1,, "Компилятор:",300); (window,1,,exefilter); (window,1,,CompPath); // Нужно устанавливать путь? (window,0,100,, "Добавлять папку в путь",300); (window,100,,CompSetPath); // Поле ввода выбора EXE-файла редактора связей (window,0,2,, "Редактор связей:",300); (window,2,,exefilter); (window,2,,LinkPath); // Нужно устанавливать путь? (window,0,200,, "Добавлять папку в путь",300); (window,200,,LinkSetPath); // Выбор папки файлов заголовков (window,0,3,, "Папка заголовков:",300); (window,3,,IncludePath); // Выбор папки файлов библиотек (window,0,4,, "Папка библиотек:",300); (window,4,,LibPath); // Создание вкладки (window,1,"Параметры"); // Параметры командной строки компилятора (window,1,5,, "Параметры компилятора:",300); (window,5,,3*24);// Высота (window,5,,CompParams); // Параметры командной строки редактора связей (window,1,6,, "Параметры редактора связей:",300); (window,6,,3*24);// Высота (window,6,,LinkParams); // Создание вкладки (window,2,"Описания"); // Имя главной функции (window,2,7,, "Имя главной функции DLL:",300); (window,7,,DllMainName); // Заголовок модели (window,2,8,, "Заголовок функции модели:",300); (window,8,,2*24);// Высота (window,8,,ModelFuncHdr); // Экспортированное имя (window,2,9,, "Экспортированное имя:",300); (window,9,,Exported); // Открытие окна if((window,NULL)) // Нажата OK { // Освобождаем старые строки параметров FreeAllStrings(); // Делаем динамические копии всех строк из полей ввода // и присваиваем их полям класса #define GETDYNRELPATH(x) (x,(),NULL) CompPath=GETDYNRELPATH((window,1,)); LinkPath=GETDYNRELPATH((window,2,)); IncludePath=GETDYNRELPATH((window,3,)); LibPath=GETDYNRELPATH((window,4,)); #undef GETDYNRELPATH CompParams=((window,5,)); LinkParams=((window,6,)); DllMainName=((window,7,)); ModelFuncHdr=((window,8,)); Exported=((window,9,)); CompSetPath=(window,100,); LinkSetPath=(window,200,); // Запись изменившихся параметров в INI-файл WriteToIni(IniFileName); } // Уничтожение окна (window); } //=========================================
// Коды ошибок #define MEC_SIMPLEBLOCK 1 // Только для простых блоков #define MEC_READERROR 2 // Ошибка чтения файла #define MEC_NOTAMODEL 3 // Файл - не модель #define MEC_NOSECTIONS 4 // Нет нужных разделов в модели #define MEC_MODELWRITEERROR 5 // Ошибка записи файла модели //========================================= // Сообщение об ошибке в модели // // // void TCAutoCompData::( const char *modelname,int errorcode) { const char *errortext; // Сообщение по коду ошибки switch(errorcode) { case MEC_SIMPLEBLOCK: errortext="Модель может подключаться только к простому блоку"; break; case MEC_READERROR: errortext="Ошибка чтения файла"; break; case MEC_NOTAMODEL: errortext="Файл не является моделью блока"; break; case MEC_NOSECTIONS: errortext="В файле нет необходимых разделов"; break; case MEC_MODELWRITEERROR: errortext="Ошибка записи файла модели"; break; default: errortext="Неизвестная ошибка"; } // Название модели, если есть if(modelname) { char *msgtext; // Здесь формируется динамический текст msgtext=("Модель: ",modelname,FALSE); (&msgtext,"\n",FALSE); // Описание ошибки (&msgtext,errortext,FALSE); // Показываем сообщение (msgtext,"Автокомпиляция",MB_OK | MB_ICONWARNING); // Освобождаем память, занятую динамическим текстом (msgtext); } else (errortext,"Автокомпиляция",MB_OK | MB_ICONWARNING); } //=========================================
// Функция модуля автокомпиляции extern "C" __declspec(dllexport) int TestCAutoComp( int CallMode, // Событие ModuleData, // Данные модуля ExtParam) // Дополнительные параметры { // Приведение указателя на личную область данных // к правильному типу *data=(*)(ModuleData->ModuleData);
// Вспомогательная переменная – указатель на структуру // функции, вызванной из окна параметров funcdata;
switch(CallMode) { // Инициализация модуля case : // Создание личной области данных модуля ModuleData->ModuleData=data=new (); // Чтение параметров из INI-файла data->ReadFromIni(ModuleData->DataFile); break; // Очистка данных модуля case : delete data; // Удаление личной области модуля break; // Вызов окна настройки модуля case : data->Setup(ModuleData->DataFile); break;
// Получение поддерживаемых модулем функций // // // case : // Название поля ввода имени модели ("Файл исходного текста:"); // Разрешенные кнопки return | // Обзор ; // Новый
// Выполнить функцию case : // Что произошло в окне параметров funcdata=()ExtParam; switch(funcdata->Function) { // Нажата кнопка "Новый" case : data->(); break; // Нажата кнопка "Обзор" case : data->(funcdata->ModelName); break; } break;
// Проверка возможности присоединения модели к блоку case : return data->(()ExtParam);
// Открыть окно редактора case : data->(()ExtParam); break;
} return RDS_COMPR_DONE; } //=========================================
// Проверка возможности назначения модели блоку int TCAutoCompData::( *param) { blockdescr; ok; // Получаем описание блока, к которому подключается модель blockdescr.servSize=sizeof(blockdescr); (param->Block,&blockdescr); // Блок должен быть простого типа, иначе наша модель со // статическими переменными не сможет сним работать ok=(blockdescr.BlockType==); // Если модель подключается вручную, выводим сообщение if(param->AttachReason== && (!ok)) { (param->ModelName,MEC_SIMPLEBLOCK); return RDS_COMPR_ERRORNOMSG; // Без сообщения пользователю } return ok?RDS_COMPR_DONE:RDS_COMPR_ERROR; } //=========================================
// Записать строку текста в файл WriteString(HANDLE file,const char *text) { res,size; size=strlen(text); if(!WriteFile(file,text,size,&res,NULL)) return FALSE; return (res==size); } //=========================================
// Загрузка текстового файла в память // filename – имя файла, maxread – сколько читать или 0 // для чтения всего файла char *ReadTextFile(const char *filename, maxread) { HANDLE f; size,actread; char *fullpath,*buffer; ok=TRUE; fullpath_w; // Получаем полный путь к файлу fullpath=(filename,NULL,NULL); if(fullpath==NULL) // Нет пути - ошибка return NULL; // Преобразуем путь в UTF16 для Windows fullpath_w=(fullpath,FALSE); // Открываем файл для чтения f=CreateFileW(fullpath_w,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); (fullpath); // Имя файла больше не нужно (fullpath_w); if(f==INVALID_HANDLE_VALUE) // Ошибка открытия return NULL; // Определяем размер файла size=GetFileSize(f,NULL); if(size==0xFFFFFFFF) // Ошибка или слишком большой { CloseHandle(f); return NULL; } // Если есть ограничение, читаем только часть файла if(maxread!=0 && maxread<size) size=maxread; // Отводим память для загрузки файла buffer=(char*)(size+1); if(buffer==NULL) // Не удалось отвести { CloseHandle(f); return NULL; } // Считываем файл в память, если он не пустой if(size) { if(ReadFile(f,buffer,size,&actread,NULL)) ok=(actread==size); else ok=FALSE; } // Закрываем файл CloseHandle(f); if(!ok) // Ошибка чтения { (buffer); return NULL; } // Дописываем после конца считанного текста нулевой байт buffer[size]=0; return buffer; } //=========================================
// Создать новый пустой файл модели // // // void TCAutoCompData::CreateEmptyModel(void) { // Текст пустой модели const char *text=TCTEXTSECTION_START "\r\n" TCTEXTSECTION_VARS "\r\n" "struct\r\nbegin\r\n" " signal name \"Start\" in run default 1\r\n" " signal name \"Ready\" out default 0\r\n" "end\r\n" TCTEXTSECTION_PROG "\r\n"; char *relpath,*fullpath; HANDLE file; ok; fullpath_w; // Вызываем диалог сохранения relpath=("", |, "Текстовые файлы (*.txt)|*.txt\nВсе файлы|*.*", "txt", "Новая модель"); if(relpath==NULL) // Пользователь нажал "Отмена" return; // Преобразуем относительный путь в полный fullpath=(relpath,NULL,NULL); // Преобразуем путь в UTF16 для Windows fullpath_w=(fullpath,FALSE); // Открываем файл для записи file=CreateFileW(fullpath_w,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL); (fullpath); // Полный путь больше не нужен (fullpath_w); if(file==INVALID_HANDLE_VALUE) // Ошибка открытия ok=FALSE; else { ok=(file,text); CloseHandle(file); } if(!ok) // Ошибка { (relpath,MEC_MODELWRITEERROR); return; } // Пустой файл модели записан – устанавливаем его имя // в качестве имени модели блока (relpath); // Освобождаем динамическую строку (relpath); } //=========================================
// Выбрать файл модели // // // void TCAutoCompData::ConnectExistingModel(const char *oldmodel) { char *relpath,*buf; ok=FALSE; // Длина текста "$TESTCMODEL" int prefixlen=strlen(TCTEXTSECTION_START); // Вызываем диалог открытия файла relpath=(oldmodel, |, "Текстовые файлы (*.txt)|*.txt\nВсе файлы|*.*", "txt", "Файл модели"); if(relpath==NULL) // Пользователь нажал "Отмена" return; // Читаем начало файла: является ли он нашей моделью? buf=(relpath,prefixlen); if(buf==NULL) // Ошибка чтения (relpath,MEC_READERROR); else if(strcmp(buf,TCTEXTSECTION_START)) // Плохой префикс (relpath,MEC_NOTAMODEL); else ok=TRUE; (buf); // Считанный текст больше не нужен if(ok) // Делаем выбранный файл именем модели блока (relpath); (relpath); } //=========================================
// Найти ключевое слово в начале строки текста char *FindKeywordAtLineStart(char *text,const char *word) { char *s=text; // Устанавливаем s на начало текста if(text==NULL) return NULL; // Ищем в цикле for(;;) { s=strstr(s,word); // Ищем word начиная с s if(s==NULL) // Не найдено return NULL; if(s==text) // Найдено в начале текста - годится return s; // Найдено в середине текста - перед s должен находиться // перевод строки if(s[-1]=='\r' || s[-1]=='\n') // Есть перевод строки return s; // Перед s - другой символ. Продолжаем поиск } } //=========================================
// Разбить текст модели на описание переменных и текст программы ProcessModelText( char *text, // текст модели в памяти char **pVars, // возвращаемое начало переменных char **pProg) // возвращаемое начало программы { char *s,*s1; if(text==NULL || pVars==NULL || pProg==NULL) return FALSE; // Ищем "$VARS" в начале строки s=(text,TCTEXTSECTION_VARS); if(s==NULL) // Нет такой строки return FALSE; // Найдено - записываем в pVars начало текста после этого // слова с пропуском всех пустых строк s+=strlen(TCTEXTSECTION_VARS); // Пропускаем название секции s+=strspn(s,"\r\n"); // Пропускаем пустые строки после названия *pVars=s; // Ищем "$PROG" в начале строки оставшегося текста s1=(s,TCTEXTSECTION_PROG); if(s1==NULL) // Нет такой строки return FALSE; // Записываем в pProg начало текста после этого слова // с пропуском всех пустых строк s=s1+strlen(TCTEXTSECTION_PROG); // Пропускаем название s+=strspn(s,"\r\n"); // Пропускаем пустые строки после названия *pProg=s; // Для завершения предыдущей секции записываем нулевой байт // вместо '$' в "$PROG" *s1=0; return TRUE; } //=========================================
// Прототип функции обратного вызова окна редактора void TCAutoCompData_EditorCallback( window, // Объект-окно data); // Данные //=========================================
// Открыть редактор модели // // // void TCAutoCompData::OpenEditor( *param) { char *modelpath,*modeltext; char *vars,*prog; win; ok; // Полный путь к файлу модели modelpath=(param->Model->ModelName,NULL,NULL); // Читаем весь файл модели в память modeltext=(modelpath,0); if(modeltext==NULL) // Ошибка чтения { (param->Model->ModelName,MEC_READERROR); return; } // Разбиваем загруженный текст на описание переменных и программу if(!(modeltext,&vars,&prog)) { (modeltext); (param->Model->ModelName,MEC_NOSECTIONS); return; } // Создаем объект-окно редактора win=(FALSE,-1,-1,param->Model->ModelName); // Создаем в нем невизуальное поле и записываем в // него описание переменных (win,0,1000,,NULL,0); (win,1000,,vars); // Создаем кнопку для вызова редактора переменных (win,0,1,|, "Переменные:",150); (win,1,,"Изменить..."); // Создаем многострочное поле ввода для текста программы (win,0,2,, "Такт расчета:",600); (win,2,,prog); (win,2,,5*24);// Высота (win,2,,1); // Enter // Загруженный текст модели больше не нужен – мы все переписали в поля окна (modeltext); // Открываем окно (с функцией обратного вызова) ok=(win,); if(ok) { // Нажата кнопка "OK" - записываем текст модели в файл HANDLE file; modelpath_w=(modelpath,FALSE); file=CreateFileW(modelpath_w,GENERIC_WRITE,0,NULL, CREATE_ALWAYS,0,NULL); (modelpath_w); if(file==INVALID_HANDLE_VALUE) // Ошибка ok=FALSE; else // Записываем в файл { // Заголовок и секция переменных ok=(file,TCTEXTSECTION_START "\r\n" TCTEXTSECTION_VARS "\r\n"); // Описание переменных ok=ok && (file,(win,1000,)); // Секция текста программы ok=ok && (file,TCTEXTSECTION_PROG "\r\n"); // Текст программы ok=ok && (file,(win,2,)); CloseHandle(file); } if(!ok) (param->Model->ModelName,MEC_MODELWRITEERROR); } // Уничтожаем окно (win); // Освобождаем строку с именем файла модели (modelpath); } //=========================================
// Функция обратного вызова окна редактора модели // // // void TCAutoCompData_EditorCallback( window, data) { dv=NULL; vdescr; char *varstr; switch(data->Event) { case : // Нажата кнопка // Создаем объект для редактирования переменных dv=(); // Заполняем объект описанием переменных (поле 1000) if(!(dv, (window,1000,))) break; // Вызываем для объекта редактор переменных if(!(dv,TRUE,, 0,"Переменные блока")) break; // Пользователь нажал "OK" – получаем текст описания // измененных переменных vdescr.servSize=sizeof(vdescr); if(!(dv,-1,&vdescr)) break; varstr=(vdescr.Var,TRUE,0,NULL); if(varstr) { // Заносим обратно в поле 1000 (win,1000,,vars); (varstr); } break; } // Уничтожаем объект-редактор, если он был создан (dv); } //=========================================


<< >> Оглавление Указатель