dladdr shim for gmodule; try to enable crash reporter on AIX (#15808)
[mono-project.git] / mono / eglib / gmodule-win32.c
blob15cbed35bf8b90ac194821464b7fd8734fc62749
1 /*
2 * gmodule.c: dl* functions, glib style
4 * Author:
5 * Gonzalo Paniagua Javier (gonzalo@novell.com)
6 * Jonathan Chambers (joncham@gmail.com)
7 * Robert Jordan (robertj@gmx.net)
9 * (C) 2006 Novell, Inc.
10 * (C) 2006 Jonathan Chambers
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:
20 * The above copyright notice and this permission notice shall be
21 * included in all copies or substantial portions of the Software.
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.
31 #include <config.h>
32 #include <glib.h>
33 #ifndef PSAPI_VERSION
34 #define PSAPI_VERSION 2 // Use the Windows 7 or newer version more directly.
35 #endif
36 #include <windows.h>
37 #include <psapi.h>
38 #include <gmodule-win32-internals.h>
40 #define LIBSUFFIX ".dll"
41 #define LIBPREFIX ""
43 struct _GModule {
44 HMODULE handle;
45 int main_module;
48 GModule *
49 g_module_open (const gchar *file, GModuleFlags flags)
51 GModule *module;
52 module = g_malloc (sizeof (GModule));
53 if (module == NULL)
54 return NULL;
56 if (file != NULL) {
57 gunichar2 *file16;
58 file16 = u8to16(file);
59 module->main_module = FALSE;
60 module->handle = LoadLibraryW (file16);
61 g_free(file16);
62 if (!module->handle) {
63 g_free (module);
64 return NULL;
67 } else {
68 module->main_module = TRUE;
69 module->handle = GetModuleHandle (NULL);
72 return module;
75 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
76 gpointer
77 w32_find_symbol (const gchar *symbol_name)
79 HMODULE *modules;
80 DWORD buffer_size = sizeof (HMODULE) * 1024;
81 DWORD needed, i;
83 modules = (HMODULE *) g_malloc (buffer_size);
85 if (modules == NULL)
86 return NULL;
88 if (!EnumProcessModules (GetCurrentProcess (), modules,
89 buffer_size, &needed)) {
90 g_free (modules);
91 return NULL;
94 /* check whether the supplied buffer was too small, realloc, retry */
95 if (needed > buffer_size) {
96 g_free (modules);
98 buffer_size = needed;
99 modules = (HMODULE *) g_malloc (buffer_size);
101 if (modules == NULL)
102 return NULL;
104 if (!EnumProcessModules (GetCurrentProcess (), modules,
105 buffer_size, &needed)) {
106 g_free (modules);
107 return NULL;
111 for (i = 0; i < needed / sizeof (HANDLE); i++) {
112 gpointer proc = (gpointer)(intptr_t)GetProcAddress (modules [i], symbol_name);
113 if (proc != NULL) {
114 g_free (modules);
115 return proc;
119 g_free (modules);
120 return NULL;
122 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
124 gboolean
125 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
127 if (module == NULL || symbol_name == NULL || symbol == NULL)
128 return FALSE;
130 if (module->main_module) {
131 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
132 if (*symbol != NULL)
133 return TRUE;
135 *symbol = w32_find_symbol (symbol_name);
136 return *symbol != NULL;
137 } else {
138 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
139 return *symbol != NULL;
143 gboolean
144 g_module_address (void *addr, char *file_name, size_t file_name_len,
145 void **file_base, char *sym_name, size_t sym_name_len,
146 void **sym_addr)
148 HMODULE module;
150 * We have to cast the address because usually this func works with strings,
151 * this being an exception.
153 BOOL ret = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)addr, &module);
154 if (ret)
155 return FALSE;
157 if (file_name != NULL && file_name_len >= 1) {
158 /* sigh, non-const. AIX for POSIX is the same way. */
159 TCHAR *fname = (TCHAR*)g_alloca(255);
160 DWORD bytes = GetModuleFileName(module, fname, 255);
161 /* XXX: check for ERROR_INSUFFICIENT_BUFFER? */
162 if (bytes) {
163 /* Convert back to UTF-8 from wide for runtime */
164 *file_name = '\0'; /* XXX */
165 } else {
166 *file_name = '\0';
169 /* XXX: implement the rest */
170 if (file_base != NULL)
171 *file_base = NULL;
172 if (sym_name != NULL && sym_name_len >= 1)
173 sym_name[0] = '\0';
174 if (sym_addr != NULL)
175 *sym_addr = NULL;
177 /* -1 reference count to avoid leaks; Ex variant does +1 refcount */
178 FreeLibrary (module);
179 return TRUE;
182 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
183 const gchar *
184 g_module_error (void)
186 gchar* ret = NULL;
187 TCHAR* buf = NULL;
188 DWORD code = GetLastError ();
190 /* FIXME: buf must not be NULL! */
191 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
192 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
194 ret = u16to8 (buf);
195 LocalFree(buf);
197 return ret;
199 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
201 gboolean
202 g_module_close (GModule *module)
204 HMODULE handle;
205 int main_module;
207 if (module == NULL || module->handle == NULL)
208 return FALSE;
210 handle = module->handle;
211 main_module = module->main_module;
212 module->handle = NULL;
213 g_free (module);
214 return (main_module ? 1 : (0 == FreeLibrary (handle)));
217 gchar *
218 g_module_build_path (const gchar *directory, const gchar *module_name)
220 const char *lib_prefix = "";
222 if (module_name == NULL)
223 return NULL;
225 if (strncmp (module_name, "lib", 3) != 0)
226 lib_prefix = LIBPREFIX;
228 if (directory && *directory){
230 return g_strdup_printf ("%s/%s%s" LIBSUFFIX, directory, lib_prefix, module_name);
232 return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name);
235 // This is not about GModule but is still a close fit.
236 // This is not named "g_" but that should be ok.
237 // g_free the result
238 // No MAX_PATH limit.
240 // Prefer mono_get_module_filename over mono_get_module_filename_ex and mono_get_module_basename.
241 // Prefer not-ex, not-base.
243 gboolean
244 mono_get_module_filename (gpointer mod, gunichar2 **pstr, guint32 *plength)
246 gunichar2 *str = NULL;
247 guint32 capacity = MAX_PATH; // tunable
248 guint32 length = 0;
249 gboolean success = FALSE;
251 while (TRUE)
253 length = 0;
254 if (capacity > (1 << 24))
255 break;
256 str = g_new (gunichar2, capacity);
257 if (!str)
258 break;
259 length = GetModuleFileNameW ((HMODULE)mod, str, capacity);
260 success = length && length < (capacity - 1); // This function does not truncate, but - 1 anyway.
261 if (success)
262 break;
263 g_free (str); // error or too small
264 str = NULL;
265 if (!length) // error
266 break;
267 capacity *= 2;
269 *pstr = str;
270 *plength = length;
271 return success;
274 // This is not about GModule but is still a close fit.
275 // This is not named "g_" but that should be ok.
276 // g_free the result
277 // No MAX_PATH limit.
279 // Prefer mono_get_module_filename over mono_get_module_filename_ex and mono_get_module_basename.
280 // Prefer not-ex, not-base.
282 gboolean
283 mono_get_module_filename_ex (gpointer process, gpointer mod, gunichar2 **pstr, guint32 *plength)
285 gunichar2 *str = NULL;
286 guint32 capacity = MAX_PATH; // tunable
287 guint32 length = 0;
288 gboolean success = FALSE;
290 while (TRUE)
292 length = 0;
293 if (capacity > (1 << 24))
294 break;
295 str = g_new (gunichar2, capacity);
296 if (!str)
297 break;
298 length = GetModuleFileNameExW (process, (HMODULE)mod, str, capacity);
299 success = length && length < (capacity - 1); // This function truncates, thus the - 1.
300 if (success)
301 break;
302 g_free (str); // error or too small
303 str = NULL;
304 if (!length) // error
305 break;
306 capacity *= 2;
308 *pstr = str;
309 *plength = length;
310 return success;
313 // This is not about GModule but is still a close fit.
314 // This is not named "g_" but that should be ok.
315 // g_free the result
316 // No MAX_PATH limit.
318 // Prefer mono_get_module_filename over mono_get_module_filename_ex and mono_get_module_basename.
319 // Prefer not-ex, not-base.
321 gboolean
322 mono_get_module_basename (gpointer process, gpointer mod, gunichar2 **pstr, guint32 *plength)
324 gunichar2 *str = NULL;
325 guint32 capacity = MAX_PATH; // tunable
326 guint32 length = 0;
327 gboolean success = FALSE;
329 while (TRUE)
331 length = 0;
332 if (capacity > (1 << 24))
333 break;
334 str = g_new (gunichar2, capacity);
335 if (!str)
336 break;
337 length = GetModuleBaseNameW (process, (HMODULE)mod, str, capacity);
338 success = length && length < (capacity - 1); // This function truncates, thus the - 1.
339 if (success)
340 break;
341 g_free (str); // error or too small
342 str = NULL;
343 if (!length) // error
344 break;
345 capacity *= 2;
347 *pstr = str;
348 *plength = length;
349 return success;
352 // g_free the result
353 // No MAX_PATH limit.
354 gboolean
355 mono_get_current_directory (gunichar2 **pstr, guint32 *plength)
357 gunichar2 *str = NULL;
358 guint32 capacity = MAX_PATH; // tunable
359 guint32 length = 0;
360 gboolean success = FALSE;
362 while (TRUE)
364 length = 0;
365 if (capacity > (1 << 24))
366 break;
367 str = g_new (gunichar2, capacity);
368 if (!str)
369 break;
370 // Call in loop, not just twice, in case another thread is changing it.
371 // Result is transient in currentness and validity (can get deleted or become a file).
372 length = GetCurrentDirectoryW (capacity, str);
373 success = length && length < (capacity - 1);
374 if (success)
375 break;
376 g_free (str); // error or too small
377 str = NULL;
378 if (!length) // error
379 break;
380 capacity *= 2;
382 *pstr = str;
383 *plength = length;
384 return success;