#include "dll_loader.hpp" #include #include #if defined(BASALT_OS_WINDOWS) #include #else #include #endif using ::basalt::shared::char_types::BSStringView; namespace basalt::presenter::dll_loader { static std::filesystem::path get_executable() { #if defined(BASALT_OS_WINDOWS) wchar_t buffer[MAX_PATH]; DWORD hr = GetModuleFileNameW(NULL, buffer, MAX_PATH); if (hr > 0 && hr < MAX_PATH) { return std::filesystem::path(buffer); } else { throw std::runtime_error("Failed to get executable path"); } #else char buffer[PATH_MAX]; ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); if (len != -1) { buffer[len] = '\0'; return std::filesystem::path(buffer); } else { throw std::runtime_error("Failed to get executable path"); } #endif } DllLoader::DllLoader(DllKind kind, const BSStringView& filename) { // Build DLL full path auto dll_path = get_executable().parent_path(); dll_path /= BSTEXT("plugin"); switch (kind) { case DllKind::Engine: dll_path /= BSTEXT("engine"); break; case DllKind::Deliver: dll_path /= BSTEXT("deliver"); break; case DllKind::ObjectLoader: dll_path /= BSTEXT("object_loader"); break; case DllKind::AnimeLoader: dll_path /= BSTEXT("anime_loader"); break; } dll_path /= filename; #if defined(BASALT_OS_WINDOWS) dll_path.replace_extension(BSTEXT(".dll")); #else dll_path.replace_extension(BSTEXT(".so")); #endif // Load DLL #if defined(BASALT_OS_WINDOWS) m_Handle = LoadLibraryW(dll_path.wstring().c_str()); #else m_Handle = dlopen(dll_path.string().c_str(), RTLD_LAZY); #endif // Check loaded DLL if (!m_Handle) throw std::runtime_error("Can not load given dynamic library."); } DllLoader::~DllLoader() { if (m_Handle) { #if defined(BASALT_OS_WINDOWS) FreeLibrary(m_Handle); #else dlclose(m_Handle); #endif } } void *DllLoader::get_function_pointer(const char *name) { if (!m_Handle) throw std::runtime_error("Can not fetch function pointer on not loaded dynamic library."); #if defined(BASALT_OS_WINDOWS) return (void *) GetProcAddress(m_Handle, name); #else return (void *) dlsym(m_Handle, name); #endif } } // namespace Basalt::Presenter