diff --git a/lib/libimhex/include/hex/api/plugin_manager.hpp b/lib/libimhex/include/hex/api/plugin_manager.hpp index 0a736a24c..111adeee5 100644 --- a/lib/libimhex/include/hex/api/plugin_manager.hpp +++ b/lib/libimhex/include/hex/api/plugin_manager.hpp @@ -104,6 +104,10 @@ namespace hex { static bool load(); static bool load(const std::fs::path &pluginFolder); + + static bool loadLibraries(); + static bool loadLibraries(const std::fs::path &pluginFolder); + static void unload(); static void reload(); static void initializeNewPlugins(); @@ -122,6 +126,7 @@ namespace hex { static std::list& getPluginsMutable(); static AutoReset> s_pluginPaths, s_pluginLoadPaths; + static AutoReset> s_loadedLibraries; }; } \ No newline at end of file diff --git a/lib/libimhex/source/api/plugin_manager.cpp b/lib/libimhex/source/api/plugin_manager.cpp index 3da569b83..b3e5c6d3e 100644 --- a/lib/libimhex/source/api/plugin_manager.cpp +++ b/lib/libimhex/source/api/plugin_manager.cpp @@ -18,24 +18,48 @@ namespace hex { + static uintptr_t loadLibrary(const std::fs::path &path) { + #if defined(OS_WINDOWS) + auto handle = uintptr_t(LoadLibraryW(path.c_str())); + + if (handle == uintptr_t(INVALID_HANDLE_VALUE) || handle == 0) { + log::error("Loading library '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), hex::formatSystemError(::GetLastError())); + return 0; + } + + return handle; + #else + auto handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY)); + + if (handle == 0) { + log::error("Loading library '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror()); + return 0; + } + + return handle; + #endif + } + + static void unloadLibrary(uintptr_t handle, const std::fs::path &path) { + #if defined(OS_WINDOWS) + if (handle != 0) { + if (FreeLibrary(HMODULE(handle)) == FALSE) { + log::error("Error when unloading library '{}': {}!", wolv::util::toUTF8String(path.filename()), hex::formatSystemError(::GetLastError())); + } + } + #else + if (handle != 0) { + dlclose(reinterpret_cast(handle)); + } + #endif + } + Plugin::Plugin(const std::fs::path &path) : m_path(path) { log::info("Loading plugin '{}'", wolv::util::toUTF8String(path.filename())); - #if defined(OS_WINDOWS) - m_handle = uintptr_t(LoadLibraryW(path.c_str())); - - if (m_handle == uintptr_t(INVALID_HANDLE_VALUE) || m_handle == 0) { - log::error("Loading plugin '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), hex::formatSystemError(::GetLastError())); - return; - } - #else - m_handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY)); - - if (m_handle == 0) { - log::error("Loading plugin '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror()); - return; - } - #endif + m_handle = loadLibrary(path); + if (m_handle == 0) + return; const auto fileName = path.stem().string(); @@ -89,15 +113,7 @@ namespace hex { log::info("Trying to unload plugin '{}'", getPluginName()); } - #if defined(OS_WINDOWS) - if (m_handle != 0) - if (FreeLibrary(HMODULE(m_handle)) == FALSE) { - log::error("Error when unloading plugin '{}': {}!", wolv::util::toUTF8String(m_path.filename()), hex::formatSystemError(::GetLastError())); - } - #else - if (m_handle != 0) - dlclose(reinterpret_cast(m_handle)); - #endif + unloadLibrary(m_handle, m_path); } bool Plugin::initializePlugin() const { @@ -284,6 +300,35 @@ namespace hex { return true; } + AutoReset> PluginManager::s_loadedLibraries; + + bool PluginManager::loadLibraries() { + bool success = true; + for (const auto &loadPath : fs::getDefaultPaths(fs::ImHexPath::Libraries)) + success = PluginManager::loadLibraries(loadPath) && success; + + return success; + } + + bool PluginManager::loadLibraries(const std::fs::path& pluginFolder) { + bool success = true; + for (const auto &entry : std::fs::recursive_directory_iterator(pluginFolder)) { + if (!(entry.path().extension() == ".dll" || entry.path().extension() == ".so" || entry.path().extension() == ".dylib")) + continue; + + auto handle = loadLibrary(entry); + if (handle == 0) { + success = false; + } + + PluginManager::s_loadedLibraries->push_back(handle); + } + + return success; + } + + + void PluginManager::initializeNewPlugins() { for (const auto &plugin : getPlugins()) { if (!plugin.isLoaded()) @@ -304,6 +349,11 @@ namespace hex { plugins.pop_back(); } + while (!s_loadedLibraries->empty()) { + unloadLibrary(s_loadedLibraries->back(), ""); + s_loadedLibraries->pop_back(); + } + getPluginsMutable() = std::move(savedPlugins); } diff --git a/main/gui/source/init/run/cli.cpp b/main/gui/source/init/run/cli.cpp index 2d1871c79..bde9c1ba8 100644 --- a/main/gui/source/init/run/cli.cpp +++ b/main/gui/source/init/run/cli.cpp @@ -59,6 +59,7 @@ namespace hex::init { // Load all plugins but don't initialize them + PluginManager::loadLibraries(); for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) { PluginManager::load(dir); } diff --git a/main/gui/source/init/tasks.cpp b/main/gui/source/init/tasks.cpp index c299a66dd..c2d0106b6 100644 --- a/main/gui/source/init/tasks.cpp +++ b/main/gui/source/init/tasks.cpp @@ -94,6 +94,7 @@ namespace hex::init { PluginManager::addLoadPath(dir); } + PluginManager::loadLibraries(); PluginManager::load(); #endif diff --git a/tests/plugins/source/plugins.cpp b/tests/plugins/source/plugins.cpp index 0cdb40167..bc85a2988 100644 --- a/tests/plugins/source/plugins.cpp +++ b/tests/plugins/source/plugins.cpp @@ -10,6 +10,7 @@ public: PluginManager::addLoadPath(dir); } + PluginManager::loadLibraries(); PluginManager::load(); } };