1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Dynamic loading framework
4 // Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's
5 // (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux)
9 // Copyright: (c) 2001 Ron Lee <ron@debian.org>
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
14 #pragma implementation "dynload.h"
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 #include "wx/wxprec.h"
27 #if wxUSE_DYNAMIC_LOADER
30 #include "wx/msw/private.h"
38 #include "wx/filename.h" // for SplitPath()
40 #include "wx/dynload.h"
41 #include "wx/module.h"
43 #if defined(__DARWIN__)
45 * The dlopen port is a port from dl_next.xs by Anno Siegel.
46 * dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
47 * The method used here is just to supply the sun style dlopen etc.
48 * functions in terms of Darwin NS*.
50 void *dlopen(const char *path
, int mode
/* mode is ignored */);
51 void *dlsym(void *handle
, const char *symbol
);
52 int dlclose(void *handle
);
53 const char *dlerror(void);
56 // ============================================================================
58 // ============================================================================
60 // ---------------------------------------------------------------------------
62 // ---------------------------------------------------------------------------
64 //FIXME: This class isn't really common at all, it should be moved into
65 // platform dependent files.
67 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
68 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".dll");
69 #elif defined(__UNIX__)
71 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".sl");
73 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".so");
77 wxDllType
wxDynamicLibrary::GetProgramHandle()
79 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
80 return dlopen(0, RTLD_LAZY
);
81 #elif defined (HAVE_SHL_LOAD)
84 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
89 bool wxDynamicLibrary::Load(wxString libname
, int flags
)
91 wxASSERT_MSG(m_handle
== 0, _T("Library already loaded."));
93 // add the proper extension for the DLL ourselves unless told not to
94 if ( !(flags
& wxDL_VERBATIM
) )
96 // and also check that the libname doesn't already have it
98 wxFileName::SplitPath(libname
, NULL
, NULL
, &ext
);
101 libname
+= GetDllExt();
105 // different ways to load a shared library
107 // FIXME: should go to the platform-specific files!
108 #if defined(__WXMAC__) && !defined(__DARWIN__)
113 wxMacFilename2FSSpec( libname
, &myFSSpec
);
115 if( GetDiskFragment( &myFSSpec
,
122 myErrName
) != noErr
)
125 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
131 #elif defined(__WXPM__) || defined(__EMX__)
133 DosLoadModule(err
, sizeof(err
), libname
.c_str(), &m_handle
);
135 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
137 #if defined(__VMS) || defined(__DARWIN__)
138 m_handle
= dlopen(libname
.c_str(), 0); // The second parameter is ignored
139 #else // !__VMS && !__DARWIN__
142 if ( flags
& wxDL_LAZY
)
144 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
145 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
147 rtldFlags
|= RTLD_LAZY
;
149 wxLogDebug(_T("wxDL_LAZY is not supported on this platform"));
152 else if ( flags
& wxDL_NOW
)
155 rtldFlags
|= RTLD_NOW
;
157 wxLogDebug(_T("wxDL_NOW is not supported on this platform"));
161 if ( flags
& wxDL_GLOBAL
)
164 rtldFlags
|= RTLD_GLOBAL
;
166 wxLogDebug(_T("RTLD_GLOBAL is not supported on this platform."));
170 m_handle
= dlopen(libname
.c_str(), rtldFlags
);
171 #endif // __VMS || __DARWIN__ ?
173 #elif defined(HAVE_SHL_LOAD)
176 if( flags
& wxDL_LAZY
)
178 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
179 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
180 shlFlags
|= BIND_DEFERRED
;
182 else if( flags
& wxDL_NOW
)
184 shlFlags
|= BIND_IMMEDIATE
;
186 m_handle
= shl_load(libname
.c_str(), BIND_DEFERRED
, 0);
188 #elif defined(__WINDOWS__)
189 m_handle
= ::LoadLibrary(libname
.c_str());
191 #error "runtime shared lib support not implemented on this platform"
196 wxString
msg(_("Failed to load shared library '%s'"));
197 #if defined(HAVE_DLERROR) && !defined(__EMX__)
198 const wxChar
*err
= dlerror();
200 wxLogError( msg
, err
);
202 wxLogSysError( msg
, libname
.c_str() );
209 void wxDynamicLibrary::Unload()
213 #if defined(__WXPM__) || defined(__EMX__)
214 DosFreeModule( m_handle
);
215 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
217 #elif defined(HAVE_SHL_LOAD)
218 shl_unload( m_handle
);
219 #elif defined(__WINDOWS__)
220 ::FreeLibrary( m_handle
);
221 #elif defined(__WXMAC__) && !defined(__DARWIN__)
222 CloseConnection( (CFragConnectionID
*) &m_handle
);
224 #error "runtime shared lib support not implemented"
230 void *wxDynamicLibrary::GetSymbol(const wxString
&name
, bool *success
) const
232 wxCHECK_MSG( IsLoaded(), NULL
,
233 _T("Can't load symbol from unloaded library") );
238 #if defined(__WXMAC__) && !defined(__DARWIN__)
240 CFragSymbolClass symClass
;
243 c2pstrcpy( (StringPtr
) symName
, name
);
245 strcpy( (char *)symName
, name
);
246 c2pstr( (char *)symName
);
248 if( FindSymbol( dllHandle
, symName
, &symAddress
, &symClass
) == noErr
)
249 symbol
= (void *)symAddress
;
251 #elif defined(__WXPM__) || defined(__EMX__)
252 DosQueryProcAddr( m_handle
, 1L, name
.c_str(), (PFN
*)symbol
);
254 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
255 symbol
= dlsym( m_handle
, name
.c_str() );
257 #elif defined(HAVE_SHL_LOAD)
258 if( shl_findsym( &m_handle
, name
.c_str(), TYPE_UNDEFINED
, &symbol
) != 0 )
261 #elif defined(__WINDOWS__)
262 symbol
= (void*) ::GetProcAddress( m_handle
, name
.mb_str() );
265 #error "runtime shared lib support not implemented"
270 wxString
msg(_("wxDynamicLibrary failed to GetSymbol '%s'"));
271 #if defined(HAVE_DLERROR) && !defined(__EMX__)
272 const wxChar
*err
= dlerror();
276 wxLogError( msg
, err
);
280 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
291 // ---------------------------------------------------------------------------
293 // ---------------------------------------------------------------------------
296 wxDLImports
* wxPluginLibrary::ms_classes
= NULL
;
298 class wxPluginLibraryModule
: public wxModule
301 wxPluginLibraryModule() { }
303 // TODO: create ms_classes on demand, why always preallocate it?
304 virtual bool OnInit()
306 wxPluginLibrary::ms_classes
= new wxDLImports(wxKEY_STRING
);
307 wxPluginManager::CreateManifest();
311 virtual void OnExit()
313 delete wxPluginLibrary::ms_classes
;
314 wxPluginLibrary::ms_classes
= NULL
;
315 wxPluginManager::ClearManifest();
319 DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule
)
322 IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule
, wxModule
)
325 wxPluginLibrary::wxPluginLibrary(const wxString
&libname
, int flags
)
329 m_before
= wxClassInfo::sm_first
;
330 Load( libname
, flags
);
331 m_after
= wxClassInfo::sm_first
;
340 // Flag us for deletion
345 wxPluginLibrary::~wxPluginLibrary()
354 wxPluginLibrary
*wxPluginLibrary::RefLib()
356 wxCHECK_MSG( m_linkcount
> 0, NULL
,
357 _T("Library had been already deleted!") );
363 bool wxPluginLibrary::UnrefLib()
365 wxASSERT_MSG( m_objcount
== 0,
366 _T("Library unloaded before all objects were destroyed") );
368 if ( --m_linkcount
== 0 )
377 // ------------------------
379 // ------------------------
381 void wxPluginLibrary::UpdateClassInfo()
384 wxHashTable
*t
= wxClassInfo::sm_classTable
;
386 // FIXME: Below is simply a cut and paste specialisation of
387 // wxClassInfo::InitializeClasses. Once this stabilises,
388 // the two should probably be merged.
390 // Actually it's becoming questionable whether we should merge
391 // this info with the main ClassInfo tables since we can nearly
392 // handle this completely internally now and it does expose
393 // certain (minimal % user_stupidy) risks.
395 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
397 if( info
->m_className
)
399 if( t
->Get(info
->m_className
) == 0 )
400 t
->Put(info
->m_className
, (wxObject
*)info
);
402 // Hash all the class names into a local table too so
403 // we can quickly find the entry they correspond to.
405 if( ms_classes
->Get(info
->m_className
) == 0 )
406 ms_classes
->Put(info
->m_className
, (wxObject
*) this);
410 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
412 if( info
->m_baseClassName1
)
413 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
414 if( info
->m_baseClassName2
)
415 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
419 void wxPluginLibrary::RestoreClassInfo()
423 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
425 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
426 ms_classes
->Delete(info
->m_className
);
429 if( wxClassInfo::sm_first
== m_after
)
430 wxClassInfo::sm_first
= m_before
;
433 info
= wxClassInfo::sm_first
;
434 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
436 wxASSERT_MSG( info
, _T("ClassInfo from wxPluginLibrary not found on purge"))
438 info
->m_next
= m_before
;
442 void wxPluginLibrary::RegisterModules()
444 // Plugin libraries might have wxModules, Register and initialise them if
447 // Note that these classes are NOT included in the reference counting since
448 // it's implicit that they will be unloaded if and when the last handle to
449 // the library is. We do have to keep a copy of the module's pointer
450 // though, as there is currently no way to Unregister it without it.
452 wxASSERT_MSG( m_linkcount
== 1,
453 _T("RegisterModules should only be called for the first load") );
455 for(wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
457 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
459 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
461 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
463 m_wxmodules
.Append(m
);
464 wxModule::RegisterModule(m
);
468 // FIXME: Likewise this is (well was) very similar to InitializeModules()
470 for(wxModuleList::Node
*node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
472 if( !node
->GetData()->Init() )
474 wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary"));
476 // XXX: Watch this, a different hash implementation might break it,
477 // a good hash implementation would let us fix it though.
479 // The name of the game is to remove any uninitialised modules and
480 // let the dtor Exit the rest on shutdown, (which we'll initiate
483 wxModuleList::Node
*oldNode
= 0;
485 node
= node
->GetNext();
487 wxModule::UnregisterModule( node
->GetData() );
491 --m_linkcount
; // Flag us for deletion
497 void wxPluginLibrary::UnregisterModules()
499 wxModuleList::Node
*node
;
501 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
502 node
->GetData()->Exit();
504 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
505 wxModule::UnregisterModule( node
->GetData() );
507 m_wxmodules
.DeleteContents(TRUE
);
511 // ---------------------------------------------------------------------------
513 // ---------------------------------------------------------------------------
515 wxDLManifest
* wxPluginManager::ms_manifest
= NULL
;
517 // ------------------------
519 // ------------------------
522 wxPluginManager::LoadLibrary(const wxString
&libname
, int flags
)
524 wxString
realname(libname
);
526 if( !(flags
& wxDL_VERBATIM
) )
527 realname
+= wxDynamicLibrary::GetDllExt();
529 wxPluginLibrary
*entry
;
531 if ( flags
& wxDL_NOSHARE
)
537 entry
= (wxPluginLibrary
*) ms_manifest
->Get(realname
);
542 wxLogTrace(_T("dll"),
543 _T("LoadLibrary(%s): already loaded."), realname
.c_str());
549 entry
= new wxPluginLibrary( libname
, flags
);
551 if ( entry
->IsLoaded() )
553 ms_manifest
->Put(realname
, (wxObject
*) entry
);
555 wxLogTrace(_T("dll"),
556 _T("LoadLibrary(%s): loaded ok."), realname
.c_str());
561 wxLogTrace(_T("dll"),
562 _T("LoadLibrary(%s): failed to load."), realname
.c_str());
564 // we have created entry just above
565 if ( !entry
->UnrefLib() )
567 // ... so UnrefLib() is supposed to delete it
568 wxFAIL_MSG( _T("Currently linked library is not loaded?") );
578 bool wxPluginManager::UnloadLibrary(const wxString
& libname
)
580 wxString realname
= libname
;
582 wxPluginLibrary
*entry
= (wxPluginLibrary
*) ms_manifest
->Get(realname
);
586 realname
+= wxDynamicLibrary::GetDllExt();
588 entry
= (wxPluginLibrary
*) ms_manifest
->Get(realname
);
593 wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."),
599 wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname
.c_str());
601 if ( !entry
->UnrefLib() )
603 // not really unloaded yet
607 ms_manifest
->Delete(realname
);
612 #if WXWIN_COMPATIBILITY_2_2
613 wxPluginLibrary
*wxPluginManager::GetObjectFromHandle(wxDllType handle
)
616 ms_manifest
->BeginFind();
618 for(node
= ms_manifest
->Next(); node
; node
= ms_manifest
->Next())
619 if( ((wxPluginLibrary
*)node
->GetData())->GetLibHandle() == handle
)
620 return (wxPluginLibrary
*)node
->GetData();
624 #endif // WXWIN_COMPATIBILITY_2_2
626 // ------------------------
627 // Class implementation
628 // ------------------------
630 bool wxPluginManager::Load(const wxString
&libname
, int flags
)
632 m_entry
= wxPluginManager::LoadLibrary(libname
, flags
);
636 void wxPluginManager::Unload()
639 ms_manifest
->BeginFind();
641 // It's either this or store the name of the lib just to do this.
643 for(node
= ms_manifest
->Next(); node
; node
= ms_manifest
->Next())
644 if( (wxPluginLibrary
*)node
->GetData() == m_entry
)
647 if( m_entry
&& m_entry
->UnrefLib() )
654 // ---------------------------------------------------------------------------
655 // wxDllLoader (all these methods are static)
656 // ---------------------------------------------------------------------------
658 #if WXWIN_COMPATIBILITY_2_2
660 wxDllType
wxDllLoader::LoadLibrary(const wxString
&name
)
662 wxPluginLibrary
*p
= wxPluginManager::LoadLibrary
665 wxDL_DEFAULT
| wxDL_VERBATIM
| wxDL_NOSHARE
668 return p
? p
->GetLibHandle() : 0;
671 void wxDllLoader::UnloadLibrary(wxDllType handle
)
673 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(handle
);
675 wxCHECK_RET( p
, _T("Unloading a library not loaded with wxDllLoader?") );
681 wxDllLoader::GetSymbol(wxDllType dllHandle
, const wxString
&name
, bool *success
)
683 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(dllHandle
);
687 wxFAIL_MSG( _T("Using a library not loaded with wxDllLoader?") );
695 return p
->GetSymbol(name
, success
);
698 #endif // WXWIN_COMPATIBILITY_2_2
700 #endif // wxUSE_DYNAMIC_LOADER