Added new dynamic loading classes. (which handle proper

wxRTTI and wxModule initialisation and unloading)
Removed serialisation code from wxObject and elsewhere.
Added USER_EXPORTED hash and list macros.
Added *_PLUGGABLE_CLASS defines for exporting dynamic wxObjects
from dlls.

 ----------------------------------------------------------------------
 Modified Files:
 	Makefile.in configure configure.in setup.h.in debian/changelog
 	distrib/msw/tmake/filelist.txt include/wx/defs.h
 	include/wx/docview.h include/wx/dynlib.h include/wx/fileconf.h
 	include/wx/hash.h include/wx/list.h include/wx/module.h
 	include/wx/object.h include/wx/resource.h include/wx/stream.h
 	include/wx/gtk/setup0.h include/wx/msw/setup0.h src/files.lst
 	src/wxBase.dsp src/wxUniv.dsp src/wxWindows.dsp
 	src/common/dynlib.cpp src/common/filename.cpp
 	src/common/module.cpp src/common/object.cpp
 	src/common/stream.cpp src/gtk/files.lst src/mac/files.lst
 	src/mgl/files.lst src/mgl/makefile.wat src/motif/files.lst
 	src/msw/dialup.cpp src/msw/files.lst src/msw/helpchm.cpp
 	src/msw/makefile.b32 src/msw/makefile.bcc src/msw/makefile.dos
 	src/msw/makefile.g95 src/msw/makefile.sc src/msw/makefile.vc
 	src/msw/makefile.wat src/os2/files.lst src/univ/files.lst
 Added Files:
 	include/wx/dynload.h src/common/dynload.cpp
 Removed Files:
 	include/wx/objstrm.h include/wx/serbase.h
 	src/common/objstrm.cpp src/common/serbase.cpp
 	utils/serialize/.cvsignore utils/serialize/makefile.b32
 	utils/serialize/sercore.cpp utils/serialize/sercore.h
 	utils/serialize/serctrl.cpp utils/serialize/serctrl.h
 	utils/serialize/serext.cpp utils/serialize/serext.h
 	utils/serialize/sergdi.cpp utils/serialize/sergdi.h
 	utils/serialize/sermain.cpp utils/serialize/serwnd.cpp
 	utils/serialize/serwnd.h
 ----------------------------------------------------------------------


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13088 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Ron Lee
2001-12-19 07:09:58 +00:00
parent 955b11918b
commit 0b9ab0bd82
66 changed files with 1838 additions and 3658 deletions

598
src/common/dynload.cpp Normal file
View File

@@ -0,0 +1,598 @@
/////////////////////////////////////////////////////////////////////////////
// Name: dynload.cpp
// Purpose: Dynamic loading framework
// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's
// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux)
// Modified by:
// Created: 03/12/01
// RCS-ID: $Id$
// Copyright: (c) 2001 Ron Lee <ron@debian.org>
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
#pragma implementation "dynload.h"
#endif
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_DYNAMIC_LOADER
#ifdef __WINDOWS__
#include "wx/msw/private.h"
#endif
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#endif
#include "wx/dynload.h"
// ----------------------------------------------------------------------------
// conditional compilation
// ----------------------------------------------------------------------------
#if defined(__WXPM__) || defined(__EMX__)
#define INCL_DOS
#include <os2.h>
#define wxDllOpen(error, lib, handle) DosLoadModule(error, sizeof(error), lib, &handle)
#define wxDllGetSymbol(handle, modaddr) DosQueryProcAddr(handle, 1L, NULL, (PFN*)modaddr)
#define wxDllClose(handle) DosFreeModule(handle)
#elif defined(HAVE_DLOPEN)
// note about dlopen() flags: we use RTLD_NOW to have more Windows-like
// behaviour (Win won't let you load a library with missing symbols) and
// RTLD_GLOBAL because it is needed sometimes and probably doesn't hurt
// otherwise. On True64-Unix RTLD_GLOBAL is not allowed and on VMS the
// second argument on dlopen is ignored.
#ifdef __VMS
#define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
#elif defined( __osf__ )
#define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY)
#else
#define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY | RTLD_GLOBAL)
#endif // __VMS
#define wxDllGetSymbol(handle, name) dlsym(handle, name)
#define wxDllClose dlclose
#elif defined(HAVE_SHL_LOAD)
#define wxDllOpen(lib) shl_load(lib.fn_str(), BIND_DEFERRED, 0)
#define wxDllClose shl_unload
static inline void *wxDllGetSymbol(shl_t handle, const wxString& name)
{
void *sym;
return ( shl_findsym(&handle, name.mb_str(), TYPE_UNDEFINED, &sym) == 0 )
? sym : 0;
}
#elif defined(__DARWIN__)
// Porting notes:
// The dlopen port is a port from dl_next.xs by Anno Siegel.
// dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
// The method used here is just to supply the sun style dlopen etc.
// functions in terms of Darwin NS*.
void *dlopen(const char *path, int mode); // mode is ignored
void *dlsym(void *handle, const char *symbol);
int dlclose(void *handle);
const char *dlerror(void);
#define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
#define wxDllGetSymbol(handle, name) dlsym(handle, name)
#define wxDllClose dlclose
#elif defined(__WINDOWS__)
// using LoadLibraryEx under Win32 to avoid name clash with LoadLibrary
#ifdef __WIN32__
#ifdef _UNICODE
#define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
#else
#define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
#endif
#else // Win16
#define wxDllOpen(lib) ::LoadLibrary(lib)
#endif // Win32/16
#define wxDllGetSymbol(handle, name) ::GetProcAddress(handle, name)
#define wxDllClose ::FreeLibrary
#elif defined(__WXMAC__)
#define wxDllClose(handle) CloseConnection(&handle)
#else
#error "Don't know how to load shared libraries on this platform."
#endif
// ============================================================================
// implementation
// ============================================================================
// ---------------------------------------------------------------------------
// wxDllLoader (all these methods are static)
// ---------------------------------------------------------------------------
#if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
const wxString wxDllLoader::ms_dllext( _T(".dll") );
#elif defined(__UNIX__)
#if defined(__HPUX__)
const wxString wxDllLoader::ms_dllext( _T(".sl") );
#else
const wxString wxDllLoader::ms_dllext( _T(".so") );
#endif
#endif
wxDllType wxDllLoader::GetProgramHandle()
{
#if defined( HAVE_DLOPEN ) && !defined(__EMX__)
// obtain handle for main program
return dlopen(NULL, RTLD_NOW/*RTLD_LAZY*/);
#elif defined (HAVE_SHL_LOAD)
// shl_findsymbol with NULL handle looks up in main program
return 0;
#else
wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
return 0;
#endif
}
wxDllType wxDllLoader::LoadLibrary(const wxString &name)
{
wxString libname( name + wxDllLoader::GetDllExt() );
wxDllType handle;
#if defined(__WXMAC__) && !defined(__UNIX__)
FSSpec myFSSpec;
Ptr myMainAddr;
Str255 myErrName;
wxMacFilename2FSSpec( libname , &myFSSpec );
if( GetDiskFragment( &myFSSpec,
0,
kCFragGoesToEOF,
"\p",
kPrivateCFragCopy,
&handle,
&myMainAddr,
myErrName ) != noErr )
{
p2cstr( myErrName );
wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
libname.c_str(),
(char*)myErrName );
handle = 0;
}
#elif defined(__WXPM__) || defined(__EMX__)
char zError[256] = "";
wxDllOpen(zError, libname, handle);
#else
handle = wxDllOpen(libname);
#endif
if ( !handle )
{
wxString msg(_("Failed to load shared library '%s'"));
#ifdef HAVE_DLERROR
wxChar *err = dlerror();
if( err )
wxLogError( msg, err );
#else
wxLogSysError( msg, libname.c_str() );
#endif
}
return handle;
}
void wxDllLoader::UnloadLibrary(wxDllType handle)
{
wxDllClose(handle);
}
void *wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name, bool *success)
{
bool failed = FALSE;
void *symbol = 0;
#if defined(__WXMAC__) && !defined(__UNIX__)
Ptr symAddress;
CFragSymbolClass symClass;
Str255 symName;
#if TARGET_CARBON
c2pstrcpy( (StringPtr) symName, name );
#else
strcpy( (char *) symName, name );
c2pstr( (char *) symName );
#endif
if( FindSymbol( dllHandle, symName, &symAddress, &symClass ) == noErr )
symbol = (void *)symAddress;
#elif defined(__WXPM__) || defined(__EMX__)
wxDllGetSymbol(dllHandle, symbol);
#else
// mb_str() is necessary in Unicode build
symbol = wxDllGetSymbol(dllHandle, name.mb_str());
#endif
if ( !symbol )
{
wxString msg(_("wxDllLoader failed to GetSymbol '%s'"));
#ifdef HAVE_DLERROR
wxChar *err = dlerror();
if( err )
{
failed = TRUE;
wxLogError( msg, err );
}
#else
failed = TRUE;
wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
name.c_str());
#endif
}
if( success )
*success = !failed;
return symbol;
}
// ---------------------------------------------------------------------------
// wxDLManifestEntry
// ---------------------------------------------------------------------------
wxDLImports wxDLManifestEntry::ms_classes(wxKEY_STRING);
wxDLManifestEntry::wxDLManifestEntry( const wxString &libname )
: m_before(wxClassInfo::sm_first)
, m_handle(wxDllLoader::LoadLibrary( libname ))
, m_after(wxClassInfo::sm_first)
, m_count(1)
{
if( m_handle != 0 )
{
UpdateClassInfo();
RegisterModules();
}
else
--m_count; // Flag us for deletion
}
wxDLManifestEntry::~wxDLManifestEntry()
{
UnregisterModules();
RestoreClassInfo();
wxDllLoader::UnloadLibrary(m_handle);
}
// ------------------------
// Private methods
// ------------------------
void wxDLManifestEntry::UpdateClassInfo()
{
wxClassInfo *info;
wxHashTable *t = wxClassInfo::sm_classTable;
// FIXME: Below is simply a cut and paste specialisation of
// wxClassInfo::InitializeClasses. Once this stabilises,
// the two should probably be merged.
//
// Actually it's becoming questionable whether we should merge
// this info with the main ClassInfo tables since we can nearly
// handle this completely internally now and it does expose
// certain (minimal % user_stupidy) risks.
for(info = m_after; info != m_before; info = info->m_next)
{
if( info->m_className )
{
if( t->Get(info->m_className) == 0 )
t->Put(info->m_className, (wxObject *)info);
// Hash all the class names into a local table too so
// we can quickly find the entry they correspond to.
if( ms_classes.Get(info->m_className) == 0 )
ms_classes.Put(info->m_className, (wxObject *) this);
}
}
for(info = m_after; info != m_before; info = info->m_next)
{
if( info->m_baseClassName1 )
info->m_baseInfo1 = (wxClassInfo *)t->Get(info->m_baseClassName1);
if( info->m_baseClassName2 )
info->m_baseInfo2 = (wxClassInfo *)t->Get(info->m_baseClassName2);
}
}
void wxDLManifestEntry::RestoreClassInfo()
{
wxClassInfo *info;
for(info = m_after; info != m_before; info = info->m_next)
{
wxClassInfo::sm_classTable->Delete(info->m_className);
ms_classes.Delete(info->m_className);
}
if( wxClassInfo::sm_first == m_after )
wxClassInfo::sm_first = m_before;
else
{
info = wxClassInfo::sm_first;
while( info->m_next && info->m_next != m_after ) info = info->m_next;
wxASSERT_MSG( info, _T("ClassInfo from wxDynamicLibrary not found on purge"))
info->m_next = m_before;
}
}
void wxDLManifestEntry::RegisterModules()
{
// Plugin libraries might have wxModules, Register and initialise them if
// they do.
//
// Note that these classes are NOT included in the reference counting since
// it's implicit that they will be unloaded if and when the last handle to
// the library is. We do have to keep a copy of the module's pointer
// though, as there is currently no way to Unregister it without it.
wxASSERT_MSG( m_count == 1,
_T("RegisterModules should only be called for the first load") );
for(wxClassInfo *info = m_after; info != m_before; info = info->m_next)
{
if( info->IsKindOf(CLASSINFO(wxModule)) )
{
wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") );
m_wxmodules.Append(m);
wxModule::RegisterModule(m);
}
}
// FIXME: Likewise this is (well was) very similar to InitializeModules()
for(wxModuleList::Node *node = m_wxmodules.GetFirst(); node; node->GetNext())
{
if( !node->GetData()->Init() )
{
wxLogDebug(_T("wxModule::Init() failed for wxDynamicLibrary"));
// XXX: Watch this, a different hash implementation might break it,
// a good hash implementation would let us fix it though.
// The name of the game is to remove any uninitialised modules and
// let the dtor Exit the rest on shutdown, (which we'll initiate
// shortly).
wxModuleList::Node *oldNode = 0;
do {
node = node->GetNext();
delete oldNode;
wxModule::UnregisterModule( node->GetData() );
oldNode = node;
} while( node );
--m_count; // Flag us for deletion
break;
}
}
}
void wxDLManifestEntry::UnregisterModules()
{
wxModuleList::Node *node;
for(node = m_wxmodules.GetFirst(); node; node->GetNext())
node->GetData()->Exit();
for(node = m_wxmodules.GetFirst(); node; node->GetNext())
wxModule::UnregisterModule( node->GetData() );
m_wxmodules.DeleteContents(TRUE);
}
// ---------------------------------------------------------------------------
// wxDynamicLibrary
// ---------------------------------------------------------------------------
wxDLManifest wxDynamicLibrary::ms_manifest(wxKEY_STRING);
// ------------------------
// Static accessors
// ------------------------
wxDLManifestEntry *wxDynamicLibrary::Link(const wxString &libname)
{
wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
if( entry )
{
entry->Ref();
}
else
{
entry = new wxDLManifestEntry( libname );
if( entry->IsLoaded() )
{
ms_manifest.Put(libname, (wxObject*) entry);
}
else
{
wxCHECK_MSG( !entry->Unref(), 0,
_T("Currently linked library is, ..not loaded??") );
entry = 0;
}
}
return entry;
}
bool wxDynamicLibrary::Unlink(const wxString &libname)
{
wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
if( entry )
return entry->Unref();
wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname.c_str());
return 0;
}
// ------------------------
// Class implementation
// ------------------------
wxDynamicLibrary::wxDynamicLibrary(const wxString &libname)
{
m_entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
if( m_entry != 0 )
{
m_entry->Ref();
}
else
{
m_entry = new wxDLManifestEntry( libname );
ms_manifest.Put(libname, (wxObject*) m_entry);
wxASSERT_MSG( m_entry != 0, _T("Failed to create manifest entry") );
}
}
wxDynamicLibrary::~wxDynamicLibrary()
{
wxNode *node;
ms_manifest.BeginFind();
// It's either this or store the name of the lib just to do this.
for(node = ms_manifest.Next(); node; node = ms_manifest.Next())
if( (wxDLManifestEntry*)node->GetData() == m_entry )
break;
if( m_entry && m_entry->Unref() )
delete node;
}
#ifdef __DARWIN__
// ---------------------------------------------------------------------------
// For Darwin/Mac OS X
// supply the sun style dlopen functions in terms of Darwin NS*
// ---------------------------------------------------------------------------
extern "C" {
#import <mach-o/dyld.h>
};
enum dyldErrorSource
{
OFImage,
};
static char dl_last_error[1024];
static
void TranslateError(const char *path, enum dyldErrorSource type, int number)
{
unsigned int index;
static char *OFIErrorStrings[] =
{
"%s(%d): Object Image Load Failure\n",
"%s(%d): Object Image Load Success\n",
"%s(%d): Not an recognisable object file\n",
"%s(%d): No valid architecture\n",
"%s(%d): Object image has an invalid format\n",
"%s(%d): Invalid access (permissions?)\n",
"%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
};
#define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
switch (type)
{
case OFImage:
index = number;
if (index > NUM_OFI_ERRORS - 1) {
index = NUM_OFI_ERRORS - 1;
}
sprintf(dl_last_error, OFIErrorStrings[index], path, number);
break;
default:
sprintf(dl_last_error, "%s(%d): Totally unknown error type %d\n",
path, number, type);
break;
}
}
const char *dlerror()
{
return dl_last_error;
}
void *dlopen(const char *path, int mode /* mode is ignored */)
{
int dyld_result;
NSObjectFileImage ofile;
NSModule handle = 0;
dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
if(dyld_result != NSObjectFileImageSuccess)
{
TranslateError(path, OFImage, dyld_result);
}
else
{
// NSLinkModule will cause the run to abort on any link error's
// not very friendly but the error recovery functionality is limited.
handle = NSLinkModule(ofile, path, TRUE);
}
return handle;
}
int dlclose(void *handle) /* stub only */
{
return 0;
}
void *dlsym(void *handle, const char *symbol)
{
return NSIsSymbolNameDefined(symbol)
? NSAddressOfSymbol( NSLookupAndBindSymbol(symbol) )
: 0 ;
}
#endif // __DARWIN__
#endif // wxUSE_DYNAMIC_LOADER
// vi:sts=4:sw=4:et