/* * 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" #include "mpt/osinfo/windows_version.hpp" #if MPT_OS_WINDOWS #include #elif MPT_OS_ANDROID #include #elif defined(MPT_WITH_LTDL) #include #elif defined(MPT_WITH_DL) #include #endif OPENMPT_NAMESPACE_BEGIN 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::LibrarySearchPath::Default: hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0); break; case mpt::LibrarySearchPath::Application: hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0); break; case mpt::LibrarySearchPath::System: hModule = NULL; // Only application packaged libraries can be loaded dynamically in WinRT break; case mpt::LibrarySearchPath::FullPath: hModule = NULL; // Absolute path is not supported in WinRT break; case mpt::LibrarySearchPath::Invalid: MPT_ASSERT_NOTREACHED(); break; } #endif #else // !MPT_OS_WINDOWS_WINRT #if (_WIN32_WINNT >= 0x0602) bool hasKB2533623 = true; #else // Check for KB2533623: bool hasKB2533623 = false; mpt::osinfo::windows::Version WindowsVersion = mpt::osinfo::windows::Version::Current(); if(WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::Win8)) { hasKB2533623 = true; } else if(WindowsVersion.IsAtLeast(mpt::osinfo::windows::Version::WinVista)) { HMODULE hKernel32DLL = LoadLibrary(TEXT("kernel32.dll")); if(hKernel32DLL) { if(::GetProcAddress(hKernel32DLL, "SetDefaultDllDirectories") != nullptr) { hasKB2533623 = true; } FreeLibrary(hKernel32DLL); hKernel32DLL = NULL; } } #endif MPT_MAYBE_CONSTANT_IF(hasKB2533623) { switch(path.GetSearchPath()) { case mpt::LibrarySearchPath::Default: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); break; case mpt::LibrarySearchPath::System: 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::LibrarySearchPath::Application: { const mpt::PathString dllPath = mpt::GetExecutablePath(); if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory()) { hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str()); } } break; case mpt::LibrarySearchPath::FullPath: hModule = LoadLibrary(path.GetFileName().AsNative().c_str()); break; #else // For libopenmpt, do the safe thing. case mpt::LibrarySearchPath::Application: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR); break; case mpt::LibrarySearchPath::FullPath: hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); break; #endif case mpt::LibrarySearchPath::Invalid: MPT_ASSERT_NOTREACHED(); break; } } else { switch(path.GetSearchPath()) { case mpt::LibrarySearchPath::Default: hModule = LoadLibrary(path.GetFileName().AsNative().c_str()); break; case mpt::LibrarySearchPath::Application: { const mpt::PathString dllPath = mpt::GetExecutablePath(); if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory()) { hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str()); } } break; case mpt::LibrarySearchPath::System: { 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::LibrarySearchPath::FullPath: hModule = LoadLibrary(path.GetFileName().AsNative().c_str()); break; case mpt::LibrarySearchPath::Invalid: MPT_ASSERT_NOTREACHED(); break; } } #endif // MPT_OS_WINDOWS_WINRT } LibraryHandle(const LibraryHandle &) = delete; LibraryHandle & operator=(const LibraryHandle &) = delete; ~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(const LibraryHandle &) = delete; LibraryHandle & operator=(const LibraryHandle &) = delete; ~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(const LibraryHandle &) = delete; LibraryHandle & operator=(const LibraryHandle &) = delete; ~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(const LibraryHandle &) = delete; LibraryHandle & operator=(const LibraryHandle &) = delete; ~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(const LibraryHandle &) = delete; LibraryHandle & operator=(const LibraryHandle &) = delete; ~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, const mpt::PathString &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::LibrarySearchPath::Application, GetDefaultPrefix() + basename + GetDefaultSuffix()); } LibraryPath LibraryPath::AppFullName(const mpt::PathString &fullname) { return LibraryPath(mpt::LibrarySearchPath::Application, fullname + GetDefaultSuffix()); } LibraryPath LibraryPath::System(const mpt::PathString &basename) { return LibraryPath(mpt::LibrarySearchPath::System, GetDefaultPrefix() + basename + GetDefaultSuffix()); } LibraryPath LibraryPath::FullPath(const mpt::PathString &path) { return LibraryPath(mpt::LibrarySearchPath::FullPath, path); } Library::Library() { return; } Library::Library(const mpt::LibraryPath &path) { if(path.GetSearchPath() == mpt::LibrarySearchPath::Invalid) { 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 OPENMPT_NAMESPACE_END