1. /* GMODULE - GLIB wrapper code for dynamic module loading
  2.  * Copyright (C) 1998, 2000 Tim Janik
  3.  *
  4.  * Win32 GMODULE implementation
  5.  * Copyright (C) 1998 Tor Lillqvist
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  *
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. /*
  24.  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
  25.  * file for a list of people on the GLib Team.  See the ChangeLog
  26.  * files for a list of changes.  These files are distributed with
  27.  * GLib at ftp://ftp.gtk.org/pub/gtk/.
  28.  */
  29.  
  30. /*
  31.  * MT safe
  32.  */
  33. #include "config.h"
  34.  
  35. #include <stdio.h>
  36. #include <windows.h>
  37.  
  38. #include <tlhelp32.h>
  39.  
  40. #ifdef G_WITH_CYGWIN
  41. #include <sys/cygwin.h>
  42. #endif
  43.  
  44. static void
  45. set_error (const gchar *format,
  46.        ...)
  47. {
  48.   gchar *error;
  49.   gchar *detail;
  50.   gchar *message;
  51.   va_list args;
  52.  
  53.   error = g_win32_error_message (GetLastError ());
  54.  
  55.   va_start (args, format);
  56.   detail = g_strdup_vprintf (format, args);
  57.   va_end (args);
  58.  
  59.   message = g_strconcat (detail, error, NULL);
  60.  
  61.   g_module_set_error (message);
  62.   g_free (message);
  63.   g_free (detail);
  64.   g_free (error);
  65. }
  66.  
  67. /* --- functions --- */
  68. static gpointer
  69. _g_module_open (const gchar *file_name,
  70.         gboolean     bind_lazy,
  71.         gboolean     bind_local)
  72. {
  73.   HINSTANCE handle;
  74.   wchar_t *wfilename;
  75. #ifdef G_WITH_CYGWIN
  76.   gchar tmp[MAX_PATH];
  77.  
  78.   cygwin_conv_to_win32_path(file_name, tmp);
  79.   file_name = tmp;
  80. #endif
  81.   wfilename = g_utf8_to_utf16 (file_name, -1, NULL, NULL, NULL);
  82.  
  83.   handle = LoadLibraryW (wfilename);
  84.   g_free (wfilename);
  85.      
  86.   if (!handle)
  87.     set_error ("`%s': ", file_name);
  88.  
  89.   return handle;
  90. }
  91.  
  92. static gint dummy;
  93. static gpointer null_module_handle = &dummy;
  94.  
  95. static gpointer
  96. _g_module_self (void)
  97. {
  98.   return null_module_handle;
  99. }
  100.  
  101. static void
  102. _g_module_close (gpointer handle,
  103.          gboolean is_unref)
  104. {
  105.   if (handle != null_module_handle)
  106.     if (!FreeLibrary (handle))
  107.       set_error ("");
  108. }
  109.  
  110. static gpointer
  111. find_in_any_module_using_toolhelp (const gchar *symbol_name)
  112. {
  113.   HANDLE snapshot;
  114.   MODULEENTRY32 me32;
  115.  
  116.   gpointer p;
  117.  
  118.   if ((snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0)) == (HANDLE) -1)
  119.     return NULL;
  120.  
  121.   me32.dwSize = sizeof (me32);
  122.   p = NULL;
  123.   if (Module32First (snapshot, &me32))
  124.     {
  125.       do {
  126.     if ((p = GetProcAddress (me32.hModule, symbol_name)) != NULL)
  127.       break;
  128.       } while (Module32Next (snapshot, &me32));
  129.     }
  130.  
  131.   CloseHandle (snapshot);
  132.  
  133.   return p;
  134. }
  135.  
  136. static gpointer
  137. find_in_any_module (const gchar *symbol_name)
  138. {
  139.   gpointer result;
  140.  
  141.   if ((result = find_in_any_module_using_toolhelp (symbol_name)) == NULL)
  142.     return NULL;
  143.   else
  144.     return result;
  145. }
  146.  
  147. static gpointer
  148. _g_module_symbol (gpointer     handle,
  149.           const gchar *symbol_name)
  150. {
  151.   gpointer p;
  152.  
  153.   if (handle == null_module_handle)
  154.     {
  155.       if ((p = GetProcAddress (GetModuleHandle (NULL), symbol_name)) == NULL)
  156.     p = find_in_any_module (symbol_name);
  157.     }
  158.   else
  159.     p = GetProcAddress (handle, symbol_name);
  160.  
  161.   if (!p)
  162.     set_error ("");
  163.  
  164.   return p;
  165. }
  166.  
  167. static gchar*
  168. _g_module_build_path (const gchar *directory,
  169.               const gchar *module_name)
  170. {
  171.   gint k;
  172.  
  173.   k = strlen (module_name);
  174.    
  175.   if (directory && *directory)
  176.     if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
  177.       return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, NULL);
  178. #ifdef G_WITH_CYGWIN
  179.     else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
  180.       return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
  181.     else
  182.       return g_strconcat (directory, G_DIR_SEPARATOR_S, "cyg", module_name, ".dll", NULL);
  183. #else
  184.     else if (strncmp (module_name, "lib", 3) == 0)
  185.       return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
  186.     else
  187.       return g_strconcat (directory, G_DIR_SEPARATOR_S, "lib", module_name, ".dll", NULL);
  188. #endif
  189.   else if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
  190.     return g_strdup (module_name);
  191. #ifdef G_WITH_CYGWIN
  192.   else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
  193.     return g_strconcat (module_name, ".dll", NULL);
  194.   else
  195.     return g_strconcat ("cyg", module_name, ".dll", NULL);
  196. #else
  197.   else if (strncmp (module_name, "lib", 3) == 0)
  198.     return g_strconcat (module_name, ".dll", NULL);
  199.   else
  200.     return g_strconcat ("lib", module_name, ".dll", NULL);
  201. #endif
  202. }