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

Окончательный вариант исходного текста на языке C++ для библиотеки (DLL) с примером модуля автокомпиляции моделей блоков для языка C. Добавлен модуль поиска настроенных модулей автокомпиляции, совместимых по формату модели.

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

  #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;
  }
  //========= Конец главной функции =========

// Функция модуля автокомпиляции - поиск extern "C" __declspec(dllexport) int ( int CallMode, // Событие ModuleData, // Данные модуля ExtParam) // Дополнительные параметры { switch(CallMode) { // Инициализация модуля case : if(()) (ModuleData->ModelFormat); break; } return RDS_COMPR_DONE; } //=========================================
// Имена секций файла модели // Начало файла #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); }; // Сформировать в файле исходный текст программы WriteSourceCode(HANDLE file,const char *name, varset,const char *prog); // Загрузить и скомпилировать одну модель void LoadAndProcessModel( *data, int fileset, varsonly); // Сообщение об ошибке в модели static void ModelErrorMsg(const char *modelname,int errorcode); public: // Подготовиться к компиляции модели void PrepareToCompileModel( *param); // Компилировать модели void CompileModels( *param); // Связать блок с моделью void AttachBlock( *param);
// Модуль настроен (есть компилятор и редактор связей) (void) { return (CompPath,NULL,NULL,NULL) && (LinkPath,NULL,NULL,NULL); };
// Чтение параметров модуля из 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 // Ошибка записи файла модели #define MEC_BADVARS 6 // Ошибка в описаниях переменных #define MEC_SRCWRITEERROR 7 // Ошибка записи исходного текста программы #define MEC_NOOBJFILE 8 // Нет объектного файла #define MEC_COMPSTARTERROR 10 // Ошибка запуска компилятора #define MEC_NODLLFILE 11 // Нет файла DLL #define MEC_LINKSTARTERROR 12 // Ошибка запуска редактора связей #define MEC_DLLCOPYERROR 13 // Ошибка копирования DLL //========================================= // Сообщение об ошибке в модели // // // void TCAutoCompData::ModelErrorMsg( 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; case MEC_BADVARS: errortext="Ошибка в разделе описания переменных"; break; case MEC_SRCWRITEERROR: errortext="Невозможно создать файл исходного текста"; break; case MEC_NOOBJFILE: errortext="Объектный файл не создан - " "в тексте модели есть ошибки"; break; case MEC_COMPSTARTERROR: errortext="Ошибка запуска компилятора"; break; case MEC_NODLLFILE: errortext="Файл DLL не создан - " "в модели есть ошибки"; break; case MEC_LINKSTARTERROR: errortext="Ошибка запуска редактора связей"; break; case MEC_DLLCOPYERROR: errortext="Ошибка копирования полученного файла DLL"; 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 : return data->();
// Вызов окна настройки модуля 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; // Подготовка к компиляции case : data->PrepareToCompileModel(()ExtParam); break; // Компиляция моделей case : data->CompileModels(()ExtParam); break; // Присоединение модели к блоку case : data->AttachBlock(()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); } //========================================= // Получить время последней записи в файл (const char *filename,FILETIME *pLastWrite) { HANDLE file; ok=TRUE; // Преобразуем путь в UTF16 для Windows fullpath_w=(filename,FALSE); // Открываем файл для чтения file=CreateFileW(fullpath_w,GENERIC_READ,FILE_SHARE_READ, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); (fullpath_w); if(file==INVALID_HANDLE_VALUE) // К файлу нет доступа return FALSE; if(pLastWrite) { // Файл открыт - получаем время изменения ok=GetFileTime(file,NULL,NULL,pLastWrite); } CloseHandle(file); return ok; } //========================================= // Проверить необходимость компиляции DLL (const char *modelfile,const char *dllfile) { FILETIME modeltime,dlltime; // Получаем время изменения DLL if(!(dllfile,&dlltime)) return FALSE; // Файла DLL, вероятно, нет // Получаем время изменения файла модели if(!(modelfile,&modeltime)) return FALSE; // Нет доступа к файлу модели - ошибка // Если modeltime<=dlltime, можно не компилировать return CompareFileTime(&modeltime,&dlltime)<=0; } //========================================= // Запуск программы и ожидание ее завершения ( const char *path, // Имя EXE-файла const char *parameters, // Параметры командной строки const char **search, // Массив имен констант const char **replace) // Массив значений констант { char *cmd,*commandline,*tempdir; STARTUPINFO startup; // Структура параметров запуска процесса PROCESS_INFORMATION info; // Структура описания процесса ok=TRUE; commandline_w,tempdir_w; // Формирование полной командной строки cmd=("\"",path,FALSE); (&cmd,"\" ",FALSE); (&cmd,parameters,FALSE); (&cmd," ",FALSE); // Пробел (на всякий случай) // В cmd теперь - команда запуска, символические константы // в ней еще не обработаны // Заменяем все константы на их значения commandline=(cmd,search,replace, -1,); (cmd); // cmd больше не нужна // В commandline - полная командная строка запуска программы if(commandline==NULL) return FALSE; // Получение имени временной папки RDS без '\' tempdir=( (), ,NULL,NULL); // Заполнение структуры STARTUPINFO ZeroMemory(&startup,sizeof(STARTUPINFO)); startup.cb=sizeof(STARTUPINFO); // Запуск процесса commandline_w=(commandline,FALSE); tempdir_w=(tempdir,FALSE); if(!CreateProcessW(NULL,commandline_w,NULL,NULL,FALSE, 0,NULL,tempdir_w,&startup,&info)) ok=FALSE; // Запустить не получилось if(ok) { // Ждем завершения процесса WaitForSingleObject(info.hProcess,INFINITE); // Процесс завершен - закрываем полученные дескрипторы CloseHandle(info.hThread); CloseHandle(info.hProcess); } // Освобождаем все динамические строки (commandline); (tempdir); (commandline_w); (tempdir_w); return ok; } //========================================= // Запуск программы и ожидание ее завершения с возможным добавлением пути к exe-файлу в PATHS ( const char *path, // Имя EXE-файла const char *parameters, // Параметры командной строки const char **search, // Массив имен констант const char **replace, // Массив значений констант setpath) // Установить путь к exe в PATH { #define PATHVAR "Path" if(setpath) { char *exepath=(path,,NULL,NULL); char *oldpath=(PATHVAR); ok; if(oldpath) // Есть пути { char *newpath=NULL; (&newpath,exepath,FALSE); (&newpath,";",FALSE); (&newpath,oldpath,FALSE); (PATHVAR,newpath,FALSE); (newpath); } else // Было пусто (PATHVAR,exepath,FALSE); ok=(path,parameters,search,replace); if(oldpath) // Восстанавливаем (PATHVAR,oldpath,FALSE); (oldpath); (exepath); return ok; } return (path,parameters,search,replace); #undef PATHVAR } //========================================= // Подготовиться к компиляции модели void TCAutoCompData::( *param) { char *dllpath; // Получаем имя DLL с сокращенным путем для записи в параметры блока #ifdef dllpath=(param->Model->ModelName,,".dll64",NULL); #else dllpath=(param->Model->ModelName,,".dll32",NULL); #endif // Выясняем, нужно ли перекомпилировать DLL if(param->Rebuild) // Принудительно компилировать все param->Model->Valid=FALSE; else // Компилировать при необходимости { // Время последней записи DLL должно быть не меньше // времени записи текста модели char *modelpath,*dllfullpath; // Полный путь к файлу модели modelpath=( param->Model->ModelName,NULL,NULL); // Полный путь к файлу DLL dllfullpath=(dllpath,NULL,NULL); // Сравниваем времена последней записи param->Model->Valid=(modelpath,dllfullpath); // Освобождаем строки (modelpath); (dllfullpath); } // Записываем в параметры блоков библиотеку и функцию в ней, // которые получатся в результате компиляции (param->Model->Model,dllpath,Exported); (dllpath); } //========================================= // Компилировать все модели void TCAutoCompData::( *param) { // Проверяем необходимые параметры if(CompPath==NULL || LinkPath==NULL) return; // Компиляция невозможна // В цикле перебираем все модели из param->InvalidModels for(int i=0;i<param->IMCount;i++) { int tempset; // Создаем новый набор временных файлов tempset=(); // Компилируем модель (param->InvalidModels[i],tempset,FALSE); // Удаляем все созданные в процессе временные файлы (tempset); } } //========================================= // Сформировать в файле исходный текст программы TCAutoCompData::( HANDLE file, // дескриптор открытого файла const char *name, // имя модели (для сообщения) varset, // набор переменных const char *prog) // исходный текст реакции { ok; vdescr; char *undef=NULL; // Начальные описания и тип главной функции DLL ok=(file, "#include <windows.h>\r\n" "#include <stdlib.h>\r\n" "#include <math.h>\r\n" #ifdef ok=ok && (file,"#define \r\n"); #else ok=ok && (file,"#define \r\n"); #endif ok=ok && (file, "#include <RdsDef.h>\r\n" "#define RDS_SERV_FUNC_BODY GetServiceFunc\r\n" "#include <RdsFunc.h>\r\n" "double _HugeDouble;\r\n\r\n" // значение ошибки ); // Имя главной функции DLL (из настроек модуля) ok=ok && (file,DllMainName); // ok=ok && (file, "(HINSTANCE /*hinst*/,unsigned long reason," "void */*lpReserved*/)\r\n" "{ if(reason==DLL_PROCESS_ATTACH)\r\n" " { if(!RDS_SERV_FUNC_BODY())\r\n" " \r\n" " else\r\n" " (&_HugeDouble);\r\n" " }\r\n" " return 1;\r\n" "}\r\n\r\n"); // Заголовок функции блока (из настроек) ok=ok && (file,ModelFuncHdr); // Продолжение функции блока и проверка типов переменных ok=ok && (file, "(int CallMode, BlockData, ExtParam)\r\n" "{ switch(CallMode)\r\n" " { case :\r\n" " if(strcmp((char*)ExtParam,\""); // Строка типа переменных блока (из varset) ok=ok && (file, (varset,,0)); // Завершение проверки типа переменных ok=ok && (file, "\")) return ;\r\n" " break;\r\n"); // Такт расчета ok=ok && (file, " case :\r\n"); // Макрос для начала дерева переменных ok=ok && (file,"#define _pVarDataStart " " ((*)(BlockData->VarTreeData))\r\n"); // Макросы для переменных блока vdescr.servSize=sizeof(vdescr); if((varset,-1,&vdescr)) { // В vdescr теперь - описание всей структуры переменных блока const char *type; char *soff; int offset=0; int n=vdescr.StructFields; // Число полей // Записываем макрос для каждой переменной for(int i=0;i<n;i++) if((varset,i,&vdescr)) { // Получили описание i-й переменной блока switch(vdescr.Type) // Тип переменной { case : case : case : type="char"; break; case : type="short int"; break; case : type="RDSINT32"; break; case : type="float"; break; case : type="double"; break; default: // Тип не поддерживается // Смещение к следующей переменной offset+=vdescr.DataSize; continue; } if(i==0 && vdescr.Type!=) break; // Первая переменная - не сигнал // Продолжать не имеет смысла ok=ok && (file,"#define "); // Имя переменной ok=ok && (file,vdescr.Name); ok=ok && (file," (*(("); ok=ok && (file,type); ok=ok && (file,"*)(_pVarDataStart+"); // Смещение к переменной (offset) в виде строки soff=(offset,10,0); ok=ok && (file,soff); (soff); ok=ok && (file,")))\r\n"); // Смещение к следующей переменной offset+=vdescr.DataSize; // Добавление к undef директивы отмены этого макроса (&undef,"#undef ",FALSE); (&undef,vdescr.Name,FALSE); (&undef,"\r\n",FALSE); } // rdsVSGetVarDescription(varset,i,...)) } // if(rdsVSGetVarDescription(...) // Вставляем текст пользователя ok=ok && (file,"{\r\n"); ok=ok && (file,prog); ok=ok && (file,"\r\n}\r\n"); // Отмена макросов переменных if(undef!=NULL) { ok=ok && (file,undef); (undef); } // Отмена макроса начала дерева переменных ok=ok && (file,"#undef _pVarTreeDataStart\r\n"); // Завершение функции модели ok=ok && (file, " break;\r\n" " } \\ switch\r\n" " return ;\r\n" "}\r\n" ); return ok; } //========================================= // Получить размер файла по его имени (const char *filename) { HANDLE f; size; // Преобразуем путь в UTF16 для Windows fullpath_w=(filename,FALSE); // Открываем файл на чтение f=CreateFileW(fullpath_w,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); (fullpath_w); if(f==INVALID_HANDLE_VALUE) // Ошибка – нет файла return 0; // Получаем размер файла size=GetFileSize(f,NULL); // Закрываем файл CloseHandle(f); return size; } //========================================= // Загрузить и скомпилировать одну модель void TCAutoCompData::( *data, // структура данных модели int fileset, // набор временных файлов varsonly) // только установка переменных { char *modeltext,*dllpath,*aux; char *vars,*prog; char *st_srcfile; char *dyn_namenoext,*dyn_objfile1,*dyn_objfile2,*dyn_dllfile; varset; bdescr; ok=TRUE; // Массивы для автоматической замены строк const char *search[]={"$INCLUDE$", // 0 "$LIB$", // 1 "$NAME$", // 2 NULL}; const char *replace[sizeof(search)/sizeof(char*)]; bdescr.servSize=sizeof(bdescr); // Полный путь относительно RDS #define DYNFULLPATH(x) (x,(),NULL) // Читаем весь файл модели в память modeltext=(data->ModelName,0); if(modeltext==NULL) // Ошибка чтения { (data->ModelName,MEC_READERROR); return; } // Файл модели считан в modeltext - разбиваем на секции vars и prog if(!(modeltext,&vars,&prog)) { (modeltext); (data->ModelName,MEC_NOSECTIONS); return; } // Создаем объект для работы с переменными varset=(); // Записываем в объект получившийся текст описания переменных if(!(varset,vars)) { (modeltext); (varset); (data->ModelName,MEC_BADVARS); return; } // Копируем переменные во все блоки, к которым подключена модель for(int i=0;i<data->NBlocks;i++) { // Берем очередной блок в списке блоков модели block=(data->Model,i,&bdescr); if(block==NULL) continue; if(bdescr.BlockType!=) continue; // Только для простых блоков // Записываем переменные в блок (varset,block,NULL); } if(varsonly) { // Нужно только установить переменные, компилировать не нужно (modeltext); (varset); return; } // Формирование исходного текста компилируемой библиотеки st_srcfile=(fileset,"$TEMP$\\model.cpp"); // В st_srcfile - указатель на имя созданного временного // файла (строка имени находится во внутренней памяти RDS) if(st_srcfile) { fullpath_w=(st_srcfile,FALSE); HANDLE file=CreateFileW(fullpath_w,GENERIC_WRITE, 0,NULL,CREATE_ALWAYS,0,NULL); (fullpath_w); if(file==INVALID_HANDLE_VALUE) // Ошибка ok=FALSE; else { // Записываем в файл исходный текст программы ok=(file,varset,prog); CloseHandle(file); } } if(!ok) (data->ModelName,MEC_SRCWRITEERROR); // Текст модели и cписок переменных больше не нужны (modeltext); (varset); // Формирование имени файла без расширения и пути aux=(st_srcfile,,"",NULL); dyn_namenoext=(aux,,NULL,NULL); (aux); // Запоминание имен временных файлов, формируемых компилятором, // и создание пустых для дальнейшей проверки (fileset, dyn_objfile1=(st_srcfile,,".obj",NULL)); (fileset, dyn_objfile2=(st_srcfile,,".o",NULL)); (fileset, dyn_dllfile=(st_srcfile,,".dll",NULL)); (fileset, aux=(st_srcfile,,".lib",NULL)); (aux); (fileset, aux=(st_srcfile,,".tds",NULL)); (aux); // Занесение различных путей в список замены replace replace[0]=IncludePath; // "$INCLUDE$" replace[1]=LibPath; // "$LIB$" replace[2]=dyn_namenoext; // "$NAME$" // Запуск компилятора if(ok) { char *fullpath=DYNFULLPATH(CompPath); if((fullpath,CompParams,search,replace,CompSetPath)) { // Проверяем наличие .obj if((dyn_objfile1)==0 && (dyn_objfile2)==0) // Нулевого размера { ok=FALSE; (data->ModelName,MEC_NOOBJFILE); } } else // Ошибка запуска { ok=FALSE; (data->ModelName,MEC_COMPSTARTERROR); } (fullpath); } // Запуск редактора связей if(ok) { char *fullpath=DYNFULLPATH(LinkPath); if((fullpath,LinkParams,search,replace,LinkSetPath)) { // Проверяем наличие .dll if((dyn_dllfile)==0) // Нулевого размера { ok=FALSE; (data->ModelName,MEC_NODLLFILE); } } else // Ошибка запуска { ok=FALSE; (data->ModelName,MEC_LINKSTARTERROR); } (fullpath); } // Полный путь к файлу DLL (куда ссылается блок) dllpath=(data->CompDllName,NULL,NULL); // Копируем созданный во временной директории файл DLL в папку модели if(ok) { from_w=rdsUTF8toUTF16(dyn_dllfile,FALSE), to_w=rdsUTF8toUTF16(dllpath,FALSE); ok=CopyFileW(from_w,to_w,FALSE); (from_w); (to_w); if(!ok) (data->ModelName,MEC_DLLCOPYERROR); } // Освобождаем динамически созданные пути ((void*)(replace[0])); ((void*)(replace[1])); (dyn_namenoext); (dyn_objfile1); (dyn_objfile2); (dyn_dllfile); (dllpath); #undef DYNFULLPATH } //========================================= // Связать блок с моделью void TCAutoCompData::( *param) { // Если модель устанавливается пользователем вручную, // нужно поменять у блока структуру переменных if(param->AttachReason==) (param->Model,-1,TRUE); } //=========================================


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