Реализация модуля плагина
Плагины активно взаимодействуют со специальным компонентом Firebird,называемым диспетчером плагинов. В частности, менеджер плагинов должензнать, какие модули плагина были загружены и должен быть уведомлен, еслиоперационная система пытается выгрузить один из этих модулей без явнойкоманды диспетчера плагина (это может произойти прежде всего прииспользовании встроенного сервера (embedded) — когда в программевызывается exit() или основная библиотека Firebird fbclientвыгружается). Основная задача интерфейса IPluginModule — этоуведомление. Прежде всего, нужно решить — как определить, что модульбудет выгружен? Когда динамическая библиотека выгружается по какой-либопричине, выполняется множество зависимых от ОС действий, и некоторые изэтих действий могут использоваться для обнаружения этого факта впрограмме. При написании плагинов, распространяемых вместе с firebird,мы всегда используем вызов деструктора глобальной переменной. Большой«плюс» этого метода заключается в том, что он независим от ОС (хотячто-то вроде функции exit(), возможно, также успешно используется). Ноиспользование деструктора позволяет легко сконцентрировать почти все,что связано с обнаружением выгрузки в одном классе, реализуя в то жевремя интерфейс IPluginModule.
Минимальная реализация выглядит следующим образом:
class PluginModule : public IPluginModuleImpl<PluginModule, CheckStatusWrapper>
{
private:
IPluginManager* pluginManager;
public:
PluginModule()
: pluginManager(NULL)
{ }
~PluginModule()
{
if (pluginManager)
{
pluginManager->unregisterModule(this);
doClean();
}
}
void registerMe(IPluginManager* m)
{
pluginManager = m;
pluginManager->registerModule(this);
}
void doClean()
{
pluginManager = NULL;
}
};
Единственным членом данных является интерфейс диспетчера плагиновIPluginManager. Он передаетсяфункции registerModule() и сохраняется в приватной переменной, в то жевремя модуль регистрируется в диспетчере плагинов методом callModule() ссобственным адресом в качестве единственного параметра. ПеременнаяpluginManager не только сохраняет указатель на интерфейс, ноодновременно служит в качестве флага, что модуль зарегистрирован. Когдавызывается деструктор зарегистрированного модуля, он уведомляетдиспетчер плагинов о неожиданной выгрузке с помощью вызоваunregisterModule(), передающим указатель на себя. Когда диспетчерплагинов будет регулярно выгружать модуль, то в первую очередь вызовметода doClean() меняет состояние модуля на незарегистрированное, и этопозволяет избежать вызова unregisterModule(), когда ОС выполняетфактическую выгрузку.
Реализовав интерфейс плагина IPluginModule, мы встретились с первыминтерфейсом, необходимым для реализации плагинов — IPluginManager. Онбудет активно использоваться позже, остальные члены этого класса вряд липотребуются вам после копирования в вашу программу. Просто не забудьтеобъявить глобальную переменную этого типа и вызвать функцию registerMe()из FB_PLUGIN_ENTRY_POINT.