/* PIP - Platform Independent Primitives Dynamic library 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 MICRO_PIP #include "pilibrary.h" #include "piincludes_p.h" #ifndef WINDOWS # include #endif //! \addtogroup System //! \{ //! \class PILibrary pilibrary.h //! //! \~\brief //! \~english Run-time library //! \~russian Run-time библиотека //! //! \~\details //! \~english \section _sec0 Synopsis //! \~russian \section _sec0 Краткий обзор //! \~english //! %PILibrary allow you dynamically load external library and use //! some methods from it. %PILibrary instance contains library //! pointer and unload library on destructor, so recommended //! to use it with \b new creation. //! //! Main method of %PILibrary is \a resolve(const char *), which returns //! \c void* pointer to requested method. One should test it //! to \c nullptr and convert it in pointer to the required method. //! //! In case of C++ libraries it`s very important to use [C-linkage](https://en.cppreference.com/w/cpp/language/language_linkage) //! of exported methods! You may also need to mark methods for //! export, e.g. \c __declspec(dllexport). You can include \c //! and use \a PIP_PLUGIN_EXPORT to mark exports with PIP. //! //! \~russian //! %PILibrary позволяет динамически загружать стороннюю библиотеку //! и использовать оттуда методы. Экземпляр %PILibrary содержит //! указатель на библиотеку и выгружает её в деструкторе, поэтому //! рекомендуется создавать её с помощью \b new. //! //! Основной метод %PILibrary - это \a resolve(const char *), который возвращает //! \c void* указатель на запрошенный метод. Необходимо проверить его //! на \c nullptr и преобразовать в указатель на нужный метод. //! //! В случае C++ библиотеки очень важно использовать [C-linkage](https://en.cppreference.com/w/cpp/language/language_linkage) //! для экспортируемых методов! Также может понадобиться пометить //! методы на экспорт, например, \c __declspec(dllexport). Можно включить \c //! и использовать \a PIP_PLUGIN_EXPORT, чтобы пометить экспорт с помощью PIP. //! //! \~\code //! extern "C" { //! __declspec(dllexport) int exportedSum(int,int); //! __declspec(dllexport) int exportedMul(int,int); //! } //! \endcode //! //! \~english \section _sec1 Usage //! \~russian \section _sec1 Использование //! //! \~english Library: //! \~russian Библиотека: //! \~\code //! #include //! //! extern "C" { //! PIP_PLUGIN_EXPORT int exportedSum(int,int); //! PIP_PLUGIN_EXPORT int exportedMul(int,int); //! } //! //! int exportedSum(int a, int b) { //! return a + b; //! } //! int exportedMul(int a, int b) { //! return a * b; //! } //! \endcode //! //! \~english Program: //! \~russian Программа: //! \~\code //! int main(int argc, char * argv[]) { //! typedef int(*MyFunc)(int,int); //! PILibrary * lib = new PILibrary(); //! if (lib->load("mylib.dll")) { //! MyFunc fadd = (MyFunc)lib->resolve("exportedSum"); //! MyFunc fmul = (MyFunc)lib->resolve("exportedMul"); //! if (fadd) { //! int sum = fadd(1, 2); //! piCout << "sum =" << sum; //! } else { //! piCout << "Can`t resolve" << "exportedSum"; //! } //! if (fmul) { //! int mul = fadd(10, 20); //! piCout << "mul =" << mul; //! } else { //! piCout << "Can`t resolve" << "exportedMul"; //! } //! } else { //! piCout << lib->lastError(); //! } //! delete lib; //! } //! //! // sum = 3 //! // mul = 30 //! \endcode //! //! \} PRIVATE_DEFINITION_START(PILibrary) #ifdef WINDOWS HMODULE #else void * #endif hLib; PRIVATE_DEFINITION_END(PILibrary) PILibrary::PILibrary(const PIString & path_) { PRIVATE->hLib = 0; load(path_); } PILibrary::~PILibrary() { unload(); } bool PILibrary::load(const PIString & path_) { libpath = path_; return loadInternal(); } bool PILibrary::load() { return loadInternal(); } void PILibrary::unload() { if (PRIVATE->hLib == 0) return; #ifdef WINDOWS FreeLibrary(PRIVATE->hLib); #else dlclose(PRIVATE->hLib); #endif PRIVATE->hLib = 0; } bool PILibrary::isLoaded() const { return PRIVATE->hLib; } //! \~\details //! \~english //! Returns exported method with name "symbol" from //! loaded library. Method have to use [C-linkage](https://en.cppreference.com/w/cpp/language/language_linkage) and //! marked to export, according to compiler specification.\n //! C-linkage doesn`t provide information about return type //! and arguments, so you should manually convert obtained //! pointer to required method format before call. //! //! \~russian //! Возвращает экспортированный метод с именем "symbol" //! из загруженной библиотеки. Метод должен иметь [C-linkage](https://en.cppreference.com/w/cpp/language/language_linkage) //! и помечен для экспорта, согласно спецификации компилятора.\n //! C-linkage не предоставляет информации о возвращаемом типе //! и аргументах, поэтому необходимо вручную преобразовать //! полученный указатель к формату требуемого метода перед вызовом. //! //! \~\return //! \~english //! \b void* pointer to method or\n //! \b nullptr if method doesn`t exists or library not loaded //! //! \~russian //! \b void* указатель на метод или\n //! \b nullptr если метод не существует или библиотека не загружена void * PILibrary::resolve(const char * symbol) { if (!isLoaded()) return 0; void * ret; #ifdef WINDOWS ret = (void*)GetProcAddress(PRIVATE->hLib, symbol); #else ret = dlsym(PRIVATE->hLib, symbol); #endif getLastError(); return ret; } bool PILibrary::loadInternal() { unload(); if (libpath.isEmpty()) return false; #ifdef WINDOWS PRIVATE->hLib = LoadLibrary(libpath.data()); #else PRIVATE->hLib = dlopen(libpath.data(), RTLD_LAZY); #endif getLastError(); return PRIVATE->hLib; } void PILibrary::getLastError() { #ifdef WINDOWS liberror = errorString(); #else const char * e = dlerror(); if (e) liberror = e; else liberror.clear(); #endif } #endif // MICRO_PIP