Текущий раздел:

Описания RDS

Руководство программиста

Глава 3. Создание модулей автоматической компиляции

§3.2. Инициализация, очистка и настройка параметров модуля

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

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

      // Класс личной области данных модуля автокомпиляции
      class TCAutoCompData
      { private:
          // Пути
          char *CompPath;     // к компилятору
          char *LinkPath;     // к редактору связей (link)
          char *IncludePath;  // к файлам заголовков
          char *LibPath;      // к библиотекам
          // Нужно ли добавлять путь к exe-файлу компилятора и редактора связей
          BOOL CompSetPath,LinkSetPath;
          // Параметры командной строки
          char *CompParams;   // компилятора
          char *LinkParams;   // редактора связей
          // Параметры исходного текста
          char *DllMainName;  // имя главной функции DLL
          char *ModelFuncHdr; // заголовок функции модели
          char *Exported;     // экспортированное имя функции

          // Освободить все динамические строки
          void FreeAllStrings(void)
            { rdsFree(CompPath);
              rdsFree(LinkPath);
              rdsFree(IncludePath);
              rdsFree(LibPath);
              rdsFree(CompParams);
              rdsFree(LinkParams);
              rdsFree(DllMainName);
              rdsFree(ModelFuncHdr);
              rdsFree(Exported);
            };

        public:
          // Чтение параметров модуля из INI-файла
          void ReadFromIni(const char *IniFileName);
          // Запись параметров модуля в INI-файл
          void WriteToIni(const char *IniFileName);
          // Настройка параметров модуля
          void Setup(const char *IniFileName);

          // Конструктор класса
          TCAutoCompData(void)
          { IncludePath=LibPath=NULL;
            CompSetPath=LinkSetPath=TRUE;
            #ifdef RDS_WIN64
              CompPath=rdsDynStrCopy(
                "$RDS$\\mingw-w64\\bin\\g++.exe");
              LinkPath=rdsDynStrCopy(CompPath);
              CompParams=rdsDynStrCopy(
                "-Wall -m64 -g -I\"$RDSINCLUDE$\" -c \"$TEMP$\\$NAME$.cpp\" -o \"$TEMP$\\$NAME$.o\""
                );
              LinkParams=rdsDynStrCopy(
                "-shared -static -static-libgcc -static-libstdc++ -Wl,--dll \"$TEMP$\\$NAME$.o\" -o \"$TEMP$\\$NAME$.dll\" -s -m64 -luser32"
                );
              DllMainName=rdsDynStrCopy("extern \"C\" __declspec(dllexport) BOOL APIENTRY DllMain");
              ModelFuncHdr=rdsDynStrCopy(
                "extern \"C\" __declspec(dllexport) int RDSCALL autocompModelFunc"
                );
              Exported=rdsDynStrCopy("autocompModelFunc");
            #else
              CompPath=rdsDynStrCopy(
                "$RDS$\\tdm-gcc\\bin\\g++.exe");
              LinkPath=rdsDynStrCopy(CompPath);
              CompParams=rdsDynStrCopy(
                "-shared -fpermissive -c -I\"$RDSINCLUDE$\" \"$TEMP$\\$NAME$.cpp\""
                );
              LinkParams=rdsDynStrCopy(
                "-shared -static -static-libgcc -static-libstdc++ -o \"$TEMP$\\$NAME$.dll\" \"$TEMP$\\$NAME$.o\""
                );
              DllMainName=rdsDynStrCopy("extern \"C\" BOOL WINAPI DllMain");
              ModelFuncHdr=rdsDynStrCopy(
                "extern \"C\" __declspec(dllexport) int RDSCALL autocompModelFunc");
              Exported=rdsDynStrCopy("autocompModelFunc@12");
            #endif
          };
          // Деструктор класса
          ~TCAutoCompData(){ FreeAllStrings(); };
      };
      //=========================================

      // Запись параметров модуля в INI-файл
      void TCAutoCompData::WriteToIni(const char *IniFileName)
      { RDS_HOBJECT ini=rdsINICreateTextHolder(TRUE);

        // Загружаем старый текст из файла во вспомогательный объект, если он есть
        if(rdsFileExists(IniFileName,NULL,NULL,NULL))
          rdsSetObjectStr(ini,RDS_HINI_LOADFILE,0,IniFileName);

        // Создаем секцию [Paths...]
        rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Paths" RDS_PLATFORMNAME);
        // Записываем в нее пути
        rdsINIWriteString(ini,"Compiler",CompPath);
        rdsINIWriteString(ini,"Linker",LinkPath);
        rdsINIWriteString(ini,"Include",IncludePath);
        rdsINIWriteString(ini,"Lib",LibPath);
        rdsINIWriteBool(ini,"CompilerToPaths",CompSetPath);
        rdsINIWriteBool(ini,"LinkerToPaths",LinkSetPath);

        // Создаем секцию [Params...]
        rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Params" RDS_PLATFORMNAME);
        // Записываем в нее параметры командной строки
        rdsINIWriteString(ini,"Compiler",CompParams);
        rdsINIWriteString(ini,"Linker",LinkParams);

        // Создаем секцию [Func...]
        rdsSetObjectStr(ini,RDS_HINI_CREATESECTION,0,"Func" RDS_PLATFORMNAME);
        // Записываем в нее остальные параметры
        rdsINIWriteString(ini,"DllMain",DllMainName);
        rdsINIWriteString(ini,"ModelFunc",ModelFuncHdr);
        rdsINIWriteString(ini,"Exported",Exported);

        // Сохраняем получившееся в файл
        rdsSetObjectStr(ini,RDS_HINI_SAVEFILE,0,TCAUTOCOMP_INI);

        // Уничтожение вспомогательного объекта
        rdsDeleteObject(ini);
      }
      //=========================================

      // Чтение параметров модуля из INI-файла
      void TCAutoCompData::ReadFromIni(const char *IniFileName)
      { RDS_HOBJECT ini=rdsINICreateTextHolder(TRUE);

        // Загружаем текст из файла во вспомогательный объект
        rdsSetObjectStr(ini,RDS_HINI_LOADFILE,0,IniFileName);
        // Проверяем, нет ли ошибок
        if(rdsCommandObject(ini,RDS_HINI_GETLASTERROR)) // Ошибка
          return;

        // Читаем строки из секции [Paths...]
        if(rdsINIOpenSection(ini,"Paths" RDS_PLATFORMNAME))
          { char *CompPath_old=CompPath, // Старые значения
                 *LinkPath_old=LinkPath,
                 *IncludePath_old=IncludePath,
                 *LibPath_old=LibPath;
            // Загружаем новые строки
            CompPath=rdsDynStrCopy(rdsINIReadString(ini,"Compiler",CompPath_old,NULL));
            LinkPath=rdsDynStrCopy(rdsINIReadString(ini,"Linker",LinkPath_old,NULL));
            IncludePath=rdsDynStrCopy(rdsINIReadString(ini,"Include",IncludePath_old,NULL));
            LibPath=rdsDynStrCopy(rdsINIReadString(ini,"Lib",LibPath_old,NULL));
            // Освобождаем старые строки
            rdsFree(CompPath_old);
            rdsFree(LinkPath_old);
            rdsFree(IncludePath_old);
            rdsFree(LibPath_old);
            // Добавление в пути
            CompSetPath=rdsINIReadBool(ini,"CompilerToPaths",CompSetPath);
            LinkSetPath=rdsINIReadBool(ini,"LinkerToPaths",LinkSetPath);
          }

        // Читаем строки из секции [Params...]
        if(rdsINIOpenSection(ini,"Params" RDS_PLATFORMNAME))
          { char *CompParams_old=CompParams, // Старые значения
                 *LinkParams_old=LinkParams;
            // Загружаем новые строки
            CompParams=rdsDynStrCopy(rdsINIReadString(ini,"Compiler",CompParams_old,NULL));
            LinkParams=rdsDynStrCopy(rdsINIReadString(ini,"Linker",LinkParams_old,NULL));
            // Освобождаем старые строки
            rdsFree(CompParams_old);
            rdsFree(LinkParams_old);
          }

        // Читаем строки из секции [Func...]
        if(rdsINIOpenSection(ini,"Func" RDS_PLATFORMNAME))
          { char *DllMainName_old=DllMainName, // Старые значения
                 *ModelFuncHdr_old=ModelFuncHdr,
                 *Exported_old=Exported;
            // Загружаем новые строки
            DllMainName=rdsDynStrCopy(rdsINIReadString(ini,"DllMain",DllMainName_old,NULL));
            ModelFuncHdr=rdsDynStrCopy(rdsINIReadString(ini,"ModelFunc",ModelFuncHdr_old,NULL));
            Exported=rdsDynStrCopy(rdsINIReadString(ini,"Exported",Exported_old,NULL));
            // Освобождаем старые строки
            rdsFree(DllMainName_old);
            rdsFree(ModelFuncHdr_old);
            rdsFree(Exported_old);
          }
        // Вспомогательный объект больше не нужен
        rdsDeleteObject(ini);
      }
      //=========================================

      // Настройка модуля автокомпиляции
      // ВАЖНО: Исходный текст программы должен быть записан в UTF8,
      //   в противном случае необходимо использовать версии функций
      //   с суффиксом "W" и символьные константы с префиксом "L"
      void TCAutoCompData::Setup(const char *IniFileName)
      { RDS_HOBJECT window;	// Объект-окно
        const char exefilter[]=	// Фильтр для диалога выбора файла
               "Исполняемые файлы (*.exe)|*.exe\nВсе файлы|*.*";

        // Создание окна
        window=rdsFORMCreate(TRUE,-1,-1,"Параметры модуля");

        // Создание вкладки
        rdsFORMAddTab(window,0,"Пути");

        // Поле ввода выбора EXE-файла компилятора
        rdsFORMAddEdit(window,0,1,RDS_FORMCTRL_OPENDIALOG,
            "Компилятор:",300);
        rdsSetObjectStr(window,1,RDS_FORMVAL_LIST,exefilter);
        rdsSetObjectStr(window,1,RDS_FORMVAL_VALUE,CompPath);

        // Нужно устанавливать путь?
        rdsFORMAddEdit(window,0,100,RDS_FORMCTRL_CHECKBOX,
            "Добавлять папку в путь",300);
        rdsSetObjectInt(window,100,RDS_FORMVAL_VALUE,CompSetPath);

        // Поле ввода выбора EXE-файла редактора связей
        rdsFORMAddEdit(window,0,2,RDS_FORMCTRL_OPENDIALOG,
            "Редактор связей:",300);
        rdsSetObjectStr(window,2,RDS_FORMVAL_LIST,exefilter);
        rdsSetObjectStr(window,2,RDS_FORMVAL_VALUE,LinkPath);

        // Нужно устанавливать путь?
        rdsFORMAddEdit(window,0,200,RDS_FORMCTRL_CHECKBOX,
            "Добавлять папку в путь",300);
        rdsSetObjectInt(window,200,RDS_FORMVAL_VALUE,LinkSetPath);

        // Выбор папки файлов заголовков
        rdsFORMAddEdit(window,0,3,RDS_FORMCTRL_DIRDIALOG,
            "Папка заголовков:",300);
        rdsSetObjectStr(window,3,RDS_FORMVAL_VALUE,IncludePath);

        // Выбор папки файлов библиотек
        rdsFORMAddEdit(window,0,4,RDS_FORMCTRL_DIRDIALOG,
            "Папка библиотек:",300);
        rdsSetObjectStr(window,4,RDS_FORMVAL_VALUE,LibPath);

        // Создание вкладки
        rdsFORMAddTab(window,1,"Параметры");

        // Параметры командной строки компилятора
        rdsFORMAddEdit(window,1,5,RDS_FORMCTRL_MULTILINE,
            "Параметры компилятора:",300);
        rdsSetObjectInt(window,5,RDS_FORMVAL_MLHEIGHT,3*24);// Высота
        rdsSetObjectStr(window,5,RDS_FORMVAL_VALUE,CompParams);

        // Параметры командной строки редактора связей
        rdsFORMAddEdit(window,1,6,RDS_FORMCTRL_MULTILINE,
            "Параметры редактора связей:",300);
        rdsSetObjectInt(window,6,RDS_FORMVAL_MLHEIGHT,3*24);// Высота
        rdsSetObjectStr(window,6,RDS_FORMVAL_VALUE,LinkParams);

        // Создание вкладки
        rdsFORMAddTab(window,2,"Описания");

        // Имя главной функции
        rdsFORMAddEdit(window,2,7,RDS_FORMCTRL_EDIT,
            "Имя главной функции DLL:",300);
        rdsSetObjectStr(window,7,RDS_FORMVAL_VALUE,DllMainName);

        // Заголовок модели
        rdsFORMAddEdit(window,2,8,RDS_FORMCTRL_MULTILINE,
            "Заголовок функции модели:",300);
        rdsSetObjectInt(window,8,RDS_FORMVAL_MLHEIGHT,2*24);// Высота
        rdsSetObjectStr(window,8,RDS_FORMVAL_VALUE,ModelFuncHdr);

        // Экспортированное имя
        rdsFORMAddEdit(window,2,9,RDS_FORMCTRL_EDIT,
            "Экспортированное имя:",300);
        rdsSetObjectStr(window,9,RDS_FORMVAL_VALUE,Exported);

        // Открытие окна
        if(rdsFORMShowModalEx(window,NULL)) // Нажата OK
          { // Освобождаем старые строки параметров
            FreeAllStrings();

            // Делаем динамические копии всех строк из полей ввода
            // и присваиваем их полям класса
            #define GETDYNRELPATH(x) rdsGetRelFilePath(x,rdsGetSystemPath(RDS_GSPAPPPATH),NULL)
              CompPath=GETDYNRELPATH(rdsGetObjectStr(window,1,RDS_FORMVAL_VALUE));
              LinkPath=GETDYNRELPATH(rdsGetObjectStr(window,2,RDS_FORMVAL_VALUE));
              IncludePath=GETDYNRELPATH(rdsGetObjectStr(window,3,RDS_FORMVAL_VALUE));
              LibPath=GETDYNRELPATH(rdsGetObjectStr(window,4,RDS_FORMVAL_VALUE));
            #undef GETDYNRELPATH

            CompParams=rdsDynStrCopy(rdsGetObjectStr(window,5,RDS_FORMVAL_VALUE));
            LinkParams=rdsDynStrCopy(rdsGetObjectStr(window,6,RDS_FORMVAL_VALUE));
            DllMainName=rdsDynStrCopy(rdsGetObjectStr(window,7,RDS_FORMVAL_VALUE));
            ModelFuncHdr=rdsDynStrCopy(rdsGetObjectStr(window,8,RDS_FORMVAL_VALUE));
            Exported=rdsDynStrCopy(rdsGetObjectStr(window,9,RDS_FORMVAL_VALUE));

            CompSetPath=rdsGetObjectInt(window,100,RDS_FORMVAL_VALUE);
            LinkSetPath=rdsGetObjectInt(window,200,RDS_FORMVAL_VALUE);

            // Запись изменившихся параметров в INI-файл
            WriteToIni(IniFileName);
          }
        // Уничтожение окна
        rdsDeleteObject(window);
      }
      //=========================================

      // Функция модуля автокомпиляции
      extern "C" __declspec(dllexport) int RDSCALL TestCAutoComp(
          int CallMode,                   // Событие
          RDS_PCOMPMODULEDATA ModuleData, // Данные модуля
          LPVOID ExtParam)                // Дополнительные параметры
      { // Приведение указателя на личную область данных
        // к правильному типу
        TCAutoCompData *data=(TCAutoCompData*)(ModuleData->ModuleData);

        switch(CallMode)
          { // Инициализация модуля
            case RDS_COMPM_INIT:
              // Создание личной области данных модуля
              ModuleData->ModuleData=data=new TCAutoCompData();
              // Чтение параметров из INI-файла
              data->ReadFromIni(ModuleData->DataFile);
              break;

            // Очистка данных модуля
            case RDS_COMPM_CLEANUP:
              delete data;	// Удаление личной области модуля
              break;

            // Вызов окна настройки модуля
            case RDS_COMPM_SETUP:
              data->Setup(ModuleData->DataFile);
              break;
          }
        return RDS_COMPR_DONE;
      }
      //=========================================