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
24 #include "dlfcn-win32.h"
27 * MSDN says these functions are not thread-safe. We make no efforts to have
28 * any kind of thread safety.
31 /* I have no special reason to have set MAX_GLOBAL_OBJECTS to this value. Any
32 * comments are welcome.
34 #define MAX_OBJECTS 255
36 static HMODULE global_objects
[MAX_OBJECTS
];
38 /* This function adds an object to the list of global objects.
39 * The implementation is very simple and slow.
40 * TODO: should failing this function be enough to fail the call to dlopen( )?
42 static void global_object_add( HMODULE hModule
)
46 for( i
= 0 ; i
< MAX_OBJECTS
; i
++ )
48 if( !global_objects
[i
] )
50 global_objects
[i
] = hModule
;
56 static void global_object_rem( HMODULE hModule
)
60 for( i
= 0 ; i
< MAX_OBJECTS
; i
++ )
62 if( global_objects
[i
] == hModule
)
64 global_objects
[i
] = 0;
70 /* Argument to last function. Used in dlerror( ) */
71 static char last_name
[MAX_PATH
];
73 static int copy_string( char *dest
, int dest_size
, const char *src
)
79 for( i
= 0 ; i
< dest_size
-1 ; i
++ )
92 void *dlopen( const char *file
, int mode
)
97 /* Do not let Windows display the critical-error-handler message box */
98 uMode
= SetErrorMode( SEM_FAILCRITICALERRORS
);
102 /* Save NULL pointer for error message */
103 _snprintf_s( last_name
, MAX_PATH
, MAX_PATH
, "0x%p", file
);
105 /* POSIX says that if the value of file is 0, a handle on a global
106 * symbol object must be provided. That object must be able to access
107 * all symbols from the original program file, and any objects loaded
108 * with the RTLD_GLOBAL flag.
109 * The return value from GetModuleHandle( ) allows us to retrieve
110 * symbols only from the original program file. For objects loaded with
111 * the RTLD_GLOBAL flag, we create our own list later on.
113 hModule
= GetModuleHandle( NULL
);
117 char lpFileName
[MAX_PATH
];
120 /* MSDN says backslashes *must* be used instead of forward slashes. */
121 for( i
= 0 ; i
< sizeof(lpFileName
)-1 ; i
++ )
125 else if( file
[i
] == '/' )
126 lpFileName
[i
] = '\\';
128 lpFileName
[i
] = file
[i
];
130 lpFileName
[i
] = '\0';
132 /* Save file name for error message */
133 copy_string( last_name
, sizeof(last_name
), lpFileName
);
135 /* POSIX says the search path is implementation-defined.
136 * LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
137 * to UNIX's search paths (start with system folders instead of current
140 hModule
= LoadLibraryEx( (LPSTR
) lpFileName
, NULL
,
141 LOAD_WITH_ALTERED_SEARCH_PATH
);
142 /* If the object was loaded with RTLD_GLOBAL, add it to list of global
143 * objects, so that its symbols may be retrieved even if the handle for
144 * the original program file is passed. POSIX says that if the same
145 * file is specified in multiple invocations, and any of them are
146 * RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
147 * symbols will remain global.
150 if( hModule
&& (mode
& RTLD_GLOBAL
) )
151 global_object_add( hModule
);
154 /* Return to previous state of the error-mode bit flags. */
155 SetErrorMode( uMode
);
157 return (void *) hModule
;
160 int dlclose( void *handle
)
162 HMODULE hModule
= (HMODULE
) handle
;
165 /* Save handle for error message */
166 _snprintf_s( last_name
, MAX_PATH
, MAX_PATH
, "0x%p", handle
);
168 ret
= FreeLibrary( hModule
);
170 /* If the object was loaded with RTLD_GLOBAL, remove it from list of global
174 global_object_rem( hModule
);
176 /* dlclose's return value in inverted in relation to FreeLibrary's. */
182 void *dlsym( void *handle
, const char *name
)
185 HMODULE myhandle
= (HMODULE
) handle
;
187 /* Save symbol name for error message */
188 copy_string( last_name
, sizeof(last_name
), name
);
190 symbol
= GetProcAddress( myhandle
, name
);
196 /* If the handle for the original program file is passed, also search
197 * in all globally loaded objects.
200 hModule
= GetModuleHandle( NULL
);
202 if( hModule
== handle
)
206 for( i
= 0 ; i
< MAX_OBJECTS
; i
++ )
208 if( global_objects
[i
] != 0 )
210 symbol
= GetProcAddress( global_objects
[i
], name
);
218 CloseHandle( hModule
);
221 return (void*) symbol
;
224 char *dlerror( void )
227 /* POSIX says this function doesn't have to be thread-safe, so we use one
229 * MSDN says the buffer cannot be larger than 64K bytes, so we set it to
232 static char lpBuffer
[65535];
235 dwMessageId
= GetLastError( );
237 if( dwMessageId
== 0 )
240 /* Format error message to:
241 * "<argument to function that failed>": <Windows localized error message>
243 ret
= copy_string( lpBuffer
, sizeof(lpBuffer
), "\"" );
244 ret
+= copy_string( lpBuffer
+ret
, sizeof(lpBuffer
)-ret
, last_name
);
245 ret
+= copy_string( lpBuffer
+ret
, sizeof(lpBuffer
)-ret
, "\": " );
246 ret
+= FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, dwMessageId
,
247 MAKELANGID( LANG_NEUTRAL
, SUBLANG_DEFAULT
),
248 lpBuffer
+ret
, sizeof(lpBuffer
)-ret
, NULL
);
252 /* POSIX says the string must not have trailing <newline> */
253 if( lpBuffer
[ret
-2] == '\r' && lpBuffer
[ret
-1] == '\n' )
254 lpBuffer
[ret
-2] = '\0';
257 /* POSIX says that invoking dlerror( ) a second time, immediately following
258 * a prior invocation, shall result in NULL being returned.