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 typedef HANDLE (WINAPI *PFNCREATETOOLHELP32SNAPSHOT)(DWORD, DWORD); 114 static PFNCREATETOOLHELP32SNAPSHOT pfnCreateToolhelp32Snapshot = NULL; 115 116 typedef BOOL (WINAPI *PFNMODULE32FIRST)(HANDLE, MODULEENTRY32*); 117 static PFNMODULE32FIRST pfnModule32First= NULL; 118 119 typedef BOOL (WINAPI *PFNMODULE32NEXT)(HANDLE, MODULEENTRY32*); 120 static PFNMODULE32NEXT pfnModule32Next = NULL; 121 122 static HMODULE kernel32; 123 124 HANDLE snapshot; 125 MODULEENTRY32 me32; 126 127 gpointer p; 128 129 if (!pfnCreateToolhelp32Snapshot || !pfnModule32First || !pfnModule32Next) 130 { 131 if (!kernel32) 132 if (!(kernel32 = GetModuleHandle ("kernel32.dll"))) 133 return NULL; 134 135 if (!(pfnCreateToolhelp32Snapshot = (PFNCREATETOOLHELP32SNAPSHOT) GetProcAddress (kernel32, "CreateToolhelp32Snapshot")) 136 || !(pfnModule32First = (PFNMODULE32FIRST) GetProcAddress (kernel32, "Module32First")) 137 || !(pfnModule32Next = (PFNMODULE32NEXT) GetProcAddress (kernel32, "Module32Next"))) 138 return NULL; 139 } 140 141 if ((snapshot = (*pfnCreateToolhelp32Snapshot) (TH32CS_SNAPMODULE, 0)) == (HANDLE) -1) 142 return NULL; 143 144 me32.dwSize = sizeof (me32); 145 p = NULL; 146 if ((*pfnModule32First) (snapshot, &me32)) 147 { 148 do { 149 if ((p = GetProcAddress (me32.hModule, symbol_name)) != NULL) 150 break; 151 } while ((*pfnModule32Next) (snapshot, &me32)); 152 } 153 154 CloseHandle (snapshot); 155 156 return p; 157 } 158 159 static gpointer 160 find_in_any_module_using_psapi (const gchar *symbol_name) 161 { 162 static HMODULE psapi = NULL; 163 164 typedef BOOL (WINAPI *PFNENUMPROCESSMODULES) (HANDLE, HMODULE *, DWORD, LPDWORD) ; 165 static PFNENUMPROCESSMODULES pfnEnumProcessModules = NULL; 166 167 HMODULE *modules; 168 HMODULE dummy; 169 gint i, size; 170 DWORD needed; 171 172 gpointer p; 173 174 if (!pfnEnumProcessModules) 175 { 176 if (!psapi) 177 if ((psapi = LoadLibrary ("psapi.dll")) == NULL) 178 return NULL; 179 180 if (!(pfnEnumProcessModules = (PFNENUMPROCESSMODULES) GetProcAddress (psapi, "EnumProcessModules"))) 181 return NULL; 182 } 183 184 if (!(*pfnEnumProcessModules) (GetCurrentProcess (), &dummy, 185 sizeof (HMODULE), &needed)) 186 return NULL; 187 188 size = needed + 10 * sizeof (HMODULE); 189 modules = g_malloc (size); 190 191 if (!(*pfnEnumProcessModules) (GetCurrentProcess (), modules, 192 size, &needed) 193 || needed > size) 194 { 195 g_free (modules); 196 return NULL; 197 } 198 199 p = NULL; 200 for (i = 0; i < needed / sizeof (HMODULE); i++) 201 if ((p = GetProcAddress (modules[i], symbol_name)) != NULL) 202 break; 203 204 g_free (modules); 205 206 return p; 207 } 208 209 static gpointer 210 find_in_any_module (const gchar *symbol_name) 211 { 212 gpointer result; 213 214 if ((result = find_in_any_module_using_toolhelp (symbol_name)) == NULL 215 && (result = find_in_any_module_using_psapi (symbol_name)) == NULL) 216 return NULL; 217 else 218 return result; 219 } 220 221 static gpointer 222 _g_module_symbol (gpointer handle, 223 const gchar *symbol_name) 224 { 225 gpointer p; 226 227 if (handle == null_module_handle) 228 { 229 if ((p = GetProcAddress (GetModuleHandle (NULL), symbol_name)) == NULL) 230 p = find_in_any_module (symbol_name); 231 } 232 else 233 p = GetProcAddress (handle, symbol_name); 234 235 if (!p) 236 set_error (""); 237 238 return p; 239 } 240 241 static gchar* 242 _g_module_build_path (const gchar *directory, 243 const gchar *module_name) 244 { 245 gint k; 246 247 k = strlen (module_name); 248 249 if (directory && *directory) 250 if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0) 251 return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, NULL); 252 #ifdef G_WITH_CYGWIN 253 else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0) 254 return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL); 255 else 256 return g_strconcat (directory, G_DIR_SEPARATOR_S, "cyg", module_name, ".dll", NULL); 257 #else 258 else if (strncmp (module_name, "lib", 3) == 0) 259 return g_strconcat (directory, G_DIR_SEPARATOR_S, module_name, ".dll", NULL); 260 else 261 return g_strconcat (directory, G_DIR_SEPARATOR_S, "lib", module_name, ".dll", NULL); 262 #endif 263 else if (k > 4 && g_ascii_strcasecmp (module_name + k - 4, ".dll") == 0) 264 return g_strdup (module_name); 265 #ifdef G_WITH_CYGWIN 266 else if (strncmp (module_name, "lib", 3) == 0 || strncmp (module_name, "cyg", 3) == 0) 267 return g_strconcat (module_name, ".dll", NULL); 268 else 269 return g_strconcat ("cyg", module_name, ".dll", NULL); 270 #else 271 else if (strncmp (module_name, "lib", 3) == 0) 272 return g_strconcat (module_name, ".dll", NULL); 273 else 274 return g_strconcat ("lib", module_name, ".dll", NULL); 275 #endif 276 } 277