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

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

Глава 2. Создание моделей блоков

§2.4. Инициализация и очистка данных блока

Описывается событие инициализации RDS_BFM_INIT – самое первое событие в «жизни» модели блока, и событие очистки RDS_BFM_CLEANUP – самое последнее. Приводится пример модели, отводящей себе память под личные нужды при инициализации и освобождающей ее при очистке.

Самое первое событие, на которое реагирует блок – это событие инициализации RDS_BFM_INIT. Оно возникает в момент подключения модели к блоку, то есть при загрузке блока из файла в составе схемы, при вставке блока из буфера обмена, при указании новой модели в окне параметров блока и т.п. Как только конкретному блоку схемы ставится в соответствие конкретная функция модели, эта функция вызывается для данного блока с параметром RDS_BFM_INIT. Обычно этот вызов используется для создания личной области данных блока – области памяти, используемой моделью по своему усмотрению. В C личная область данных чаще всего представляет собой структуру, а в C++ – объект какого-либо класса. В личной области хранятся параметры блока, которые неудобно или невозможно хранить в статических переменных – строки, вспомогательные объекты, информация о динамических переменных, с которыми работает блок, и т.п. При инициализации модель должна отвести память под личную область данных (например, функцией malloc или оператором new) и присвоить указатель на созданную область полю BlockData структуры данных блока RDS_BLOCKDATA, указатель на которую передается в функцию модели через параметр BlockData при каждом вызове.

Событие очистки RDS_BFM_CLEANUP – это самое последнее событие, на которое может среагировать блок. Оно возникает тогда, когда по какой-либо причине модель отключается от блока: при удалении блока пользователем, при очистке памяти в момент завершения RDS или при загрузке новой схемы, перед подключением к блоку новой модели и т.п. Если при реакции на была создана личная область данных, при реакции на RDS_BFM_CLEANUP она должна быть удалена.

В качестве примера рассмотрим модель блока, работающую с личной областью, в которой будут храниться два параметра: целый IParam и вещественный DParam (пример не имеет практического применения, он просто иллюстрирует реакцию блока на события инициализации и очистки). В этом примере будет приведена и главная функция DLL, и модель блока. В дальнейшем в приводимых примерах главная функция DLL чаще всего будет опущена.

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

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

  //====== Класс личной области данных ======
  class TTest1Data
  { public:
      int IParam;       // Целый параметр
      double DParam;    // Вещественный параметр
      TTest1Data(void)  // Конструктор класса
        { IParam=0; DParam=0.0;
          (L"Область создана",L"TTest1Data",MB_OK);
        };
      ~TTest1Data()     // Деструктор класса
        { (L"Область удалена",L"TTest1Data",MB_OK);};
  };
  //=========================================

  //============= Модель блока ==============
  extern "C" __declspec(dllexport)
    int  Test1(int CallMode,
                       BlockData,
                       ExtParam)
  { TTest1Data *data;
    switch(CallMode)
      { case :    // Инициализация
          BlockData->BlockData=new TTest1Data();
          break;
        case : // Очистка
          data=(TTest1Data*)(BlockData->BlockData);
          delete data;
          break;
      }
    return ;
  }
  //=========================================

Перед функцией модели блока находится описание класса TTest1Data, объект которого используется блоком в качестве личной области данных. В конструкторе и деструкторе класса (функциях, автоматически вызываемых при создании и уничтожении объекта соответственно) вызывается сервисная функция rdsMessageBoxW, выводящая сообщение о создании и удалении объекта. Функция модели Test1 реагирует всего на два события: инициализации RDS_BFM_INIT и очистки RDS_BFM_CLEANUP. При вызове функции с параметром RDS_BFM_INIT создается объект TTest1Data, указатель на который присваивается полю структуры данных блока BlockData. При вызове функции с параметром RDS_BFM_CLEANUP значение BlockData->BlockData приводится к типу «указатель на TTest1Data» (для ясности примера в функцию модели введена вспомогательная переменная data), после чего созданный при инициализации объект уничтожается.

Чтобы проверить работоспособность этого примера необходимо скомпилировать DLL с этой моделью, запустить RDS, создать новую схему и создать в ней новый простой блок (пункт «Создать | Новый блок» в контекстном меню или в меню редактирования). Затем необходимо открыть окно параметров этого блока (пункт «Параметры» в контекстном меню блока), выбрать в окне вкладку «DLL», указать путь к скомпилированной DLL и имя экспортированной функции в ней (рис. 15). Именем экспортированной функции, в данном случае, будет «Test1@12», поскольку использовался тридцатидвухбитный компилятор GCC. В других компиляторах именем экспортированной функции может быть просто «Test1» или «_Test1@12» – способ формирования экспортированного имени из имени функции обычно указывается в описании компилятора. При нажатии кнопки «OK» модель будет подключена к созданному блоку, при этом она будет вызвана с параметром RDS_BFM_INIT и должна вывести сообщение «Область создана». Если после этого удалить созданный блок, перед удалением модель будет отключена от него, что приведет к вызову функции с параметром RDS_BFM_CLEANUP и выводу сообщения «Область удалена». Это же сообщение будет выведено, если закрыть RDS не удаляя блок (в момент отключения модели от блока при очистке памяти перед завершением программы).

Подключение модели к блоку – после нажатия OK к блоку будет подключена модель Test1 из библиотеки testdll.dll , находящейся в стандартной папке DLL

Рис. 15. Подключение модели к блоку – после нажатия «OK» к блоку будет подключена модель «Test1»
из библиотеки «testdll.dll», находящейся в стандартной папке DLL


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