2 * gmodule.c: dl* functions, glib style
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.
34 #define PSAPI_VERSION 2 // Use the Windows 7 or newer version more directly.
39 #include "../utils/w32subset.h"
41 #define LIBSUFFIX ".dll"
50 g_module_open (const gchar
*file
, GModuleFlags flags
)
53 module
= g_malloc (sizeof (GModule
));
59 file16
= u8to16(file
);
60 module
->main_module
= FALSE
;
61 module
->handle
= LoadLibraryW (file16
);
63 if (!module
->handle
) {
69 module
->main_module
= TRUE
;
70 module
->handle
= GetModuleHandle (NULL
);
76 #if HAVE_API_SUPPORT_WIN32_ENUM_PROCESS_MODULES
78 w32_find_symbol (const gchar
*symbol_name
)
81 DWORD buffer_size
= sizeof (HMODULE
) * 1024;
84 modules
= (HMODULE
*) g_malloc (buffer_size
);
89 if (!EnumProcessModules (GetCurrentProcess (), modules
,
90 buffer_size
, &needed
)) {
95 /* check whether the supplied buffer was too small, realloc, retry */
96 if (needed
> buffer_size
) {
100 modules
= (HMODULE
*) g_malloc (buffer_size
);
105 if (!EnumProcessModules (GetCurrentProcess (), modules
,
106 buffer_size
, &needed
)) {
112 for (i
= 0; i
< needed
/ sizeof (HANDLE
); i
++) {
113 gpointer proc
= (gpointer
)(intptr_t)GetProcAddress (modules
[i
], symbol_name
);
123 #elif !HAVE_EXTERN_DEFINED_WIN32_ENUM_PROCESS_MODULES
125 w32_find_symbol (const gchar
*symbol_name
)
127 g_unsupported_api ("EnumProcessModules");
128 SetLastError (ERROR_NOT_SUPPORTED
);
132 extern gpointer
w32_find_symbol (const gchar
*symbol_name
);
133 #endif /* HAVE_API_SUPPORT_WIN32_ENUM_PROCESS_MODULES */
136 g_module_symbol (GModule
*module
, const gchar
*symbol_name
, gpointer
*symbol
)
138 if (module
== NULL
|| symbol_name
== NULL
|| symbol
== NULL
)
141 if (module
->main_module
) {
142 *symbol
= (gpointer
)(intptr_t)GetProcAddress (module
->handle
, symbol_name
);
146 *symbol
= w32_find_symbol (symbol_name
);
147 return *symbol
!= NULL
;
149 *symbol
= (gpointer
)(intptr_t)GetProcAddress (module
->handle
, symbol_name
);
150 return *symbol
!= NULL
;
154 #if HAVE_API_SUPPORT_WIN32_GET_MODULE_HANDLE_EX
156 g_module_address (void *addr
, char *file_name
, size_t file_name_len
,
157 void **file_base
, char *sym_name
, size_t sym_name_len
,
162 * We have to cast the address because usually this func works with strings,
163 * this being an exception.
165 BOOL ret
= GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
, (LPCWSTR
)addr
, &module
);
169 if (file_name
!= NULL
&& file_name_len
>= 1) {
170 /* sigh, non-const. AIX for POSIX is the same way. */
171 WCHAR fname
[MAX_PATH
];
172 DWORD bytes
= GetModuleFileNameW (module
, fname
, G_N_ELEMENTS (fname
));
174 /* Convert back to UTF-8 from wide for runtime */
175 GFixedBufferCustomAllocatorData custom_alloc_data
;
176 custom_alloc_data
.buffer
= file_name
;
177 custom_alloc_data
.buffer_size
= file_name_len
;
178 custom_alloc_data
.req_buffer_size
= 0;
179 if (!g_utf16_to_utf8_custom_alloc (fname
, -1, NULL
, NULL
, g_fixed_buffer_custom_allocator
, &custom_alloc_data
, NULL
))
185 /* XXX: implement the rest */
186 if (file_base
!= NULL
)
188 if (sym_name
!= NULL
&& sym_name_len
>= 1)
190 if (sym_addr
!= NULL
)
193 /* -1 reference count to avoid leaks; Ex variant does +1 refcount */
194 FreeLibrary (module
);
197 #elif !HAVE_EXTERN_DEFINED_WIN32_GET_MODULE_HANDLE_EX
199 g_module_address (void *addr
, char *file_name
, size_t file_name_len
,
200 void **file_base
, char *sym_name
, size_t sym_name_len
,
203 g_unsupported_api ("GetModuleHandleEx");
204 SetLastError (ERROR_NOT_SUPPORTED
);
207 #endif /* HAVE_API_SUPPORT_WIN32_GET_MODULE_HANDLE_EX */
209 #if HAVE_API_SUPPORT_WIN32_FORMAT_MESSAGE
211 g_module_error (void)
214 DWORD code
= GetLastError ();
215 #if HAVE_API_SUPPORT_WIN32_LOCAL_ALLOC_FREE
217 if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER
, NULL
, code
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (PWSTR
)&buf
, 0, NULL
)) {
222 WCHAR local_buf
[1024];
223 if (!FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
,
224 code
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), local_buf
, G_N_ELEMENTS (local_buf
) - 1, NULL
) )
225 local_buf
[0] = TEXT('\0');
227 ret
= u16to8 (local_buf
);
231 #elif !HAVE_EXTERN_DEFINED_WIN32_FORMAT_MESSAGE
233 g_module_error (void)
235 return g_strdup_printf ("GetLastError=%d. FormatMessage not supported.", GetLastError ());
237 #endif /* HAVE_API_SUPPORT_WIN32_FORMAT_MESSAGE */
240 g_module_close (GModule
*module
)
245 if (module
== NULL
|| module
->handle
== NULL
)
248 handle
= module
->handle
;
249 main_module
= module
->main_module
;
250 module
->handle
= NULL
;
252 return (main_module
? 1 : (0 == FreeLibrary (handle
)));
256 g_module_build_path (const gchar
*directory
, const gchar
*module_name
)
258 const char *lib_prefix
= "";
260 if (module_name
== NULL
)
263 if (strncmp (module_name
, "lib", 3) != 0)
264 lib_prefix
= LIBPREFIX
;
266 if (directory
&& *directory
){
268 return g_strdup_printf ("%s/%s%s" LIBSUFFIX
, directory
, lib_prefix
, module_name
);
270 return g_strdup_printf ("%s%s" LIBSUFFIX
, lib_prefix
, module_name
);
273 // This is not about GModule but is still a close fit.
274 // This is not named "g_" but that should be ok.
276 // No MAX_PATH limit.
278 // Prefer mono_get_module_filename over mono_get_module_filename_ex and mono_get_module_basename.
279 // Prefer not-ex, not-base.
282 mono_get_module_filename (gpointer mod
, gunichar2
**pstr
, guint32
*plength
)
284 gunichar2
*str
= NULL
;
285 guint32 capacity
= MAX_PATH
; // tunable
287 gboolean success
= FALSE
;
292 if (capacity
> (1 << 24))
294 str
= g_new (gunichar2
, capacity
);
297 length
= GetModuleFileNameW ((HMODULE
)mod
, str
, capacity
);
298 success
= length
&& length
< (capacity
- 1); // This function does not truncate, but - 1 anyway.
301 g_free (str
); // error or too small
303 if (!length
) // error
312 // This is not about GModule but is still a close fit.
313 // This is not named "g_" but that should be ok.
315 // No MAX_PATH limit.
317 // Prefer mono_get_module_filename over mono_get_module_filename_ex and mono_get_module_basename.
318 // Prefer not-ex, not-base.
320 #if HAVE_API_SUPPORT_WIN32_GET_MODULE_FILE_NAME_EX
322 mono_get_module_filename_ex (gpointer process
, gpointer mod
, gunichar2
**pstr
, guint32
*plength
)
324 gunichar2
*str
= NULL
;
325 guint32 capacity
= MAX_PATH
; // tunable
327 gboolean success
= FALSE
;
332 if (capacity
> (1 << 24))
334 str
= g_new (gunichar2
, capacity
);
337 length
= GetModuleFileNameExW (process
, (HMODULE
)mod
, str
, capacity
);
338 success
= length
&& length
< (capacity
- 1); // This function truncates, thus the - 1.
341 g_free (str
); // error or too small
343 if (!length
) // error
351 #elif !HAVE_EXTERN_DEFINED_WIN32_GET_MODULE_FILE_NAME_EX
353 mono_get_module_filename_ex (gpointer process
, gpointer mod
, gunichar2
**pstr
, guint32
*plength
)
355 g_unsupported_api ("GetModuleFileNameEx");
356 SetLastError (ERROR_NOT_SUPPORTED
);
359 #endif /* HAVE_API_SUPPORT_WIN32_GET_MODULE_FILE_NAME_EX */
361 // This is not about GModule but is still a close fit.
362 // This is not named "g_" but that should be ok.
364 // No MAX_PATH limit.
366 // Prefer mono_get_module_filename over mono_get_module_filename_ex and mono_get_module_basename.
367 // Prefer not-ex, not-base.
369 #if HAVE_API_SUPPORT_WIN32_GET_MODULE_BASE_NAME
371 mono_get_module_basename (gpointer process
, gpointer mod
, gunichar2
**pstr
, guint32
*plength
)
373 gunichar2
*str
= NULL
;
374 guint32 capacity
= MAX_PATH
; // tunable
376 gboolean success
= FALSE
;
381 if (capacity
> (1 << 24))
383 str
= g_new (gunichar2
, capacity
);
386 length
= GetModuleBaseNameW (process
, (HMODULE
)mod
, str
, capacity
);
387 success
= length
&& length
< (capacity
- 1); // This function truncates, thus the - 1.
390 g_free (str
); // error or too small
392 if (!length
) // error
400 #elif !HAVE_EXTERN_DEFINED_WIN32_GET_MODULE_BASE_NAME
402 mono_get_module_basename (gpointer process
, gpointer mod
, gunichar2
**pstr
, guint32
*plength
)
404 g_unsupported_api ("GetModuleBaseName");
405 SetLastError (ERROR_NOT_SUPPORTED
);
408 #endif /* HAVE_API_SUPPORT_WIN32_GET_MODULE_BASE_NAME */
411 // No MAX_PATH limit.
413 mono_get_current_directory (gunichar2
**pstr
, guint32
*plength
)
415 gunichar2
*str
= NULL
;
416 guint32 capacity
= MAX_PATH
; // tunable
418 gboolean success
= FALSE
;
423 if (capacity
> (1 << 24))
425 str
= g_new (gunichar2
, capacity
);
428 // Call in loop, not just twice, in case another thread is changing it.
429 // Result is transient in currentness and validity (can get deleted or become a file).
430 length
= GetCurrentDirectoryW (capacity
, str
);
431 success
= length
&& length
< (capacity
- 1);
434 g_free (str
); // error or too small
436 if (!length
) // error