• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.1 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, see <http://www.gnu.org/licenses/>.
19  */
20 
21 /*
22  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GLib Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GLib at ftp://ftp.gtk.org/pub/gtk/.
26  */
27 
28 /*
29  * MT safe
30  */
31 #include "config.h"
32 
33 #include <stdio.h>
34 #include <windows.h>
35 
36 #include <tlhelp32.h>
37 
38 #ifdef G_WITH_CYGWIN
39 #include <sys/cygwin.h>
40 #endif
41 
42 static void G_GNUC_PRINTF (1, 2)
set_error(const gchar * format,...)43 set_error (const gchar *format,
44 	   ...)
45 {
46   gchar *error;
47   gchar *detail;
48   gchar *message;
49   va_list args;
50 
51   error = g_win32_error_message (GetLastError ());
52 
53   va_start (args, format);
54   detail = g_strdup_vprintf (format, args);
55   va_end (args);
56 
57   message = g_strconcat (detail, error, NULL);
58 
59   g_module_set_error (message);
60   g_free (message);
61   g_free (detail);
62   g_free (error);
63 }
64 
65 /* --- functions --- */
66 static gpointer
_g_module_open(const gchar * file_name,gboolean bind_lazy,gboolean bind_local)67 _g_module_open (const gchar *file_name,
68 		gboolean     bind_lazy,
69 		gboolean     bind_local)
70 {
71   HINSTANCE handle;
72   wchar_t *wfilename;
73   DWORD old_mode;
74   BOOL success;
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   /* suppress error dialog */
84   success = SetThreadErrorMode (SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS, &old_mode);
85   if (!success)
86     set_error ("");
87 
88   /* When building for UWP, load app asset DLLs instead of filesystem DLLs.
89    * Needs MSVC, Windows 8 and newer, and is only usable from apps. */
90 #if _WIN32_WINNT >= 0x0602 && defined(G_WINAPI_ONLY_APP)
91   handle = LoadPackagedLibrary (wfilename, 0);
92 #else
93   handle = LoadLibraryW (wfilename);
94 #endif
95 
96   if (success)
97     SetThreadErrorMode (old_mode, NULL);
98   g_free (wfilename);
99 
100   if (!handle)
101     set_error ("'%s': ", file_name);
102 
103   return handle;
104 }
105 
106 static gint dummy;
107 static gpointer null_module_handle = &dummy;
108 
109 static gpointer
_g_module_self(void)110 _g_module_self (void)
111 {
112   return null_module_handle;
113 }
114 
115 static void
_g_module_close(gpointer handle)116 _g_module_close (gpointer handle)
117 {
118   if (handle != null_module_handle)
119     if (!FreeLibrary (handle))
120       set_error ("");
121 }
122 
123 static gpointer
find_in_any_module_using_toolhelp(const gchar * symbol_name)124 find_in_any_module_using_toolhelp (const gchar *symbol_name)
125 {
126   HANDLE snapshot;
127   MODULEENTRY32 me32;
128 
129   gpointer p = NULL;
130 
131   /* Under UWP, Module32Next and Module32First are not available since we're
132    * not allowed to search in the address space of arbitrary loaded DLLs */
133 #if !defined(G_WINAPI_ONLY_APP)
134   /* https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot#remarks
135    * If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds. */
136   while (TRUE)
137     {
138       snapshot = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE, 0);
139       if (snapshot == INVALID_HANDLE_VALUE && GetLastError () == ERROR_BAD_LENGTH)
140         {
141           g_thread_yield ();
142           continue;
143         }
144       break;
145     }
146 
147   if (snapshot == INVALID_HANDLE_VALUE)
148     return NULL;
149 
150   me32.dwSize = sizeof (me32);
151   p = NULL;
152   if (Module32First (snapshot, &me32))
153     {
154       do {
155 	if ((p = GetProcAddress (me32.hModule, symbol_name)) != NULL)
156 	  break;
157       } while (Module32Next (snapshot, &me32));
158     }
159 
160   CloseHandle (snapshot);
161 #endif
162 
163   return p;
164 }
165 
166 static gpointer
find_in_any_module(const gchar * symbol_name)167 find_in_any_module (const gchar *symbol_name)
168 {
169   gpointer result;
170 
171   if ((result = find_in_any_module_using_toolhelp (symbol_name)) == NULL)
172     return NULL;
173   else
174     return result;
175 }
176 
177 static gpointer
_g_module_symbol(gpointer handle,const gchar * symbol_name)178 _g_module_symbol (gpointer     handle,
179 		  const gchar *symbol_name)
180 {
181   gpointer p;
182 
183   if (handle == null_module_handle)
184     {
185       if ((p = GetProcAddress (GetModuleHandle (NULL), symbol_name)) == NULL)
186 	p = find_in_any_module (symbol_name);
187     }
188   else
189     p = GetProcAddress (handle, symbol_name);
190 
191   if (!p)
192     set_error ("");
193 
194   return p;
195 }
196 
197 static gchar*
_g_module_build_path(const gchar * directory,const gchar * module_name)198 _g_module_build_path (const gchar *directory,
199 		      const gchar *module_name)
200 {
201   gint k;
202 
203   k = strlen (module_name);
204 
205   if (directory && *directory)
206     if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
207       return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, NULL);
208 #ifdef G_WITH_CYGWIN
209     else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
210       return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
211     else
212       return g_strconcat (directory, G_DIR_SEPARATOR_S, "cyg", module_name, ".dll", NULL);
213 #else
214     else if (strncmp (module_name, "lib", 3) == 0)
215       return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL);
216     else
217       return g_strconcat (directory, G_DIR_SEPARATOR_S, "lib", module_name, ".dll", NULL);
218 #endif
219   else if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0)
220     return g_strdup (module_name);
221 #ifdef G_WITH_CYGWIN
222   else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0)
223     return g_strconcat (module_name, ".dll", NULL);
224   else
225     return g_strconcat ("cyg", module_name, ".dll", NULL);
226 #else
227   else if (strncmp (module_name, "lib", 3) == 0)
228     return g_strconcat (module_name, ".dll", NULL);
229   else
230     return g_strconcat ("lib", module_name, ".dll", NULL);
231 #endif
232 }
233