2008-10-11 Miguel de Icaza <miguel@novell.com>
[mono.git] / eglib / src / 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 <glib.h>
32 #include <gmodule.h>
33
34 #ifdef G_OS_UNIX
35 #include <dlfcn.h>
36
37 /* For Linux and Solaris, need to add others as we port this */
38 #define LIBPREFIX "lib"
39 #define LIBSUFFIX ".so"
40
41 struct _GModule {
42         void *handle;
43 };
44
45 GModule *
46 g_module_open (const gchar *file, GModuleFlags flags)
47 {
48         int f = 0;
49         GModule *module;
50         void *handle;
51         
52         flags &= G_MODULE_BIND_MASK;
53         if ((flags & G_MODULE_BIND_LAZY) != 0)
54                 f |= RTLD_LAZY;
55         if ((flags & G_MODULE_BIND_LOCAL) != 0)
56                 f |= RTLD_LOCAL;
57
58         handle = dlopen (file, f);
59         if (handle == NULL)
60                 return NULL;
61         
62         module = g_new (GModule,1);
63         module->handle = handle;
64         
65         return module;
66 }
67
68 gboolean
69 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
70 {
71         if (symbol_name == NULL || symbol == NULL)
72                 return FALSE;
73
74         if (module == NULL || module->handle == NULL)
75                 return FALSE;
76
77         *symbol = dlsym (module->handle, symbol_name);
78         return (*symbol != NULL);
79 }
80
81 const gchar *
82 g_module_error (void)
83 {
84         return dlerror ();
85 }
86
87 gboolean
88 g_module_close (GModule *module)
89 {
90         void *handle;
91         if (module == NULL || module->handle == NULL)
92                 return FALSE;
93
94         handle = module->handle;
95         module->handle = NULL;
96         g_free (module);
97         return (0 == dlclose (handle));
98 }
99
100 #elif defined (G_OS_WIN32)
101 #include <windows.h>
102 #include <psapi.h>
103
104 #define LIBSUFFIX ".dll"
105 #define LIBPREFIX ""
106
107 struct _GModule {
108         HMODULE handle;
109         int main_module;
110 };
111
112 GModule *
113 g_module_open (const gchar *file, GModuleFlags flags)
114 {
115         GModule *module;
116         module = g_malloc (sizeof (GModule));
117         if (module == NULL)
118                 return NULL;
119
120         if (file != NULL) {
121                 gunichar2 *file16;
122                 file16 = u8to16(file); 
123                 module->main_module = FALSE;
124                 module->handle = LoadLibrary (file16);
125                 g_free(file16);
126                 if (!module->handle) {
127                         g_free (module);
128                         return NULL;
129                 }
130                         
131         } else {
132                 module->main_module = TRUE;
133                 module->handle = GetModuleHandle (NULL);
134         }
135
136         return module;
137 }
138
139 static gpointer
140 w32_find_symbol (const gchar *symbol_name)
141 {
142         HMODULE *modules;
143         DWORD buffer_size = sizeof (HMODULE) * 1024;
144         DWORD needed, i;
145
146         modules = (HMODULE *) g_malloc (buffer_size);
147
148         if (modules == NULL)
149                 return NULL;
150
151         if (!EnumProcessModules (GetCurrentProcess (), modules,
152                                  buffer_size, &needed)) {
153                 g_free (modules);
154                 return NULL;
155         }
156
157         /* check whether the supplied buffer was too small, realloc, retry */
158         if (needed > buffer_size) {
159                 g_free (modules);
160
161                 buffer_size = needed;
162                 modules = (HMODULE *) g_malloc (buffer_size);
163
164                 if (modules == NULL)
165                         return NULL;
166
167                 if (!EnumProcessModules (GetCurrentProcess (), modules,
168                                          buffer_size, &needed)) {
169                         g_free (modules);
170                         return NULL;
171                 }
172         }
173
174         for (i = 0; i < needed / sizeof (HANDLE); i++) {
175                 gpointer proc = (gpointer)(intptr_t)GetProcAddress (modules [i], symbol_name);
176                 if (proc != NULL) {
177                         g_free (modules);
178                         return proc;
179                 }
180         }
181
182         g_free (modules);
183         return NULL;
184 }
185
186 gboolean
187 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
188 {
189         if (module == NULL || symbol_name == NULL || symbol == NULL)
190                 return FALSE;
191
192         if (module->main_module) {
193                 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
194                 if (*symbol != NULL)
195                         return TRUE;
196
197                 *symbol = w32_find_symbol (symbol_name);
198                 return *symbol != NULL;
199         } else {
200                 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
201                 return *symbol != NULL;
202         }
203 }
204
205 const gchar *
206 g_module_error (void)
207 {
208         gchar* ret = NULL;
209         TCHAR* buf = NULL;
210         DWORD code = GetLastError ();
211
212         FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 
213                 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
214
215         ret = u16to8 (buf);
216         LocalFree(buf);
217
218         return ret;
219 }
220
221 gboolean
222 g_module_close (GModule *module)
223 {
224         HMODULE handle;
225         int main_module;
226
227         if (module == NULL || module->handle == NULL)
228                 return FALSE;
229
230         handle = module->handle;
231         main_module = module->main_module;
232         module->handle = NULL;
233         g_free (module);
234         return (main_module ? 1 : (0 == FreeLibrary (handle)));
235 }
236
237 #else
238
239 #define LIBSUFFIX ""
240 #define LIBPREFIX ""
241
242 GModule *
243 g_module_open (const gchar *file, GModuleFlags flags)
244 {
245         g_error ("%s", "g_module_open not implemented on this platform");
246         return NULL;
247 }
248
249 gboolean
250 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
251 {
252         g_error ("%s", "g_module_open not implemented on this platform");
253         return FALSE;
254 }
255
256 const gchar *
257 g_module_error (void)
258 {
259         g_error ("%s", "g_module_open not implemented on this platform");
260         return NULL;
261 }
262
263 gboolean
264 g_module_close (GModule *module)
265 {
266         g_error ("%s", "g_module_open not implemented on this platform");
267         return FALSE;
268 }
269 #endif
270
271 gchar *
272 g_module_build_path (const gchar *directory, const gchar *module_name)
273 {
274         char *lib_prefix = "";
275         
276         if (module_name == NULL)
277                 return NULL;
278
279         if (strncmp (module_name, "lib", 3) != 0)
280                 lib_prefix = LIBPREFIX;
281         
282         if (directory && *directory){ 
283                 
284                 return g_strdup_printf ("%s/%s%s" LIBSUFFIX, directory, lib_prefix, module_name);
285         }
286         return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name); 
287 }
288