// ============================================================================ // DynLibUtils.cpp — Shared dynamic library loading utilities // ============================================================================ #include "DynLibUtils.h" #ifndef _WIN32 # include #endif namespace ANSCENTER { namespace DynLib { // ── FileExists ─────────────────────────────────────────────────────────── bool FileExists(const std::string& path) { #ifdef _WIN32 DWORD attr = GetFileAttributesA(path.c_str()); return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_DIRECTORY); #else struct stat st {}; return (::stat(path.c_str(), &st) == 0) && S_ISREG(st.st_mode); #endif } // ── JoinPath ───────────────────────────────────────────────────────────── std::string JoinPath(const std::string& base, const std::string& component) { #ifdef _WIN32 const char sep = '\\'; #else const char sep = '/'; #endif if (base.empty()) return component; if (base.back() == sep || base.back() == '/') return base + component; return base + sep + component; } // ── InjectDllSearchPath ────────────────────────────────────────────────── void InjectDllSearchPath(const std::string& dir) { #ifdef _WIN32 // Safe UTF-8 → wide-string conversion (handles non-ASCII paths correctly) int wlen = MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, nullptr, 0); std::wstring wdir(static_cast(wlen > 0 ? wlen - 1 : 0), L'\0'); if (wlen > 0) MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, wdir.data(), wlen); DLL_DIRECTORY_COOKIE cookie = AddDllDirectory(wdir.c_str()); if (!cookie) std::cerr << "[DynLib] WARNING: AddDllDirectory failed for: " << dir << " (error " << GetLastError() << ")" << std::endl; char existing_path[32767] = {}; GetEnvironmentVariableA("PATH", existing_path, sizeof(existing_path)); std::string new_path = dir + ";" + existing_path; if (!SetEnvironmentVariableA("PATH", new_path.c_str())) std::cerr << "[DynLib] WARNING: SetEnvironmentVariable PATH failed." << std::endl; #else const char* existing = getenv("LD_LIBRARY_PATH"); std::string new_path = dir + (existing ? (":" + std::string(existing)) : ""); setenv("LD_LIBRARY_PATH", new_path.c_str(), 1); #endif std::cout << "[DynLib] DLL search path injected: " << dir << std::endl; } // ── LoadLib ────────────────────────────────────────────────────────────── LibHandle LoadLib(const std::string& path, bool globalLoad) { #ifdef _WIN32 (void)globalLoad; return LoadLibraryExA(path.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); #else return globalLoad ? ::dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL) : ::dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); #endif } // ── FreeLib ────────────────────────────────────────────────────────────── void FreeLib(LibHandle h) { if (!h) return; #ifdef _WIN32 ::FreeLibrary(h); #else ::dlclose(h); #endif } // ── GetSymbol ──────────────────────────────────────────────────────────── void* GetSymbol(LibHandle h, const char* sym) { if (!h) return nullptr; #ifdef _WIN32 return reinterpret_cast(::GetProcAddress(h, sym)); #else return ::dlsym(h, sym); #endif } // ── FindAndLoad ────────────────────────────────────────────────────────── LibHandle FindAndLoad(const std::vector& candidates, std::string& loadedPath, bool verbose, bool globalLoad) { for (const auto& name : candidates) { LibHandle h = LoadLib(name, globalLoad); if (h) { loadedPath = name; if (verbose) std::cout << "[DynLib] Loaded: " << name << std::endl; return h; } } return LIB_INVALID; } } // namespace DynLib } // namespace ANSCENTER