/* * mptLibrary.cpp * -------------- * Purpose: Shared library handling. * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #include "stdafx.h" #include "mptLibrary.h" #if defined(MPT_ENABLE_DYNBIND) #if MPT_OS_WINDOWS #include #elif MPT_OS_ANDROID #include #elif defined(MPT_WITH_LTDL) #include #elif defined(MPT_WITH_DL) #include #endif #endif OPENMPT_NAMESPACE_BEGIN #if defined(MPT_ENABLE_DYNBIND) namespace mpt { #if MPT_OS_WINDOWS // KB2533623 / Win8 #ifndef LOAD_LIBRARY_SEARCH_DEFAULT_DIRS #define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000 #endif #ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR #define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200 #endif #ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif #ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR #define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100 #endif class LibraryHandle { private: HMODULE hModule; public: LibraryHandle(const mpt::LibraryPath &path) : hModule(NULL) { #if MPT_OS_WINDOWS_WINRT #if (_WIN32_WINNT < 0x0602) (void)path; hModule = NULL; // unsupported #else switch(path.GetSearchPath()) { case mpt::LibrarySearchPathDefault: hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0); break; case mpt::LibrarySearchPathApplication: hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0); break; case mpt::LibrarySearchPathSystem: hModule = NULL; // Only application packaged libraries can be loaded dynamically in WinRT break; case mpt::LibrarySearchPathFullPath: hModule = NULL; // Absolute path is not supported in WinRT break; case mpt::LibrarySearchPathInvalid: MPT_ASSERT_NOTREACHED(); break; } #endif #else // !MPT_OS_WINDOWS_WINRT mpt::Windows::Version WindowsVersion = mpt::Windows::Version::Current(); // Check for KB2533623: bool hasKB2533623 = false; if(WindowsVersion.IsAtLeast(mpt::Windows::Version::Win8)) { hasKB2533623 = true; } else if(WindowsVersion.IsAtLeast(mpt::Windows::Version::WinVista)) { HMODULE hKernel32DLL = LoadLibraryW(L"kernel32.dll"); if(hKernel32DLL) { if(::GetProcAddress(hKernel32DLL, "SetDefaultDllDirectories") != nullptr) { hasKB2533623 = true; } FreeLibrary(hKernel32DLL); hKernel32DLL = NULL; } } if(hasKB2533623) { switch(path.GetSearchPath()) { case mpt::LibrarySearchPathDefault: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); break; case mpt::LibrarySearchPathSystem: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); break; #if defined(MODPLUG_TRACKER) // Using restricted search paths applies to potential DLL dependencies // recursively. // This fails loading for e.g. Codec or Plugin DLLs in application // directory if they depend on the MSVC C or C++ runtime (which is // located in the system directory). // Just rely on the default search path here. case mpt::LibrarySearchPathApplication: { const mpt::PathString dllPath = mpt::GetAppPath(); if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory()) { hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str()); } } break; case mpt::LibrarySearchPathFullPath: hModule = LoadLibrary(path.GetFileName().AsNative().c_str()); break; #else // For libopenmpt, do the safe thing. case mpt::LibrarySearchPathApplication: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR); break; case mpt::LibrarySearchPathFullPath: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); break; #endif case mpt::LibrarySearchPathInvalid: MPT_ASSERT_NOTREACHED(); break; } } else { switch(path.GetSearchPath()) { case mpt::LibrarySearchPathDefault: hModule = LoadLibrary(path.GetFileName().AsNative().c_str()); break; case mpt::LibrarySearchPathApplication: { const mpt::PathString dllPath = mpt::GetAppPath(); if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory()) { hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str()); } } break; case mpt::LibrarySearchPathSystem: { const mpt::PathString dllPath = mpt::GetSystemPath(); if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory()) { hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str()); } } break; case mpt::LibrarySearchPathFullPath: hModule = LoadLibrary(path.GetFileName().AsNative().c_str()); break; case mpt::LibrarySearchPathInvalid: MPT_ASSERT_NOTREACHED(); break; } } #endif // MPT_OS_WINDOWS_WINRT } ~LibraryHandle() { if(IsValid()) { FreeLibrary(hModule); } hModule = NULL; } public: bool IsValid() const { return (hModule != NULL); } FuncPtr GetProcAddress(const std::string &symbol) const { if(!IsValid()) { return nullptr; } return reinterpret_cast(::GetProcAddress(hModule, symbol.c_str())); } }; #elif MPT_OS_ANDROID // Fake implementation. // Load shared objects from the JAVA side of things. class LibraryHandle { public: LibraryHandle(const mpt::LibraryPath &path) { return; } ~LibraryHandle() { return; } public: bool IsValid() const { return true; } FuncPtr GetProcAddress(const std::string &symbol) const { if(!IsValid()) { return nullptr; } return reinterpret_cast(dlsym(0, symbol.c_str())); } }; #elif defined(MPT_WITH_LTDL) class LibraryHandle { private: bool inited; lt_dlhandle handle; public: LibraryHandle(const mpt::LibraryPath &path) : inited(false) , handle(0) { if(lt_dlinit() != 0) { return; } inited = true; handle = lt_dlopenext(path.GetFileName().AsNative().c_str()); } ~LibraryHandle() { if(IsValid()) { lt_dlclose(handle); } handle = 0; if(inited) { lt_dlexit(); inited = false; } } public: bool IsValid() const { return handle != 0; } FuncPtr GetProcAddress(const std::string &symbol) const { if(!IsValid()) { return nullptr; } return reinterpret_cast(lt_dlsym(handle, symbol.c_str())); } }; #elif defined(MPT_WITH_DL) class LibraryHandle { private: void* handle; public: LibraryHandle(const mpt::LibraryPath &path) : handle(NULL) { handle = dlopen(path.GetFileName().AsNative().c_str(), RTLD_NOW); } ~LibraryHandle() { if(IsValid()) { dlclose(handle); } handle = NULL; } public: bool IsValid() const { return handle != NULL; } FuncPtr GetProcAddress(const std::string &symbol) const { if(!IsValid()) { return NULL; } return reinterpret_cast(dlsym(handle, symbol.c_str())); } }; #else // MPT_OS // dummy implementation class LibraryHandle { public: LibraryHandle(const mpt::LibraryPath &path) { MPT_UNREFERENCED_PARAMETER(path); return; } ~LibraryHandle() { return; } public: bool IsValid() const { return false; } FuncPtr GetProcAddress(const std::string &symbol) const { MPT_UNREFERENCED_PARAMETER(symbol); if(!IsValid()) { return nullptr; } return nullptr; } }; #endif // MPT_OS LibraryPath::LibraryPath(mpt::LibrarySearchPath searchPath, class mpt::PathString const &fileName) : searchPath(searchPath) , fileName(fileName) { return; } mpt::LibrarySearchPath LibraryPath::GetSearchPath() const { return searchPath; } mpt::PathString LibraryPath::GetFileName() const { return fileName; } mpt::PathString LibraryPath::GetDefaultPrefix() { #if MPT_OS_WINDOWS return P_(""); #elif MPT_OS_ANDROID return P_("lib"); #elif defined(MPT_WITH_LTDL) return P_("lib"); #elif defined(MPT_WITH_DL) return P_("lib"); #else return P_("lib"); #endif } mpt::PathString LibraryPath::GetDefaultSuffix() { #if MPT_OS_WINDOWS return P_(".dll"); #elif MPT_OS_ANDROID return P_(".so"); #elif defined(MPT_WITH_LTDL) return P_(""); // handled by libltdl #elif defined(MPT_WITH_DL) return P_(".so"); #else return mpt::PathString(); #endif } LibraryPath LibraryPath::App(const mpt::PathString &basename) { return LibraryPath(mpt::LibrarySearchPathApplication, GetDefaultPrefix() + basename + GetDefaultSuffix()); } LibraryPath LibraryPath::AppFullName(const mpt::PathString &fullname) { return LibraryPath(mpt::LibrarySearchPathApplication, fullname + GetDefaultSuffix()); } #if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) LibraryPath LibraryPath::AppDataFullName(const mpt::PathString &fullname, const mpt::PathString &appdata) { if(appdata.empty()) { return LibraryPath(mpt::LibrarySearchPathInvalid, P_("")); } return LibraryPath(mpt::LibrarySearchPathFullPath, appdata.WithTrailingSlash() + fullname + GetDefaultSuffix()); } #endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT LibraryPath LibraryPath::System(const mpt::PathString &basename) { return LibraryPath(mpt::LibrarySearchPathSystem, GetDefaultPrefix() + basename + GetDefaultSuffix()); } LibraryPath LibraryPath::FullPath(const mpt::PathString &path) { return LibraryPath(mpt::LibrarySearchPathFullPath, path); } Library::Library() { return; } Library::Library(const mpt::LibraryPath &path) { if(path.GetSearchPath() == mpt::LibrarySearchPathInvalid) { return; } if(path.GetFileName().empty()) { return; } m_Handle = std::make_shared(path); } void Library::Unload() { *this = mpt::Library(); } bool Library::IsValid() const { return m_Handle && m_Handle->IsValid(); } FuncPtr Library::GetProcAddress(const std::string &symbol) const { if(!IsValid()) { return nullptr; } return m_Handle->GetProcAddress(symbol); } } // namespace mpt #else // !MPT_ENABLE_DYNBIND MPT_MSVC_WORKAROUND_LNK4221(mptLibrary) #endif // MPT_ENABLE_DYNBIND OPENMPT_NAMESPACE_END