Tue Feb 26 15:43:26 CET 2008 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / utils / mono-dl.c
index c65e380e9228fb6d0d9a967aec44bb879aa74b5f..1986112a5d02dd4198b6673384d0d9de4f1a3032 100644 (file)
@@ -29,29 +29,15 @@ static const char suffixes [][4] = {
 #ifdef PLATFORM_WIN32
 
 #include <windows.h>
+#include <psapi.h>
 
 #define SO_HANDLE_TYPE HMODULE
-#define LL_SO_OPEN(file,flags) (file)? LoadLibrary ((file)): GetModuleHandle (NULL)
-#define LL_SO_CLOSE(module) do { if ((module)->main_module) FreeLibrary ((module)->handle); } while (0)
-#define LL_SO_SYMBOL(handle, name) GetProcAddress ((handle), (name))
+#define LL_SO_OPEN(file,flags) w32_load_module ((file), (flags))
+#define LL_SO_CLOSE(module) do { if (!(module)->main_module) FreeLibrary ((module)->handle); } while (0)
+#define LL_SO_SYMBOL(module, name) w32_find_symbol ((module), (name))
 #define LL_SO_TRFLAGS(flags) 0
 #define LL_SO_ERROR() w32_dlerror ()
 
-static char*
-w32_dlerror (void)
-{
-       char* ret;
-       TCHAR* buf = NULL;
-       DWORD code = GetLastError ();
-
-       FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
-               code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
-
-       ret = g_strdup (buf);
-       LocalFree (buf);
-       return ret;
-}
-
 #elif defined (HAVE_DL_LOADER)
 
 #include <dlfcn.h>
@@ -62,8 +48,8 @@ w32_dlerror (void)
 
 #define SO_HANDLE_TYPE void*
 #define LL_SO_OPEN(file,flags) dlopen ((file), (flags))
-#define LL_SO_CLOSE(handle) dlclose ((handle))
-#define LL_SO_SYMBOL(handle, name) dlsym ((handle), (name))
+#define LL_SO_CLOSE(module) dlclose ((module)->handle)
+#define LL_SO_SYMBOL(module, name) dlsym ((module)->handle, (name))
 #define LL_SO_TRFLAGS(flags) convert_flags ((flags))
 #define LL_SO_ERROR() g_strdup (dlerror ())
 
@@ -80,11 +66,11 @@ convert_flags (int flags)
 }
 
 #else
-/* no duynamic loader supported */
+/* no dynamic loader supported */
 #define SO_HANDLE_TYPE void*
 #define LL_SO_OPEN(file,flags) NULL
-#define LL_SO_CLOSE(handle) 
-#define LL_SO_SYMBOL(handle, name) NULL
+#define LL_SO_CLOSE(module) 
+#define LL_SO_SYMBOL(module, name) NULL
 #define LL_SO_TRFLAGS(flags) (flags)
 #define LL_SO_ERROR() g_strdup ("No support for dynamic loader")
 
@@ -95,6 +81,101 @@ struct _MonoDl {
        int main_module;
 };
 
+#ifdef PLATFORM_WIN32
+
+static char*
+w32_dlerror (void)
+{
+       char* ret = NULL;
+       wchar_t* buf = NULL;
+       DWORD code = GetLastError ();
+
+       if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL,
+               code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &buf, 0, NULL))
+       {
+               ret = g_utf16_to_utf8 (buf, wcslen(buf), NULL, NULL, NULL);
+               LocalFree (buf);
+       } else {
+               g_assert_not_reached ();
+       }
+       return ret;
+}
+
+static gpointer
+w32_find_symbol (MonoDl *module, const gchar *symbol_name)
+{
+       HMODULE *modules;
+       DWORD buffer_size = sizeof (HMODULE) * 1024;
+       DWORD needed, i;
+       gpointer proc = NULL;
+
+       /* get the symbol directly from the specified module */
+       if (!module->main_module)
+               return GetProcAddress (module->handle, symbol_name);
+
+       /* get the symbol from the main module */
+       proc = GetProcAddress (module->handle, symbol_name);
+       if (proc != NULL)
+               return proc;
+
+       /* get the symbol from the loaded DLLs */
+       modules = (HMODULE *) g_malloc (buffer_size);
+       if (modules == NULL)
+               return NULL;
+
+       if (!EnumProcessModules (GetCurrentProcess (), modules,
+                                buffer_size, &needed)) {
+               g_free (modules);
+               return NULL;
+       }
+
+       /* check whether the supplied buffer was too small, realloc, retry */
+       if (needed > buffer_size) {
+               g_free (modules);
+
+               buffer_size = needed;
+               modules = (HMODULE *) g_malloc (buffer_size);
+
+               if (modules == NULL)
+                       return NULL;
+
+               if (!EnumProcessModules (GetCurrentProcess (), modules,
+                                        buffer_size, &needed)) {
+                       g_free (modules);
+                       return NULL;
+               }
+       }
+
+       for (i = 0; i < needed / sizeof (HANDLE); i++) {
+               proc = GetProcAddress (modules [i], symbol_name);
+               if (proc != NULL) {
+                       g_free (modules);
+                       return proc;
+               }
+       }
+
+       g_free (modules);
+       return NULL;
+}
+
+
+static gpointer
+w32_load_module (const char* file, int flags)
+{
+       gpointer hModule = NULL;
+       if (file)
+       {
+               gunichar2* file_utf16 = g_utf8_to_utf16 (file, strlen (file), NULL, NULL, NULL);
+               hModule = LoadLibrary (file_utf16);
+               g_free (file_utf16);
+       }
+       else
+       {
+               hModule = GetModuleHandle (NULL);
+       }
+       return hModule;
+}
+#endif
 
 /*
  * read a value string from line with any of the following formats:
@@ -262,11 +343,11 @@ mono_dl_symbol (MonoDl *module, const char *name, void **symbol)
                char *usname = malloc (strlen (name) + 2);
                *usname = '_';
                strcpy (usname + 1, name);
-               sym = LL_SO_SYMBOL (module->handle, usname);
+               sym = LL_SO_SYMBOL (module, usname);
                free (usname);
        }
 #else
-       sym = LL_SO_SYMBOL (module->handle, name);
+       sym = LL_SO_SYMBOL (module, name);
 #endif
        if (sym) {
                if (symbol)