/*! \file piplugin.h * \ingroup System * \~\brief * \~english Plugin control * \~russian Управление плагинами */ /* PIP - Platform Independent Primitives Plugin helpers Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIPLUGIN_H #define PIPLUGIN_H #ifndef MICRO_PIP #include "pilibrary.h" #include "pistringlist.h" #ifdef DOXYGEN //! \~english Declare plugin, should be used before other PIP_PLUGIN_* macros //! \~russian Объявляет плагин, должен быть использован перед любыми другими PIP_PLUGIN_* макросами //! \~\relatesalso PIPluginLoader #define PIP_PLUGIN //! \~english Set user version to check it while loading, "version" is quoted string //! \~russian Устанавливает пользовательскую версию для проверки во время загрузки, "version" - строка в кавычках //! \~\relatesalso PIPluginLoader #define PIP_PLUGIN_SET_USER_VERSION(version) //! \~english Add pointer to future merge with plugin. Type is integer //! \~russian Добавляет указатель для будущего слияния. Тип - целое число //! \~\relatesalso PIPluginLoader #define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr) //! \~english Declare function to merge static sections //! \~russian Объявляет метод для слияния статических секций //! \~\details //! \~english //! This is functions with 3 arguments: (int type, void * from, void * to). //! This function invoked first while loading plugin with //! "from" - plugin scope, "to" - application scope, and second //! (optionally) on \a PIPluginLoader::mergeStatic() method with //! "from" - application scope, "to" - plugin scope. So with macro //! you can merge application and plugin static data. //! \~russian //! Этот метод имеет 3 аргумента: (int type, void * from, void * to). //! Он вызывается первый раз при загрузке плагина с "from" - областью плагина, //! "to" - областью приложения, и второй раз (необязательно) при вызове //! \a PIPluginLoader::mergeStatic() с "from" - областью приложения и //! "to" - областью плагина. Таким образом, этот макрос позволяет провести //! слияние статических данных приложения и плагина. //! \~\relatesalso PIPluginLoader #define PIP_PLUGIN_STATIC_SECTION_MERGE //! \~english Mark method to export //! \~russian Пометить метод на экспорт //! \~\relatesalso PIPluginLoader #define PIP_PLUGIN_EXPORT #else #ifdef WINDOWS # define PIP_PLUGIN_EXPORT __declspec(dllexport) #else # define PIP_PLUGIN_EXPORT #endif #define __PIP_PLUGIN_LOADER_VERSION_FUNC__ pip_loader_version #define __PIP_PLUGIN_STATIC_MERGE_FUNC__ pip_merge_static #define __PIP_PLUGIN_LOADER_VERSION__ 2 #define PIP_PLUGIN_SET_USER_VERSION(v) \ STATIC_INITIALIZER_BEGIN \ PIPluginInfo * pi = PIPluginInfoStorage::instance()->currentInfo(); \ if (pi) pi->setUserVersion(v); \ STATIC_INITIALIZER_END #define PIP_PLUGIN_ADD_STATIC_SECTION(type, ptr) \ STATIC_INITIALIZER_BEGIN \ PIPluginInfo * pi = PIPluginInfoStorage::instance()->currentInfo(); \ if (pi) pi->setStaticSection(type, ptr); \ STATIC_INITIALIZER_END #define PIP_PLUGIN \ extern "C" { \ PIP_PLUGIN_EXPORT int __PIP_PLUGIN_LOADER_VERSION_FUNC__() {return __PIP_PLUGIN_LOADER_VERSION__;} \ } #define PIP_PLUGIN_STATIC_SECTION_MERGE \ extern "C" { \ PIP_PLUGIN_EXPORT void __PIP_PLUGIN_STATIC_MERGE_FUNC__(int type, void * from, void * to); \ } \ void __PIP_PLUGIN_STATIC_MERGE_FUNC__(int type, void * from, void * to) #endif class PIP_EXPORT PIPluginInfo { public: PIPluginInfo(); void setUserVersion(const PIString & v); void setStaticSection(int type, void * ptr); PIString userVersion() const; PIMap staticSections() const; private: PIString user_version; PIMap static_sections; }; class PIP_EXPORT PIPluginInfoStorage { public: PIPluginInfoStorage(); PIPluginInfo * currentInfo(); PIPluginInfo * pluginInfo(void * p); PIPluginInfo * applicationInfo(); PIPluginInfo * enterPlugin(void * p); void unloadPlugin(void * p); static PIPluginInfoStorage * instance(); private: NO_COPY_CLASS(PIPluginInfoStorage) void * current; PIMap info; }; class PIP_EXPORT PIPluginLoader { public: typedef int(*FunctionLoaderVersion)(); typedef void(*FunctionStaticMerge)(int, void *, void *); //! \~english Possible load plugin error //! \~russian Возможные ошибки загрузки плагина enum Error { Unknown /** \~english No \a load() call yet \~russian Не было вызова \a load() */ , NoError /** \~english No error \~russian Нет ошибки */ , LibraryLoadError /** \~english System can`t load library \~russian Система не смогла загрузить библиотеку */ , MissingSymbols /** \~english Can`t find necessary symbols \~russian Нет необходимых методов */ , InvalidLoaderVersion /** \~english Internal version mismatch \~russian Неверная внутренняя версия */ , InvalidUserVersion /** \~english User version mismatch \~russian Неверная пользовательская версия */ , }; //! \~english Contruct loader with base filename "name" and call \a load() if "name" not empty //! \~russian Создает загрузчик с базовым именем файла "name" и вызывает \a load() если "name" не пустое PIPluginLoader(const PIString & name = PIString()); //! \~english Destructor, unload library //! \~russian Деструктор, выгружает библиотеку ~PIPluginLoader(); //! \~english Load plugin with base filename "name" //! \~russian Загружает плагин с базовым именем "name" bool load(const PIString & name); //! \~english Unload plugin and free library //! \~russian Выгружает плагин и освобождает библиотеку void unload(); //! \~english Returns if plugin is successfully loaded //! \~russian Возвращает успешно ли загружен плагин bool isLoaded() const; //! \~english Returns error of last \a load() call //! \~russian Возвращает ошибку последнего вызова \a load() Error lastError() const; //! \~english Returns error message of last \a load() call //! \~russian Возвращает сообщение об ошибке последнего вызова \a load() PIString lastErrorText() const; //! \~english Set if %PIPluginLoader should print load messages, \b true by default //! \~russian Устанавливает должен ли %PIPluginLoader выводить сообщения, \b true по умолчанию void setMessages(bool yes); //! \~english Returns if %PIPluginLoader should print load messages, \b true by default //! \~russian Возвращает должен ли %PIPluginLoader выводить сообщения, \b true по умолчанию bool isMessages() const; //! \~english Returns loaded plugin library path //! \~russian Возвращает путь к загруженной библиотеке PIString libPath(); //! \~english Obtain exported library method with name "symbol" //! \~russian Получает экспортированный метод библиотеки с именем "symbol" //! \~\sa PILibrary::resolve() void * resolve(const char * name); //! \~english Invoke plugin \a PIP_PLUGIN_STATIC_SECTION_MERGE //! \~russian Вызывает у плагина \a PIP_PLUGIN_STATIC_SECTION_MERGE void mergeStatic(); static PIStringList pluginsDirectories(const PIString & name); private: NO_COPY_CLASS(PIPluginLoader) PIString findLibrary(const PIString & path); static PIString libExtension(); PILibrary lib; FunctionLoaderVersion func_loader_version; FunctionStaticMerge func_static_merge; PIString error_str; Error error; bool loaded, messages; }; #endif // MICRO_PIP #endif // PIPLUGIN_H