DISTRHO Plugin Framework
LibraryUtils.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef DISTRHO_LIBRARY_UTILS_HPP_INCLUDED
18 #define DISTRHO_LIBRARY_UTILS_HPP_INCLUDED
19 
20 #include "../DistrhoUtils.hpp"
21 
22 #ifdef DISTRHO_OS_WINDOWS
23 # include <winsock2.h>
24 # include <windows.h>
25 typedef HMODULE lib_t;
26 #else
27 # include <dlfcn.h>
28 typedef void* lib_t;
29 #endif
30 
31 // -----------------------------------------------------------------------
32 // library related calls
33 
34 /*
35  * Open 'filename' library (must not be null).
36  * May return null, in which case "lib_error" has the error.
37  */
38 static inline
39 lib_t lib_open(const char* const filename) noexcept
40 {
41  DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr);
42 
43  try {
44 #ifdef DISTRHO_OS_WINDOWS
45  return ::LoadLibraryA(filename);
46 #else
47  return ::dlopen(filename, RTLD_NOW|RTLD_LOCAL);
48 #endif
49  } DISTRHO_SAFE_EXCEPTION_RETURN("lib_open", nullptr);
50 }
51 
52 /*
53  * Close a previously opened library (must not be null).
54  * If false is returned, "lib_error" has the error.
55  */
56 static inline
57 bool lib_close(const lib_t lib) noexcept
58 {
59  DISTRHO_SAFE_ASSERT_RETURN(lib != nullptr, false);
60 
61  try {
62 #ifdef DISTRHO_OS_WINDOWS
63  return ::FreeLibrary(lib);
64 #else
65  return (::dlclose(lib) == 0);
66 #endif
67  } DISTRHO_SAFE_EXCEPTION_RETURN("lib_close", false);
68 }
69 
70 /*
71  * Get a library symbol (must not be null).
72  * Returns null if the symbol is not found.
73  */
74 template<typename Func>
75 static inline
76 Func lib_symbol(const lib_t lib, const char* const symbol) noexcept
77 {
78  DISTRHO_SAFE_ASSERT_RETURN(lib != nullptr, nullptr);
79  DISTRHO_SAFE_ASSERT_RETURN(symbol != nullptr && symbol[0] != '\0', nullptr);
80 
81  try {
82 #ifdef DISTRHO_OS_WINDOWS
83 # if defined(__GNUC__) && (__GNUC__ >= 9)
84 # pragma GCC diagnostic push
85 # pragma GCC diagnostic ignored "-Wcast-function-type"
86 # endif
87  return (Func)::GetProcAddress(lib, symbol);
88 # if defined(__GNUC__) && (__GNUC__ >= 9)
89 # pragma GCC diagnostic pop
90 # endif
91 #else
92  return (Func)(uintptr_t)::dlsym(lib, symbol);
93 #endif
94  } DISTRHO_SAFE_EXCEPTION_RETURN("lib_symbol", nullptr);
95 }
96 
97 /*
98  * Return the last operation error ('filename' must not be null).
99  * May return null.
100  */
101 static inline
102 const char* lib_error(const char* const filename) noexcept
103 {
104  DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', nullptr);
105 
106 #ifdef DISTRHO_OS_WINDOWS
107  static char libError[2048+1];
108  std::memset(libError, 0, sizeof(libError));
109 
110  try {
111  const DWORD winErrorCode = ::GetLastError();
112  const int winErrorFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS;
113  LPVOID winErrorString;
114 
115  ::FormatMessage(winErrorFlags, nullptr, winErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&winErrorString, 0, nullptr);
116 
117  std::snprintf(libError, 2048, "%s: error code %li: %s", filename, winErrorCode, (const char*)winErrorString);
118  ::LocalFree(winErrorString);
119  } DISTRHO_SAFE_EXCEPTION("lib_error");
120 
121  return (libError[0] != '\0') ? libError : nullptr;
122 #else
123  return ::dlerror();
124 #endif
125 }
126 
127 // -----------------------------------------------------------------------
128 
129 #endif // DISTRHO_LIBRARY_UTILS_HPP_INCLUDED