added dlopen method for windows. To be tested.

git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4280 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2011-06-17 18:51:22 +00:00
parent 03f0d61764
commit e0f6899e01
3 changed files with 367 additions and 6 deletions

View File

@ -0,0 +1,317 @@
/*
* dlfcn-win32
* Copyright (c) 2007 Ramiro Polla
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef WINDOWS_SYS
#include <windows.h>
#include <stdio.h>
#include "dlfcn_win32.h"
/* Note:
* MSDN says these functions are not thread-safe. We make no efforts to have
* any kind of thread safety.
*/
typedef struct global_object {
HMODULE hModule;
struct global_object *previous;
struct global_object *next;
} global_object;
static global_object first_object;
/* These functions implement a double linked list for the global objects. */
static global_object *global_search( HMODULE hModule )
{
global_object *pobject;
if( hModule == NULL )
return NULL;
for( pobject = &first_object; pobject ; pobject = pobject->next )
if( pobject->hModule == hModule )
return pobject;
return NULL;
}
static void global_add( HMODULE hModule )
{
global_object *pobject;
global_object *nobject;
if( hModule == NULL )
return;
pobject = global_search( hModule );
/* Do not add object again if it's already on the list */
if( pobject )
return;
for( pobject = &first_object; pobject->next ; pobject = pobject->next );
nobject = malloc( sizeof(global_object) );
/* Should this be enough to fail global_add, and therefore also fail
* dlopen?
*/
if( !nobject )
return;
pobject->next = nobject;
nobject->next = NULL;
nobject->previous = pobject;
nobject->hModule = hModule;
}
static void global_rem( HMODULE hModule )
{
global_object *pobject;
if( hModule == NULL )
return;
pobject = global_search( hModule );
if( !pobject )
return;
if( pobject->next )
pobject->next->previous = pobject->previous;
if( pobject->previous )
pobject->previous->next = pobject->next;
free( pobject );
}
/* POSIX says dlerror( ) doesn't have to be thread-safe, so we use one
* static buffer.
* MSDN says the buffer cannot be larger than 64K bytes, so we set it to
* the limit.
*/
static char error_buffer[65535];
static char *current_error;
static int copy_string( char *dest, int dest_size, const char *src )
{
int i = 0;
/* gcc should optimize this out */
if( !src && !dest )
return 0;
for( i = 0 ; i < dest_size-1 ; i++ )
{
if( !src[i] )
break;
else
dest[i] = src[i];
}
dest[i] = '\0';
return i;
}
static void save_err_str( const char *str )
{
DWORD dwMessageId;
DWORD pos;
dwMessageId = GetLastError( );
if( dwMessageId == 0 )
return;
/* Format error message to:
* "<argument to function that failed>": <Windows localized error message>
*/
pos = copy_string( error_buffer, sizeof(error_buffer), "\"" );
pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, str );
pos += copy_string( error_buffer+pos, sizeof(error_buffer)-pos, "\": " );
pos += FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwMessageId,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
error_buffer+pos, sizeof(error_buffer)-pos, NULL );
if( pos > 1 )
{
/* POSIX says the string must not have trailing <newline> */
if( error_buffer[pos-2] == '\r' && error_buffer[pos-1] == '\n' )
error_buffer[pos-2] = '\0';
}
current_error = error_buffer;
}
static void save_err_ptr_str( const void *ptr )
{
char ptr_buf[19]; /* 0x<pointer> up to 64 bits. */
sprintf( ptr_buf, "0x%p", ptr );
save_err_str( ptr_buf );
}
void *dlopen( const char *file, int mode )
{
HMODULE hModule;
UINT uMode;
current_error = NULL;
/* Do not let Windows display the critical-error-handler message box */
uMode = SetErrorMode( SEM_FAILCRITICALERRORS );
if( file == 0 )
{
/* POSIX says that if the value of file is 0, a handle on a global
* symbol object must be provided. That object must be able to access
* all symbols from the original program file, and any objects loaded
* with the RTLD_GLOBAL flag.
* The return value from GetModuleHandle( ) allows us to retrieve
* symbols only from the original program file. For objects loaded with
* the RTLD_GLOBAL flag, we create our own list later on.
*/
hModule = GetModuleHandle( NULL );
if( !hModule )
save_err_ptr_str( file );
}
else
{
char lpFileName[MAX_PATH];
int i;
/* MSDN says backslashes *must* be used instead of forward slashes. */
for( i = 0 ; i < sizeof(lpFileName)-1 ; i++ )
{
if( !file[i] )
break;
else if( file[i] == '/' )
lpFileName[i] = '\\';
else
lpFileName[i] = file[i];
}
lpFileName[i] = '\0';
/* POSIX says the search path is implementation-defined.
* LOAD_WITH_ALTERED_SEARCH_PATH is used to make it behave more closely
* to UNIX's search paths (start with system folders instead of current
* folder).
*/
hModule = LoadLibraryEx( (LPSTR) lpFileName, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH );
/* If the object was loaded with RTLD_GLOBAL, add it to list of global
* objects, so that its symbols may be retrieved even if the handle for
* the original program file is passed. POSIX says that if the same
* file is specified in multiple invocations, and any of them are
* RTLD_GLOBAL, even if any further invocations use RTLD_LOCAL, the
* symbols will remain global.
*/
if( !hModule )
save_err_str( lpFileName );
else if( (mode & RTLD_GLOBAL) )
global_add( hModule );
}
/* Return to previous state of the error-mode bit flags. */
SetErrorMode( uMode );
return (void *) hModule;
}
int dlclose( void *handle )
{
HMODULE hModule = (HMODULE) handle;
BOOL ret;
current_error = NULL;
ret = FreeLibrary( hModule );
/* If the object was loaded with RTLD_GLOBAL, remove it from list of global
* objects.
*/
if( ret )
global_rem( hModule );
else
save_err_ptr_str( handle );
/* dlclose's return value in inverted in relation to FreeLibrary's. */
ret = !ret;
return (int) ret;
}
void *dlsym( void *handle, const char *name )
{
FARPROC symbol;
current_error = NULL;
symbol = GetProcAddress( handle, name );
if( symbol == NULL )
{
HMODULE hModule;
/* If the handle for the original program file is passed, also search
* in all globally loaded objects.
*/
hModule = GetModuleHandle( NULL );
if( hModule == handle )
{
global_object *pobject;
for( pobject = &first_object; pobject ; pobject = pobject->next )
{
if( pobject->hModule )
{
symbol = GetProcAddress( pobject->hModule, name );
if( symbol != NULL )
break;
}
}
}
CloseHandle( hModule );
}
if( symbol == NULL )
save_err_str( name );
return (void*) symbol;
}
char *dlerror( void )
{
char *error_pointer = current_error;
/* POSIX says that invoking dlerror( ) a second time, immediately following
* a prior invocation, shall result in NULL being returned.
*/
current_error = NULL;
return error_pointer;
}
#endif

View File

@ -0,0 +1,47 @@
/*
* dlfcn-win32
* Copyright (c) 2007 Ramiro Polla
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifdef WINDOWS_SYS
#ifndef DLFCN_H
#define DLFCN_H
/* POSIX says these are implementation-defined.
* To simplify use with Windows API, we treat them the same way.
*/
#define RTLD_LAZY 0
#define RTLD_NOW 0
#define RTLD_GLOBAL (1 << 1)
#define RTLD_LOCAL (1 << 2)
/* These two were added in The Open Group Base Specifications Issue 6.
* Note: All other RTLD_* flags in any dlfcn.h are not standard compliant.
*/
#define RTLD_DEFAULT 0
#define RTLD_NEXT 0
void *dlopen ( const char *file, int mode );
int dlclose( void *handle );
void *dlsym ( void *handle, const char *name );
char *dlerror( void );
#endif /* DLFCN_H */
#endif /* WINDOWS_SYS */

View File

@ -11,8 +11,9 @@
#include <plugins/pluginclasses.h>
// lets disable the plugin system for now, as it's unfinished.
#define WINDOWS_SYS
#ifndef WINDOWS_SYS
#ifdef WINDOWS_SYS
#include "dlfcn_win32.h"
#else
#include <dlfcn.h>
#endif
@ -79,7 +80,6 @@ void RsPluginManager::loadPlugins(const std::vector<std::string>& plugin_directo
bool RsPluginManager::loadPlugin(const std::string& plugin_name)
{
#ifndef WINDOWS_SYS
std::cerr << " Loading plugin " << plugin_name << std::endl;
// The following choice is somewhat dangerous since the program can stop when a symbol can
@ -122,9 +122,6 @@ bool RsPluginManager::loadPlugin(const std::string& plugin_name)
std::cerr << " Symbols have been linked in LAZY mode. This means that undefined symbols may" << std::endl ;
std::cerr << " crash your program any time." << std::endl ;
}
#else
std::cerr << " Plugin load is yet unimplemented under windows." << std::endl;
#endif
return true ;
}