CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
dll.cpp
Go to the documentation of this file.
1
9#include "system/dll.h"
10
11#include "errors/fatal.h"
12#include "string/format.h"
14
15#include <cassert>
16
17#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
18#include <dlfcn.h>
19#elif defined(_WIN32) || defined(_WIN64)
20#include <windows.h>
21#endif
22
23namespace CppCommon {
24
26
27class DLL::Impl
28{
29public:
30 Impl() : _dll(nullptr) {}
31
32 ~Impl()
33 {
34 try
35 {
36 if (IsLoaded())
37 Unload();
38 }
39 catch (const DLLException& ex)
40 {
41 fatality(DLLException(ex.string()).Attach(_path));
42 }
43 }
44
45 const Path path() const { return _path; }
46
47 bool IsLoaded() const
48 {
49 return (_dll != nullptr);
50 }
51
52 bool IsResolve(const std::string& name) const
53 {
54 assert(IsLoaded() && "DLL must be loaded!");
55 if (!IsLoaded())
56 return false;
57
58 return ResolveAddress(name) != nullptr;
59 }
60
61 void Assign(const Path& path)
62 {
63 assert(!IsLoaded() && "DLL must not be loaded when assigning a new path!");
64 if (IsLoaded())
65 Unload();
66
67 _path = path;
68
69#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
70 // Concatenate DLL executable path
71 if (_path.IsRelative())
72 _path = Path::executable().parent().Append(_path);
73#endif
74
75 // Concatenate DLL prefix if not provided
76 std::string filename = _path.filename().string();
77 std::string prefix = DLL::prefix();
78 if (std::strncmp(filename.c_str(), prefix.c_str(), prefix.size()) != 0)
79 _path.ReplaceFilename(prefix + filename);
80
81 // Concatenate DLL extension if not provided
82 if (_path.extension() != DLL::extension())
83 _path.Concat(DLL::extension());
84 }
85
86 bool Load()
87 {
88 assert(!IsLoaded() && "DLL is already loaded!");
89 if (IsLoaded())
90 Unload();
91
92#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
93 _dll = dlopen(_path.string().c_str(), RTLD_NOW);
94#elif defined(_WIN32) || defined(_WIN64)
95 _dll = LoadLibraryExW(_path.wstring().c_str(), nullptr, 0);
96#endif
97 return (_dll != nullptr);
98 }
99
100 bool Load(const Path& path)
101 {
102 Assign(path);
103 return Load();
104 }
105
106 void Unload()
107 {
108 assert(IsLoaded() && "DLL is not loaded!");
109 if (!IsLoaded())
110 return;
111
112#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
113 int result = dlclose(_dll);
114 if (result != 0)
115 throwex DLLException(format("Cannot unload DLL file: {}!", dlerror())).Attach(_path);
116#elif defined(_WIN32) || defined(_WIN64)
117 if (!FreeLibrary(_dll))
118 throwex DLLException("Cannot unload DLL file!").Attach(_path);
119#endif
120 _dll = nullptr;
121 }
122
123 void* ResolveAddress(const std::string& name) const
124 {
125 assert(IsLoaded() && "DLL is not loaded!");
126 if (!IsLoaded())
127 return nullptr;
128
129#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
130 return dlsym(_dll, name.c_str());
131#elif defined(_WIN32) || defined(_WIN64)
132 return (void*)GetProcAddress(_dll, name.c_str());
133#endif
134 }
135
136private:
137 Path _path;
138#if defined(unix) || defined(__unix) || defined(__unix__) || defined(__APPLE__)
139 void* _dll;
140#elif defined(_WIN32) || defined(_WIN64)
141 HMODULE _dll;
142#endif
143};
144
146
148{
149 // Check implementation storage parameters
150 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
151 static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
152 static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
153
154 // Create the implementation instance
155 new(&_storage)Impl();
156}
157
158DLL::DLL(const Path& path, bool load)
159{
160 // Check implementation storage parameters
161 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
162 static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
163 static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
164
165 // Create the implementation instance
166 new(&_storage)Impl();
167
168 impl().Assign(path);
169
170 if (load)
171 impl().Load();
172}
173
174DLL::DLL(const DLL& dll)
175{
176 // Check implementation storage parameters
177 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
178 static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
179 static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
180
181 // Create the implementation instance
182 new(&_storage)Impl();
183
184 impl().Assign(dll.path());
185}
186
187DLL::DLL(DLL&& dll) noexcept
188{
189 // Check implementation storage parameters
190 [[maybe_unused]] ValidateAlignedStorage<sizeof(Impl), alignof(Impl), StorageSize, StorageAlign> _;
191 static_assert((StorageSize >= sizeof(Impl)), "DLL::StorageSize must be increased!");
192 static_assert(((StorageAlign % alignof(Impl)) == 0), "DLL::StorageAlign must be adjusted!");
193
194 // Create the implementation instance
195 new(&_storage)Impl();
196
197 std::swap(_storage, dll._storage);
198}
199
201{
202 // Delete the implementation instance
203 reinterpret_cast<Impl*>(&_storage)->~Impl();
204}
205
207{
208 impl().Assign(path);
209 return *this;
210}
211
213{
214 impl().Assign(dll.path());
215 return *this;
216}
217
218DLL& DLL::operator=(DLL&& dll) noexcept
219{
220 std::swap(_storage, dll._storage);
221 return *this;
222}
223
224const Path DLL::path() const { return impl().path(); }
225
226bool DLL::IsLoaded() const { return impl().IsLoaded(); }
227bool DLL::IsResolve(const std::string& name) const { return impl().IsResolve(name); }
228
229bool DLL::Load() { return impl().Load(); }
230bool DLL::Load(const Path& path) { return impl().Load(path); }
231void DLL::Unload() { impl().Unload(); }
232
233void* DLL::ResolveAddress(const std::string& name) const { return impl().ResolveAddress(name); }
234
235void DLL::swap(DLL& dll) noexcept
236{
237 using std::swap;
238 swap(_storage, dll._storage);
239}
240
241} // namespace CppCommon
Dynamic link library.
Definition dll.h:56
DLL & operator=(const Path &path)
Definition dll.cpp:206
friend void swap(DLL &dll1, DLL &dll2) noexcept
Definition dll.inl:41
bool IsResolve(const std::string &name) const
Is dynamic link library resolve the given symbol?
Definition dll.cpp:227
bool Load()
Load dynamic link library.
Definition dll.cpp:229
void Unload()
Unload dynamic link library.
Definition dll.cpp:231
DLL()
Initialize the dynamic link library with an empty path.
Definition dll.cpp:147
const Path path() const
Get the dynamic link library path.
Definition dll.cpp:224
bool IsLoaded() const
Is dynamic link library loaded?
Definition dll.cpp:226
Filesystem path.
Definition path.h:90
Dynamic link library definition.
#define throwex
Throw extended exception macro.
Definition exceptions.h:23
Fatal abort execution definition.
#define fatality(...)
Fatal abort execution extended macro.
Definition fatal.h:22
Format string definition.
C++ Common project definitions.
std::string format(fmt::format_string< T... > pattern, T &&... args)
Format string.
Definition format.inl:12
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition filecache.inl:23
Aligned storage validator definition.