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

Описания RDS

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

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

§3.5. Поиск совместимых модулей

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

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

### §3.5. Поиск совместимых модулей

Рассматривается создание модуля-заглушки, который ищет среди зарегистрированных настроенный модуль, работающий с моделями с той же строкой формата.

Модулей автокомпиляции может быть существенно больше, чем различных форматов поддерживаемых ими моделей. Обычно модуль создается под конкретный компилятор или семейство компиляторов, а формат модели – под набор функций, доступных пользвателю. Поэтому разные модули, предназначенные для разных компиляторов, могут работать с одними и теми же моделями. Например, среди стандартных модулей автокомпиляции есть рассчитанные на компиляторы C++ MinGW, OpenWatcom, Borland, и все они работают с одним и тем же форматом файла модели. Это позволяет не переделывать модель под конкретный компилятор, установленный у пользователя.

Однако, здесь могла бы возникнуть проблема. При подключении к блоку автокомпилируемой модели в окне параметров этого блока указывается название конкретного модуля автокомпиляции, который будет работать с этой моделью. В файле схемы для этого блока также сохраняется ссылка на конкретный модуль, выбранный пользователем. Поэтому при переносе схемы с машины, на которой установлен один компилятор, на машину, на которой установлен другой, пришлось бы менять названия модуля автокомпиляции для каждого блока. Хотя это можно достаточно быстро сделать при помощи групповой установки параметров блоков, это сильно осложнило бы жизнь пользователю.

Чтобы избежать перенастройки схемы под разные модули автокомпиляции с общим форматом модели, в описание модуля добавлена строка формата модели. Кроме того, сервисные функции RDS позволяют создать такой модуль автокомпиляции («модуль поиска»), который сам ничего не делает, а, вместо этого, просит RDS подключить вместо себя другой модуль, который может работать с моделью такого формата.

Может показаться, что для подключения модуля, работающего с заданным форматом модели, не нужен специальный «модуль поиска», у RDS достаточно информации, чтобы сделать это самостоятельно. Однако, это привело бы к несовместимости со схемами, созданными в старых версиях RDS, где формат модели не поддерживался. В параметрах блока, хранящихся в файле схемы, модуль автокомпиляции указывается как пара «имя_DLL, имя_функции», поэтому с каждым блоком должена быть связана конкретная исполняемая функция модуля в конкретной библиотеке. Замена указания на модуль указанием на формат модели нарушила бы обратную совместимость. Именно поэтому необходим модуль поиска – указание на него будет находиться в файле схемы, а он уже будет подключать другой модуль, совместимый по формату модели.

Крайне желательно, чтобы модуль поиска выбрал из всех доступных модулей автокомпиляции с подходящим форматом модели тот, который действительно может скомпилировать модель. То есть правильно настроенный модуль, компилятор для которого установлен на машине пользователя. Для выполнения такой проверки модули автокомпиляции вызываются с параметром RDS_COMPM_SETUPISOK: в ответ на этот вызов функция модуля должна вернуть ненулевое значение (например, «TRUE») только в том случае, если модуль может успешно компилировать модели. В противном случае возвращается ноль.

Добавим в класс личной области данных TCAutoCompData нашего модуля функцию-член CanWork для проверки правильности настройки модуля. Будем считать модуль правильно настроенным, если существуют файлы компилятора и редактора связей, пути к которым указаны в параметрах CompPath и LinkPath соответственно.

      // Класс личной области данных модуля автокомпиляции
      class TCAutoCompData
      { private:
          // … без изменений …

        public:
          // Подготовиться к компиляции модели
          void PrepareToCompileModel(RDS_COMPPREPAREDATA *param);
          // Компилировать модели
          void CompileModels(RDS_COMPILEDATA *param);
          // Связать блок с моделью
          void AttachBlock(RDS_COMPBLOCKOPDATA *param);

          // Модуль настроен (есть компилятор и редактор связей)
          BOOL CanWork(void)
            { return rdsFileExists(CompPath,NULL,NULL,NULL) &&
                     rdsFileExists(LinkPath,NULL,NULL,NULL);
            };
          // … без изменений …

          // Деструктор класса
          ~TCAutoCompData(){ FreeAllStrings(); };
      };
      //=========================================

Для проверки существования файла используется сервисная функция RDS rdsFileExists. Она может принимать аргумент с символическими константами путей (у нас в настройках модуля они используются) и возвращает истину, если файл существует.

Теперь добавим реакцию на RDS_COMPM_SETUPISOK в функцию модуля – эта реакция будет простой.

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

            // Модуль настроен?
            case RDS_COMPM_SETUPISOK:
              return data->CanWork();
            // … без изменений …
          }
        return RDS_COMPR_DONE;
      }
      //=========================================

Теперь наш модуль может сообщать RDS о своей способности компилировать модели. Создадим в той же самой DLL новый модуль автокомпиляции, который будет нашим «модулем поиска». Его функция будет очень простой, поскольку все действия по поиску и подключению совместимого настроенного модуля на самом деле выполняет RDS.

      // Функция модуля автокомпиляции - поиск
      extern "C" __declspec(dllexport) int RDSCALL TestCAutoCompSearch(
          int CallMode,                   // Событие
          RDS_PCOMPMODULEDATA ModuleData, // Данные модуля
          LPVOID ExtParam)                // Дополнительные параметры
      {
        switch(CallMode)
          { // Инициализация модуля
            case RDS_COMPM_INIT:
              if(rdscompLinkModuleAllowed())
                rdscompLinkAvailableModule(ModuleData->ModelFormat);
              break;
          }
        return RDS_COMPR_DONE;
      }
      //=========================================

Здесь при инициализации модуля сначала вызывается функция rdscompLinkModuleAllowed – она возвращает значение «истина», если в данный момент разрешено выполнять поиск совместимых модулей. Такая проверка нужна для того, чтобы RDS не нашел в качестве допустимого варианта этот же модуль, который только что вызвал поиск. Если поиск разрешен, вызывается функция rdscompLinkAvailableModule в которую передается строка формата модели из поля ModelFormat структуры RDS_COMPMODULEDATA (ModuleData->ModelFormat). Больше никаких действий производить не нужно, все остальное будет выполнено автоматически.

Теперь нужно зарегистрировать модуль поиска в RDS, создав для него файл описания модуля. При ранее сделанных предположениях о компиляции и размещении DLL нашего примера, файл описания нового модуля будет выглядеть следующим образом:

      autocomp
        file "$INI$\\UserExtensions\\AutoComp\\p3.32.dll" func "TestCAutoCompSearch@12"
        file64 "$INI$\\UserExtensions\\AutoComp\\p3.64.dll" func64 "TestCAutoCompSearch"
        title default "Поиск среди настроенных тестовых"
        title English "Any test module"
        format "ProgrammersManual.CPlusPlus.Test"
        seq 20000

Если назвать этот файл, например, «progman_sample_search.acm» и поместить его в «UserExtensions\AutoComp\», в списке модулей автокомпиляции появится новый модуль с названием «Поиск среди настроенных тестовых», причем по умолчанию он будет находиться непосредственно перед созданным нами основным модулем с названием «Тестовый модуль из руководства». Это связано с тем, что для основного модуля мы установили порядковый номер («seq») 20001, а для нового – 20000. И у нового, и у старого модулей указана строка формата модели «ProgrammersManual.CPlusPlus.Test», поэтому новый модуль поиска можно подключать к любому блоку вместо старого основного. Это не повлияет работу схемы, поскольку на самом деле компиляцией моделей будет заниматься не новый модуль (он этого не умеет), а старый. Если, в дальнейшем, будет создан еще один модуль с той же строкой формата модели, он также сможет выполнять компиляцию вместо модуля поиска.