Files
pip/libs/main/system/pilibrary.cpp
2022-12-14 14:13:52 +03:00

237 lines
7.2 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef MICRO_PIP
# include "pilibrary.h"
# include "piincludes_p.h"
# ifndef WINDOWS
# include <dlfcn.h>
# endif
//! \class PILibrary pilibrary.h
//! \~\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 <piplugin.h>
//! 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 <piplugin.h>
//! и использовать \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 <piplugin.h>
//!
//! 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 = LoadLibraryA(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