winamp/Src/external_dependencies/openmpt-trunk/misc/mptLibrary.cpp
2024-09-24 14:54:57 +02:00

554 lines
10 KiB
C++

/*
* 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 <windows.h>
#elif MPT_OS_ANDROID
#include <dlfcn.h>
#elif defined(MPT_WITH_LTDL)
#include <ltdl.h>
#elif defined(MPT_WITH_DL)
#include <dlfcn.h>
#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<FuncPtr>(::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<FuncPtr>(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<FuncPtr>(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<FuncPtr>(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<LibraryHandle>(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