[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / eglib / gmodule-win32.c
blobb4521c61cd20fb8dec5269658ebfafa048ee6d69
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.h>
39 #include "../utils/w32subset.h"
41 #define LIBSUFFIX ".dll"
42 #define LIBPREFIX ""
44 struct _GModule {
45 HMODULE handle;
46 int main_module;
49 GModule *
50 g_module_open (const gchar *file, GModuleFlags flags)
52 GModule *module;
53 module = g_malloc (sizeof (GModule));
54 if (module == NULL)
55 return NULL;
57 if (file != NULL) {
58 gunichar2 *file16;
59 file16 = u8to16(file);
60 module->main_module = FALSE;
61 module->handle = LoadLibraryW (file16);
62 g_free(file16);
63 if (!module->handle) {
64 g_free (module);
65 return NULL;
68 } else {
69 module->main_module = TRUE;
70 module->handle = GetModuleHandle (NULL);
73 return module;
76 #if HAVE_API_SUPPORT_WIN32_ENUM_PROCESS_MODULES
77 gpointer
78 w32_find_symbol (const gchar *symbol_name)
80 HMODULE *modules;
81 DWORD buffer_size = sizeof (HMODULE) * 1024;
82 DWORD needed, i;
84 modules = (HMODULE *) g_malloc (buffer_size);
86 if (modules == NULL)
87 return NULL;
89 if (!EnumProcessModules (GetCurrentProcess (), modules,
90 buffer_size, &needed)) {
91 g_free (modules);
92 return NULL;
95 /* check whether the supplied buffer was too small, realloc, retry */
96 if (needed > buffer_size) {
97 g_free (modules);
99 buffer_size = needed;
100 modules = (HMODULE *) g_malloc (buffer_size);
102 if (modules == NULL)
103 return NULL;
105 if (!EnumProcessModules (GetCurrentProcess (), modules,
106 buffer_size, &needed)) {
107 g_free (modules);
108 return NULL;
112 for (i = 0; i < needed / sizeof (HANDLE); i++) {
113 gpointer proc = (gpointer)(intptr_t)GetProcAddress (modules [i], symbol_name);
114 if (proc != NULL) {
115 g_free (modules);
116 return proc;
120 g_free (modules);
121 return NULL;
123 #elif !HAVE_EXTERN_DEFINED_WIN32_ENUM_PROCESS_MODULES
124 gpointer
125 w32_find_symbol (const gchar *symbol_name)
127 g_unsupported_api ("EnumProcessModules");
128 SetLastError (ERROR_NOT_SUPPORTED);
129 return NULL;
131 #else
132 extern gpointer w32_find_symbol (const gchar *symbol_name);
133 #endif /* HAVE_API_SUPPORT_WIN32_ENUM_PROCESS_MODULES */
135 gboolean
136 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
138 if (module == NULL || symbol_name == NULL || symbol == NULL)
139 return FALSE;
141 if (module->main_module) {
142 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
143 if (*symbol != NULL)
144 return TRUE;
146 *symbol = w32_find_symbol (symbol_name);
147 return *symbol != NULL;
148 } else {
149 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
150 return *symbol != NULL;
154 #if HAVE_API_SUPPORT_WIN32_GET_MODULE_HANDLE_EX
155 gboolean
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,
158 void **sym_addr)
160 HMODULE module;
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);
166 if (!ret)
167 return FALSE;
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));
173 if (bytes) {
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))
180 *file_name = '\0';
181 } else {
182 *file_name = '\0';
185 /* XXX: implement the rest */
186 if (file_base != NULL)
187 *file_base = NULL;
188 if (sym_name != NULL && sym_name_len >= 1)
189 sym_name[0] = '\0';
190 if (sym_addr != NULL)
191 *sym_addr = NULL;
193 /* -1 reference count to avoid leaks; Ex variant does +1 refcount */
194 FreeLibrary (module);
195 return TRUE;
197 #elif !HAVE_EXTERN_DEFINED_WIN32_GET_MODULE_HANDLE_EX
198 gboolean
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,
201 void **sym_addr)
203 g_unsupported_api ("GetModuleHandleEx");
204 SetLastError (ERROR_NOT_SUPPORTED);
205 return FALSE;
207 #endif /* HAVE_API_SUPPORT_WIN32_GET_MODULE_HANDLE_EX */
209 #if HAVE_API_SUPPORT_WIN32_FORMAT_MESSAGE
210 const gchar *
211 g_module_error (void)
213 gchar* ret = NULL;
214 DWORD code = GetLastError ();
215 #if HAVE_API_SUPPORT_WIN32_LOCAL_ALLOC_FREE
216 PWSTR buf = NULL;
217 if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (PWSTR)&buf, 0, NULL)) {
218 ret = u16to8 (buf);
219 LocalFree (buf);
221 #else
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);
228 #endif
229 return ret;
231 #elif !HAVE_EXTERN_DEFINED_WIN32_FORMAT_MESSAGE
232 const gchar *
233 g_module_error (void)
235 return g_strdup_printf ("GetLastError=%d. FormatMessage not supported.", GetLastError ());
237 #endif /* HAVE_API_SUPPORT_WIN32_FORMAT_MESSAGE */
239 gboolean
240 g_module_close (GModule *module)
242 HMODULE handle;
243 int main_module;
245 if (module == NULL || module->handle == NULL)
246 return FALSE;
248 handle = module->handle;
249 main_module = module->main_module;
250 module->handle = NULL;
251 g_free (module);
252 return (main_module ? 1 : (0 == FreeLibrary (handle)));
255 gchar *
256 g_module_build_path (const gchar *directory, const gchar *module_name)
258 const char *lib_prefix = "";
260 if (module_name == NULL)
261 return 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.
275 // g_free the result
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.
281 gboolean
282 mono_get_module_filename (gpointer mod, gunichar2 **pstr, guint32 *plength)
284 gunichar2 *str = NULL;
285 guint32 capacity = MAX_PATH; // tunable
286 guint32 length = 0;
287 gboolean success = FALSE;
289 while (TRUE)
291 length = 0;
292 if (capacity > (1 << 24))
293 break;
294 str = g_new (gunichar2, capacity);
295 if (!str)
296 break;
297 length = GetModuleFileNameW ((HMODULE)mod, str, capacity);
298 success = length && length < (capacity - 1); // This function does not truncate, but - 1 anyway.
299 if (success)
300 break;
301 g_free (str); // error or too small
302 str = NULL;
303 if (!length) // error
304 break;
305 capacity *= 2;
307 *pstr = str;
308 *plength = length;
309 return success;
312 // This is not about GModule but is still a close fit.
313 // This is not named "g_" but that should be ok.
314 // g_free the result
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
321 gboolean
322 mono_get_module_filename_ex (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 = GetModuleFileNameExW (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;
351 #elif !HAVE_EXTERN_DEFINED_WIN32_GET_MODULE_FILE_NAME_EX
352 gboolean
353 mono_get_module_filename_ex (gpointer process, gpointer mod, gunichar2 **pstr, guint32 *plength)
355 g_unsupported_api ("GetModuleFileNameEx");
356 SetLastError (ERROR_NOT_SUPPORTED);
357 return FALSE;
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.
363 // g_free the result
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
370 gboolean
371 mono_get_module_basename (gpointer process, gpointer mod, gunichar2 **pstr, guint32 *plength)
373 gunichar2 *str = NULL;
374 guint32 capacity = MAX_PATH; // tunable
375 guint32 length = 0;
376 gboolean success = FALSE;
378 while (TRUE)
380 length = 0;
381 if (capacity > (1 << 24))
382 break;
383 str = g_new (gunichar2, capacity);
384 if (!str)
385 break;
386 length = GetModuleBaseNameW (process, (HMODULE)mod, str, capacity);
387 success = length && length < (capacity - 1); // This function truncates, thus the - 1.
388 if (success)
389 break;
390 g_free (str); // error or too small
391 str = NULL;
392 if (!length) // error
393 break;
394 capacity *= 2;
396 *pstr = str;
397 *plength = length;
398 return success;
400 #elif !HAVE_EXTERN_DEFINED_WIN32_GET_MODULE_BASE_NAME
401 gboolean
402 mono_get_module_basename (gpointer process, gpointer mod, gunichar2 **pstr, guint32 *plength)
404 g_unsupported_api ("GetModuleBaseName");
405 SetLastError (ERROR_NOT_SUPPORTED);
406 return FALSE;
408 #endif /* HAVE_API_SUPPORT_WIN32_GET_MODULE_BASE_NAME */
410 // g_free the result
411 // No MAX_PATH limit.
412 gboolean
413 mono_get_current_directory (gunichar2 **pstr, guint32 *plength)
415 gunichar2 *str = NULL;
416 guint32 capacity = MAX_PATH; // tunable
417 guint32 length = 0;
418 gboolean success = FALSE;
420 while (TRUE)
422 length = 0;
423 if (capacity > (1 << 24))
424 break;
425 str = g_new (gunichar2, capacity);
426 if (!str)
427 break;
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);
432 if (success)
433 break;
434 g_free (str); // error or too small
435 str = NULL;
436 if (!length) // error
437 break;
438 capacity *= 2;
440 *pstr = str;
441 *plength = length;
442 return success;