3 * Copyright (c) 2007 Ramiro Polla
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "dlfcn-win32.h"
26 * MSDN says these functions are not thread-safe. We make no efforts to have
27 * any kind of thread safety.
30 /* I have no special reason to have set MAX_GLOBAL_OBJECTS to this value. Any
31 * comments are welcome.
33 #define MAX_OBJECTS 255
35 static HMODULE global_objects
[MAX_OBJECTS
];
37 /* This function adds an object to the list of global objects.
38 * The implementation is very simple and slow.
39 * TODO: should failing this function be enough to fail the call to dlopen( )?
41 static void global_object_add( HMODULE hModule
)
45 for( i
= 0 ; i
< MAX_OBJECTS
; i
++ )
47 if( !global_objects
[i
] )
49 global_objects
[i
] = hModule
;
55 static void global_object_rem( HMODULE hModule
)
59 for( i
= 0 ; i
< MAX_OBJECTS
; i
++ )
61 if( global_objects
[i
] == hModule
)
63 global_objects
[i
] = 0;
69 /* Argument to last function. Used in dlerror( ) */
70 static char last_name
[MAX_PATH
];
72 static int copy_string( char *dest
, int dest_size
, const char *src
)
78 for( i
= 0 ; i
< dest_size
-1 ; i
++ )
91 void *dlopen( const char *file
, int mode
)
96 /* Do not let Windows display the critical-error-handler message box */
97 uMode
= SetErrorMode( SEM_FAILCRITICALERRORS
);
101 /* Save NULL pointer for error message */
102 _snprintf_s( last_name
, MAX_PATH
, MAX_PATH
, "0x%p", file
);
104 /* POSIX says that if the value of file is 0, a handle on a global
105 * symbol object must be provided. That object must be able to access
106 * all symbols from the original program file, and any objects loaded
107 * with the RTLD_GLOBAL flag.
108 * The return value from GetModuleHandle( ) allows us to retrieve
109 * symbols only from the original program file. For objects loaded with
110 * the RTLD_GLOBAL flag, we create our own list later on.
112 hModule
= GetModuleHandle( NULL
);
116 char lpFileName
[MAX_PATH
];
119 /* MSDN says backslashes *must* be used instead of forward slashes. */
120 for( i
= 0 ; i
< sizeof(lpFileName
)-1 ; i
++ )
124 else if( file
[i
] == '/' )
125 lpFileName
[i
] = '\\';
127 lpFileName
[i
] = file
[i
];
129 lpFileName
[i
] = '\0';
131 /* Save file name for error message */
132 copy_string( last_name
, sizeof(last_name
), lpFileName
);
134 /* POSIX says the search path is implementation-defined.
135 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
136 * to UNIX's search paths (start with system folders instead of current
139 hModule
= LoadLibraryEx( (LPSTR
) lpFileName
, NULL
,
140 LOAD_WITH_ALTERED_SEARCH_PATH
);
141 /* If the object was loaded with RTLD_GLOBAL, add it to list of global
142 * objects, so that its symbols may be retrieved even if the handle for
143 * the original program file is passed. POSIX says that if the same
144 * file is specified in multiple invocations, and any of them are
145 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
146 * symbols will remain global.
149 if( hModule
&& (mode
& RTLD_GLOBAL
) )
150 global_object_add( hModule
);
153 /* Return to previous state of the error-mode bit flags. */
154 SetErrorMode( uMode
);
156 return (void *) hModule
;
159 int dlclose( void *handle
)
161 HMODULE hModule
= (HMODULE
) handle
;
164 /* Save handle for error message */
165 _snprintf_s( last_name
, MAX_PATH
, MAX_PATH
, "0x%p", handle
);
167 ret
= FreeLibrary( hModule
);
169 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global
173 global_object_rem( hModule
);
175 /* dlclose's return value in inverted in relation to FreeLibrary's. */
181 void *dlsym( void *handle
, const char *name
)
184 HMODULE myhandle
= (HMODULE
) handle
;
186 /* Save symbol name for error message */
187 copy_string( last_name
, sizeof(last_name
), name
);
189 symbol
= GetProcAddress( myhandle
, name
);
195 /* If the handle for the original program file is passed, also search
196 * in all globally loaded objects.
199 hModule
= GetModuleHandle( NULL
);
201 if( hModule
== handle
)
205 for( i
= 0 ; i
< MAX_OBJECTS
; i
++ )
207 if( global_objects
[i
] != 0 )
209 symbol
= GetProcAddress( global_objects
[i
], name
);
217 CloseHandle( hModule
);
220 return (void*) symbol
;
223 char *dlerror( void )
226 /* POSIX says this function doesn't have to be thread-safe, so we use one
228 * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
231 static char lpBuffer
[65535];
234 dwMessageId
= GetLastError( );
236 if( dwMessageId
== 0 )
239 /* Format error message to:
240 * "<argument to function that failed>": <Windows localized error message>
242 ret
= copy_string( lpBuffer
, sizeof(lpBuffer
), "\"" );
243 ret
+= copy_string( lpBuffer
+ret
, sizeof(lpBuffer
)-ret
, last_name
);
244 ret
+= copy_string( lpBuffer
+ret
, sizeof(lpBuffer
)-ret
, "\": " );
245 ret
+= FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwMessageId
,
246 MAKELANGID( LANG_NEUTRAL
, SUBLANG_DEFAULT
),
247 lpBuffer
+ret
, sizeof(lpBuffer
)-ret
, NULL
);
251 /* POSIX says the string must not have trailing <newline> */
252 if( lpBuffer
[ret
-2] == '\r' && lpBuffer
[ret
-1] == '\n' )
253 lpBuffer
[ret
-2] = '\0';
256 /* POSIX says that invoking dlerror( ) a second time, immediately following
257 * a prior invocation, shall result in NULL being returned.