1 |
/* |
2 |
Copyright (C) 2010 Christian Schoenebeck |
3 |
*/ |
4 |
|
5 |
#include "DynamicLibraries.h" |
6 |
#include "global_private.h" |
7 |
#if defined(WIN32) |
8 |
# include <windows.h> |
9 |
#else |
10 |
# include <dlfcn.h> |
11 |
# include <errno.h> |
12 |
# include <dirent.h> |
13 |
# include <sys/types.h> |
14 |
# include <sys/stat.h> |
15 |
# include <unistd.h> |
16 |
#endif |
17 |
#include <string.h> |
18 |
#include <iostream> |
19 |
|
20 |
namespace LinuxSampler { |
21 |
|
22 |
/* |
23 |
NOTE: it is expected by the sampler that a reference count is maintained for |
24 |
DLLs, so DLLs can be opened n times, and a DLL shall only be freed from |
25 |
memory after DynamicLibraryClose() was also called n times. Usually this |
26 |
behavior is already implemented on Operating System level. If not, it has to |
27 |
be implemented here for the respective OS ! |
28 |
*/ |
29 |
|
30 |
int DynamicLibrariesSearch(String dir, String funct, DynamicLibrariesSearchCallbackFunction* pCallback, void* pCustom) throw (Exception) { |
31 |
int iLibsLoadedCount = 0; |
32 |
|
33 |
#if defined(WIN32) |
34 |
WIN32_FIND_DATA win32FindData; |
35 |
const String dllpattern = dir + "\\*.dll"; |
36 |
HANDLE hDir = FindFirstFile(dllpattern.c_str(), &win32FindData); |
37 |
if (hDir == INVALID_HANDLE_VALUE) { |
38 |
if (GetLastError() != ERROR_FILE_NOT_FOUND) { |
39 |
throw Exception("library path '" + dir + "' doesn't exist"); |
40 |
} else { |
41 |
return 0; // no file found |
42 |
} |
43 |
} |
44 |
|
45 |
do { |
46 |
// skip directory entries |
47 |
if (win32FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
48 |
continue; |
49 |
// dir entry name as full qualified path |
50 |
const String sPath = dir + "\\" + win32FindData.cFileName; |
51 |
// load the DLL |
52 |
HINSTANCE hinstLib; |
53 |
void* pDLL = hinstLib = LoadLibrary(sPath.c_str()); |
54 |
if (!pDLL) { |
55 |
std::cerr << "Failed to load DLL: " << sPath << std::endl; |
56 |
continue; |
57 |
} |
58 |
|
59 |
void* pFunct = GetProcAddress(hinstLib, funct.c_str()); |
60 |
if (pFunct == NULL) { |
61 |
std::cerr << "ERROR: unable to find " << funct << "() in " << sPath |
62 |
<< std::endl << std::flush; |
63 |
FreeLibrary(hinstLib); |
64 |
continue; |
65 |
} |
66 |
|
67 |
// call the the supplied callback function to report the found DLL |
68 |
pCallback(sPath, pDLL, pFunct, pCustom); |
69 |
|
70 |
iLibsLoadedCount++; |
71 |
|
72 |
} while (FindNextFile(hDir, &win32FindData)); |
73 |
|
74 |
if (hDir != INVALID_HANDLE_VALUE) FindClose(hDir); |
75 |
|
76 |
#else // POSIX |
77 |
|
78 |
#if defined(__APPLE__) /* 20071224 Toshi Nagata */ |
79 |
if (dir.find("~") == 0) |
80 |
dir.replace(0, 1, getenv("HOME")); |
81 |
#endif |
82 |
DIR* hDir = opendir(dir.c_str()); |
83 |
if (!hDir) { |
84 |
throw Exception("library path '" + dir + "' doesn't exist"); |
85 |
} |
86 |
for (dirent* pEntry = readdir(hDir); pEntry; pEntry = readdir(hDir)) { |
87 |
// dir entry name as full qualified path |
88 |
const String sPath = dir + "/" + pEntry->d_name; |
89 |
// skip entries that are not regular files |
90 |
struct stat entry_stat; |
91 |
if (lstat(sPath.c_str(), &entry_stat) != 0 || |
92 |
(entry_stat.st_mode & S_IFMT) != S_IFREG) |
93 |
continue; |
94 |
// skip files that are not .so files |
95 |
if (sPath.length() < 3 || |
96 |
sPath.substr(sPath.length() - 3) != ".so" && |
97 |
sPath.find(".so.") == String::npos) |
98 |
continue; |
99 |
// load the DLL |
100 |
void* pDLL = dlopen(sPath.c_str(), RTLD_NOW); |
101 |
if (!pDLL) { |
102 |
std::cerr << "failed to load DLL: '" << sPath << "', cause: " |
103 |
<< dlerror() << std::endl; |
104 |
continue; |
105 |
} |
106 |
// load the requested function |
107 |
void* pFunct = dlsym(pDLL, funct.c_str()); |
108 |
char* pcErr = dlerror(); |
109 |
if (pcErr || !pFunct) { |
110 |
std::cerr << "ERROR: unable to find " << funct << "() in '" << sPath |
111 |
<< "'" << std::endl << std::flush; |
112 |
dlclose(pDLL); |
113 |
continue; |
114 |
} |
115 |
|
116 |
// call the the supplied callback function to report the found and |
117 |
// successfully opened DLL |
118 |
pCallback(sPath, pDLL, pFunct, pCustom); |
119 |
|
120 |
iLibsLoadedCount++; |
121 |
} |
122 |
closedir(hDir); |
123 |
#endif |
124 |
|
125 |
return iLibsLoadedCount; |
126 |
} |
127 |
|
128 |
void* DynamicLibraryOpen(String filename) { |
129 |
#if defined(WIN32) |
130 |
return LoadLibrary(filename.c_str()); |
131 |
#else |
132 |
return dlopen(filename.c_str(), RTLD_NOW); |
133 |
#endif |
134 |
} |
135 |
|
136 |
void* DynamicLibraryGetSymbol(void* hDLL, String symbol) { |
137 |
#if defined(WIN32) |
138 |
return GetProcAddress(hDLL, symbol.c_str()); |
139 |
#else |
140 |
return dlsym(hDLL, symbol.c_str()); |
141 |
#endif |
142 |
} |
143 |
|
144 |
void DynamicLibraryClose(void* hDLL) { |
145 |
#if defined(WIN32) |
146 |
FreeLibrary(hDLL); |
147 |
#else |
148 |
dlclose(hDLL); |
149 |
#endif |
150 |
} |
151 |
|
152 |
} // namespace LinuxSampler |