d1dca5303eb7d174fa98c154a35901844105dd5b
[mono.git] / eglib / src / gmodule-win32.c
1 /*
2  * gmodule.c: dl* functions, glib style
3  *
4  * Author:
5  *   Gonzalo Paniagua Javier (gonzalo@novell.com)
6  *   Jonathan Chambers (joncham@gmail.com)
7  *   Robert Jordan (robertj@gmx.net)
8  *
9  * (C) 2006 Novell, Inc.
10  * (C) 2006 Jonathan Chambers
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining
13  * a copy of this software and associated documentation files (the
14  * "Software"), to deal in the Software without restriction, including
15  * without limitation the rights to use, copy, modify, merge, publish,
16  * distribute, sublicense, and/or sell copies of the Software, and to
17  * permit persons to whom the Software is furnished to do so, subject to
18  * the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be
21  * included in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  */
31 #include <config.h>
32 #include <glib.h>
33 #include <gmodule.h>
34 #include <windows.h>
35 #include <psapi.h>
36
37 #define LIBSUFFIX ".dll"
38 #define LIBPREFIX ""
39
40 struct _GModule {
41         HMODULE handle;
42         int main_module;
43 };
44
45 GModule *
46 g_module_open (const gchar *file, GModuleFlags flags)
47 {
48         GModule *module;
49         module = g_malloc (sizeof (GModule));
50         if (module == NULL)
51                 return NULL;
52
53         if (file != NULL) {
54                 gunichar2 *file16;
55                 file16 = u8to16(file); 
56                 module->main_module = FALSE;
57                 module->handle = LoadLibraryW (file16);
58                 g_free(file16);
59                 if (!module->handle) {
60                         g_free (module);
61                         return NULL;
62                 }
63                         
64         } else {
65                 module->main_module = TRUE;
66                 module->handle = GetModuleHandle (NULL);
67         }
68
69         return module;
70 }
71
72 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
73 static gpointer
74 w32_find_symbol (const gchar *symbol_name)
75 {
76         HMODULE *modules;
77         DWORD buffer_size = sizeof (HMODULE) * 1024;
78         DWORD needed, i;
79
80         modules = (HMODULE *) g_malloc (buffer_size);
81
82         if (modules == NULL)
83                 return NULL;
84
85         if (!EnumProcessModules (GetCurrentProcess (), modules,
86                                  buffer_size, &needed)) {
87                 g_free (modules);
88                 return NULL;
89         }
90
91         /* check whether the supplied buffer was too small, realloc, retry */
92         if (needed > buffer_size) {
93                 g_free (modules);
94
95                 buffer_size = needed;
96                 modules = (HMODULE *) g_malloc (buffer_size);
97
98                 if (modules == NULL)
99                         return NULL;
100
101                 if (!EnumProcessModules (GetCurrentProcess (), modules,
102                                          buffer_size, &needed)) {
103                         g_free (modules);
104                         return NULL;
105                 }
106         }
107
108         for (i = 0; i < needed / sizeof (HANDLE); i++) {
109                 gpointer proc = (gpointer)(intptr_t)GetProcAddress (modules [i], symbol_name);
110                 if (proc != NULL) {
111                         g_free (modules);
112                         return proc;
113                 }
114         }
115
116         g_free (modules);
117         return NULL;
118 }
119
120 #else /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
121
122 static gpointer
123 w32_find_symbol (const gchar *symbol_name)
124 {
125         g_unsupported_api ("EnumProcessModules");
126         SetLastError (ERROR_NOT_SUPPORTED);
127         return NULL;
128 }
129 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
130
131 gboolean
132 g_module_symbol (GModule *module, const gchar *symbol_name, gpointer *symbol)
133 {
134         if (module == NULL || symbol_name == NULL || symbol == NULL)
135                 return FALSE;
136
137         if (module->main_module) {
138                 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
139                 if (*symbol != NULL)
140                         return TRUE;
141
142                 *symbol = w32_find_symbol (symbol_name);
143                 return *symbol != NULL;
144         } else {
145                 *symbol = (gpointer)(intptr_t)GetProcAddress (module->handle, symbol_name);
146                 return *symbol != NULL;
147         }
148 }
149
150 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
151 const gchar *
152 g_module_error (void)
153 {
154         gchar* ret = NULL;
155         TCHAR* buf = NULL;
156         DWORD code = GetLastError ();
157
158         /* FIXME: buf must not be NULL! */
159         FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, 
160                 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 0, NULL);
161
162         ret = u16to8 (buf);
163         LocalFree(buf);
164
165         return ret;
166 }
167
168 #elif G_HAVE_API_SUPPORT(HAVE_UWP_WINAPI_SUPPORT)   /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
169
170 const gchar *
171 g_module_error (void)
172 {
173         gchar* ret = NULL;
174         TCHAR buf[1024];
175         DWORD code = GetLastError ();
176
177         if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
178                 code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, G_N_ELEMENTS(buf) - 1, NULL) )
179                 buf[0] = TEXT('\0');
180
181         ret = u16to8 (buf);
182         return ret;
183 }
184
185 #else
186
187 const gchar *
188 g_module_error (void)
189 {
190         g_unsupported_api ("FormatMessage");
191         SetLastError (ERROR_NOT_SUPPORTED);
192         return NULL;
193 }
194
195 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
196
197 gboolean
198 g_module_close (GModule *module)
199 {
200         HMODULE handle;
201         int main_module;
202
203         if (module == NULL || module->handle == NULL)
204                 return FALSE;
205
206         handle = module->handle;
207         main_module = module->main_module;
208         module->handle = NULL;
209         g_free (module);
210         return (main_module ? 1 : (0 == FreeLibrary (handle)));
211 }
212
213 gchar *
214 g_module_build_path (const gchar *directory, const gchar *module_name)
215 {
216         char *lib_prefix = "";
217         
218         if (module_name == NULL)
219                 return NULL;
220
221         if (strncmp (module_name, "lib", 3) != 0)
222                 lib_prefix = LIBPREFIX;
223         
224         if (directory && *directory){ 
225                 
226                 return g_strdup_printf ("%s/%s%s" LIBSUFFIX, directory, lib_prefix, module_name);
227         }
228         return g_strdup_printf ("%s%s" LIBSUFFIX, lib_prefix, module_name); 
229 }