(root)/
glib-2.79.0/
gmodule/
gmodule-win32.c
       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   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   *
       9   * This library is free software; you can redistribute it and/or
      10   * modify it under the terms of the GNU Lesser General Public
      11   * License as published by the Free Software Foundation; either
      12   * version 2.1 of the License, or (at your option) any later version.
      13   *
      14   * This library is distributed in the hope that it will be useful,
      15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
      17   * Lesser General Public License for more details.
      18   *
      19   * You should have received a copy of the GNU Lesser General Public
      20   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      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 <glib.h>
      36  #include <stdio.h>
      37  #include <windows.h>
      38  
      39  #include <tlhelp32.h>
      40  
      41  #ifdef G_WITH_CYGWIN
      42  #include <sys/cygwin.h>
      43  #endif
      44  
      45  static void G_GNUC_PRINTF (2, 3)
      46  set_error (GError      **error,
      47             const gchar  *format,
      48             ...)
      49  {
      50    gchar *win32_error;
      51    gchar *detail;
      52    gchar *message;
      53    va_list args;
      54  
      55    win32_error = g_win32_error_message (GetLastError ());
      56  
      57    va_start (args, format);
      58    detail = g_strdup_vprintf (format, args);
      59    va_end (args);
      60  
      61    message = g_strconcat (detail, win32_error, NULL);
      62  
      63    g_module_set_error (message);
      64    g_set_error_literal (error, G_MODULE_ERROR, G_MODULE_ERROR_FAILED, message);
      65  
      66    g_free (message);
      67    g_free (detail);
      68    g_free (win32_error);
      69  }
      70  
      71  /* --- functions --- */
      72  static gpointer
      73  _g_module_open (const gchar *file_name,
      74  		gboolean     bind_lazy,
      75  		gboolean     bind_local,
      76                  GError     **error)
      77  {
      78    HINSTANCE handle;
      79    wchar_t *wfilename;
      80    DWORD old_mode;
      81    BOOL success;
      82  #ifdef G_WITH_CYGWIN
      83    gchar tmp[MAX_PATH];
      84  
      85    cygwin_conv_to_win32_path(file_name, tmp);
      86    file_name = tmp;
      87  #endif
      88    wfilename = g_utf8_to_utf16 (file_name, -1, NULL, NULL, NULL);
      89  
      90    /* suppress error dialog */
      91    success = SetThreadErrorMode (SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS, &old_mode);
      92    if (!success)
      93      set_error (error, "");
      94  
      95    /* When building for UWP, load app asset DLLs instead of filesystem DLLs.
      96     * Needs MSVC, Windows 8 and newer, and is only usable from apps. */
      97  #if _WIN32_WINNT >= 0x0602 && defined(G_WINAPI_ONLY_APP)
      98    handle = LoadPackagedLibrary (wfilename, 0);
      99  #else
     100    handle = LoadLibraryW (wfilename);
     101  #endif
     102  
     103    if (success)
     104      SetThreadErrorMode (old_mode, NULL);
     105    g_free (wfilename);
     106        
     107    if (!handle)
     108      set_error (error, "'%s': ", file_name);
     109  
     110    return handle;
     111  }
     112  
     113  static gint dummy;
     114  static gpointer null_module_handle = &dummy;
     115    
     116  static gpointer
     117  _g_module_self (void)
     118  {
     119    return null_module_handle;
     120  }
     121  
     122  static void
     123  _g_module_close (gpointer handle)
     124  {
     125    if (handle != null_module_handle)
     126      if (!FreeLibrary (handle))
     127        set_error (NULL, "");
     128  }
     129  
     130  static gpointer
     131  find_in_any_module_using_toolhelp (const gchar *symbol_name)
     132  {
     133    HANDLE snapshot; 
     134    MODULEENTRY32 me32;
     135  
     136    gpointer p = NULL;
     137  
     138    /* Under UWP, Module32Next and Module32First are not available since we're
     139     * not allowed to search in the address space of arbitrary loaded DLLs */
     140  #if !defined(G_WINAPI_ONLY_APP)
     141    /* https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot#remarks
     142     * If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds. */
     143    while (TRUE)
     144      {
     145        snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
     146        if (snapshot == INVALID_HANDLE_VALUE && GetLastError () == ERROR_BAD_LENGTH)
     147          {
     148            g_thread_yield ();
     149            continue;
     150          }
     151        break;
     152      }
     153  
     154    if (snapshot == INVALID_HANDLE_VALUE)
     155      return NULL;
     156  
     157    me32.dwSize = sizeof (me32);
     158    p = NULL;
     159    if (Module32First (snapshot, &me32))
     160      {
     161        do {
     162  	if ((p = GetProcAddress (me32.hModule, symbol_name)) != NULL)
     163  	  break;
     164        } while (Module32Next (snapshot, &me32));
     165      }
     166  
     167    CloseHandle (snapshot);
     168  #endif
     169  
     170    return p;
     171  }
     172  
     173  static gpointer
     174  find_in_any_module (const gchar *symbol_name)
     175  {
     176    gpointer result;
     177  
     178    if ((result = find_in_any_module_using_toolhelp (symbol_name)) == NULL)
     179      return NULL;
     180    else
     181      return result;
     182  }
     183  
     184  static gpointer
     185  _g_module_symbol (gpointer     handle,
     186  		  const gchar *symbol_name)
     187  {
     188    gpointer p;
     189    
     190    if (handle == null_module_handle)
     191      {
     192        if ((p = GetProcAddress (GetModuleHandle (NULL), symbol_name)) == NULL)
     193  	p = find_in_any_module (symbol_name);
     194      }
     195    else
     196      p = GetProcAddress (handle, symbol_name);
     197  
     198    if (!p)
     199      set_error (NULL, "");
     200  
     201    return p;
     202  }
     203  
     204  static gchar*
     205  _g_module_build_path (const gchar *directory,
     206  		      const gchar *module_name)
     207  {
     208    gint k;
     209  
     210    k = strlen (module_name);
     211      
     212    if (directory && *directory)
     213      if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
     214        return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, NULL);
     215  #ifdef G_WITH_CYGWIN
     216      else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
     217        return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
     218      else
     219        return g_strconcat (directory, G_DIR_SEPARATOR_S, "cyg", module_name, ".dll", NULL);
     220  #else
     221      else if (strncmp (module_name, "lib", 3) == 0)
     222        return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
     223      else
     224        return g_strconcat (directory, G_DIR_SEPARATOR_S, "lib", module_name, ".dll", NULL);
     225  #endif
     226    else if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
     227      return g_strdup (module_name);
     228  #ifdef G_WITH_CYGWIN
     229    else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
     230      return g_strconcat (module_name, ".dll", NULL);
     231    else
     232      return g_strconcat ("cyg", module_name, ".dll", NULL);
     233  #else
     234    else if (strncmp (module_name, "lib", 3) == 0)
     235      return g_strconcat (module_name, ".dll", NULL);
     236    else
     237      return g_strconcat ("lib", module_name, ".dll", NULL);
     238  #endif
     239  }