Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / eglib / gmodule-unix.c
1 /*
2  * gmodule.c: dl* functions, glib style
3  *
4  * Author:
5  *   Gonzalo Paniagua Javier (gonzalo@novell.com)
6  *   Jonathan Chambers (joncham@gmail.com)
7  *   Robert Jordan (robertj@gmx.net)
8  *
9  * (C) 2006 Novell, Inc.
10  * (C) 2006 Jonathan Chambers
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining
13  * a copy of this software and associated documentation files (the
14  * "Software"), to deal in the Software without restriction, including
15  * without limitation the rights to use, copy, modify, merge, publish,
16  * distribute, sublicense, and/or sell copies of the Software, and to
17  * permit persons to whom the Software is furnished to do so, subject to
18  * the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be
21  * included in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  */
31 #include <config.h>
32
33 #include <glib.h>
34 #include <gmodule.h>
35
36 #if defined(G_OS_UNIX) && defined(HAVE_DLFCN_H)
37 #include <dlfcn.h>
38
39 /* For Linux and Solaris, need to add others as we port this */
40 #define LIBPREFIX "lib"
41 #define LIBSUFFIX ".so"
42
43 struct _GModule {
44         void *handle;
45 };
46
47 GModule *
48 g_module_open (const gchar *file, GModuleFlags flags)
49 {
50         int f = 0;
51         GModule *module;
52         void *handle;
53         
54         flags &= G_MODULE_BIND_MASK;
55         if ((flags & G_MODULE_BIND_LAZY) != 0)
56                 f |= RTLD_LAZY;
57         if ((flags & G_MODULE_BIND_LOCAL) != 0)
58                 f |= RTLD_LOCAL;
59
60         handle = dlopen (file, f);
61         if (handle == NULL)
62                 return NULL;
63         
64         module = g_new (GModule,1);
65         module->handle = handle;
66         
67         return module;
68 }
69
70 gboolean
71 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
72 {
73         if (symbol_name == NULL || symbol == NULL)
74                 return FALSE;
75
76         if (module == NULL || module->handle == NULL)
77                 return FALSE;
78
79         *symbol = dlsym (module->handle, symbol_name);
80         return (*symbol != NULL);
81 }
82
83 const gchar *
84 g_module_error (void)
85 {
86         return dlerror ();
87 }
88
89 gboolean
90 g_module_close (GModule *module)
91 {
92         void *handle;
93         if (module == NULL || module->handle == NULL)
94                 return FALSE;
95
96         handle = module->handle;
97         module->handle = NULL;
98         g_free (module);
99         return (0 == dlclose (handle));
100 }
101
102 #elif defined (G_OS_WIN32)
103 #include <windows.h>
104 #include <psapi.h>
105
106 #define LIBSUFFIX ".dll"
107 #define LIBPREFIX ""
108
109 struct _GModule {
110         HMODULE handle;
111         int main_module;
112 };
113
114 GModule *
115 g_module_open (const gchar *file, GModuleFlags flags)
116 {
117         GModule *module;
118         module = g_malloc (sizeof (GModule));
119         if (module == NULL)
120                 return NULL;
121
122         if (file != NULL) {
123                 gunichar2 *file16;
124                 file16 = u8to16(file); 
125                 module->main_module = FALSE;
126                 module->handle = LoadLibrary (file16);
127                 g_free(file16);
128                 if (!module->handle) {
129                         g_free (module);
130                         return NULL;
131                 }
132                         
133         } else {
134                 module->main_module = TRUE;
135                 module->handle = GetModuleHandle (NULL);
136         }
137
138         return module;
139 }
140
141 static gpointer
142 w32_find_symbol (const gchar *symbol_name)
143 {
144         HMODULE *modules;
145         DWORD buffer_size = sizeof (HMODULE) * 1024;
146         DWORD needed, i;
147
148         modules = (HMODULE *) g_malloc (buffer_size);
149
150         if (modules == NULL)
151                 return NULL;
152
153         if (!EnumProcessModules (GetCurrentProcess (), modules,
154                                  buffer_size, &needed)) {
155                 g_free (modules);
156                 return NULL;
157         }
158
159         /* check whether the supplied buffer was too small, realloc, retry */
160         if (needed > buffer_size) {
161                 g_free (modules);
162
163                 buffer_size = needed;
164                 modules = (HMODULE *) g_malloc (buffer_size);
165
166                 if (modules == NULL)
167                         return NULL;
168
169                 if (!EnumProcessModules (GetCurrentProcess (), modules,
170                                          buffer_size, &needed)) {
171                         g_free (modules);
172                         return NULL;
173                 }
174         }
175
176         for (i = 0; i < needed / sizeof (HANDLE); i++) {
177                 gpointer proc = (gpointer)(intptr_t)GetProcAddress (modules [i], symbol_name);
178                 if (proc != NULL) {
179                         g_free (modules);
180                         return proc;
181                 }
182         }
183
184         g_free (modules);
185         return NULL;
186 }
187
188 gboolean
189 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
190 {
191         if (module == NULL || symbol_name == NULL || symbol == NULL)
192                 return FALSE;
193
194         if (module->main_module) {
195                 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
196                 if (*symbol != NULL)
197                         return TRUE;
198
199                 *symbol = w32_find_symbol (symbol_name);
200                 return *symbol != NULL;
201         } else {
202                 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
203                 return *symbol != NULL;
204         }
205 }
206
207 const gchar *
208 g_module_error (void)
209 {
210         gchar* ret = NULL;
211         TCHAR* buf = NULL;
212         DWORD code = GetLastError ();
213
214         FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 
215                 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
216
217         ret = u16to8 (buf);
218         LocalFree(buf);
219
220         return ret;
221 }
222
223 gboolean
224 g_module_close (GModule *module)
225 {
226         HMODULE handle;
227         int main_module;
228
229         if (module == NULL || module->handle == NULL)
230                 return FALSE;
231
232         handle = module->handle;
233         main_module = module->main_module;
234         module->handle = NULL;
235         g_free (module);
236         return (main_module ? 1 : (0 == FreeLibrary (handle)));
237 }
238
239 #else
240
241 #define LIBSUFFIX ""
242 #define LIBPREFIX ""
243
244 GModule *
245 g_module_open (const gchar *file, GModuleFlags flags)
246 {
247         g_error ("%s", "g_module_open not implemented on this platform");
248         return NULL;
249 }
250
251 gboolean
252 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
253 {
254         g_error ("%s", "g_module_open not implemented on this platform");
255         return FALSE;
256 }
257
258 const gchar *
259 g_module_error (void)
260 {
261         g_error ("%s", "g_module_open not implemented on this platform");
262         return NULL;
263 }
264
265 gboolean
266 g_module_close (GModule *module)
267 {
268         g_error ("%s", "g_module_open not implemented on this platform");
269         return FALSE;
270 }
271 #endif
272
273 gchar *
274 g_module_build_path (const gchar *directory, const gchar *module_name)
275 {
276         const char *lib_prefix = "";
277         
278         if (module_name == NULL)
279                 return NULL;
280
281         if (strncmp (module_name, "lib", 3) != 0)
282                 lib_prefix = LIBPREFIX;
283         
284         if (directory && *directory)
285                 return g_strdup_printf ("%s/%s%s" LIBSUFFIX, directory, lib_prefix, module_name);
286         return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name); 
287 }
288