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"
39 #include "wx/filename.h" // for SplitPath()
40 #include "wx/strconv.h"
42 #include "wx/dynload.h"
43 #include "wx/module.h"
45 #if defined(__DARWIN__)
47 * The dlopen port is a port from dl_next.xs by Anno Siegel.
48 * dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
49 * The method used here is just to supply the sun style dlopen etc.
50 * functions in terms of Darwin NS*.
52 void *dlopen(const char *path
, int mode
/* mode is ignored */);
53 void *dlsym(void *handle
, const char *symbol
);
54 int dlclose(void *handle
);
55 const char *dlerror(void);
58 // ============================================================================
60 // ============================================================================
62 // ---------------------------------------------------------------------------
64 // ---------------------------------------------------------------------------
66 //FIXME: This class isn't really common at all, it should be moved into
67 // platform dependent files.
69 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
70 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".dll");
71 #elif defined(__UNIX__)
73 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".sl");
75 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".so");
79 wxDllType
wxDynamicLibrary::GetProgramHandle()
81 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
82 return dlopen(0, RTLD_LAZY
);
83 #elif defined (HAVE_SHL_LOAD)
86 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
91 bool wxDynamicLibrary::Load(wxString libname
, int flags
)
93 wxASSERT_MSG(m_handle
== 0, _T("Library already loaded."));
95 // add the proper extension for the DLL ourselves unless told not to
96 if ( !(flags
& wxDL_VERBATIM
) )
98 // and also check that the libname doesn't already have it
100 wxFileName::SplitPath(libname
, NULL
, NULL
, &ext
);
103 libname
+= GetDllExt();
107 // different ways to load a shared library
109 // FIXME: should go to the platform-specific files!
110 #if defined(__WXMAC__) && !defined(__DARWIN__)
115 wxMacFilename2FSSpec( libname
, &myFSSpec
);
117 if( GetDiskFragment( &myFSSpec
,
124 myErrName
) != noErr
)
127 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
133 #elif defined(__WXPM__) || defined(__EMX__)
135 DosLoadModule(err
, sizeof(err
), libname
.c_str(), &m_handle
);
137 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
139 #if defined(__VMS) || defined(__DARWIN__)
140 m_handle
= dlopen(libname
.c_str(), 0); // The second parameter is ignored
141 #else // !__VMS && !__DARWIN__
144 if ( flags
& wxDL_LAZY
)
146 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
147 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
149 rtldFlags
|= RTLD_LAZY
;
151 wxLogDebug(_T("wxDL_LAZY is not supported on this platform"));
154 else if ( flags
& wxDL_NOW
)
157 rtldFlags
|= RTLD_NOW
;
159 wxLogDebug(_T("wxDL_NOW is not supported on this platform"));
163 if ( flags
& wxDL_GLOBAL
)
166 rtldFlags
|= RTLD_GLOBAL
;
168 wxLogDebug(_T("RTLD_GLOBAL is not supported on this platform."));
172 m_handle
= dlopen(libname
.fn_str(), rtldFlags
);
173 #endif // __VMS || __DARWIN__ ?
175 #elif defined(HAVE_SHL_LOAD)
178 if( flags
& wxDL_LAZY
)
180 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
181 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
182 shlFlags
|= BIND_DEFERRED
;
184 else if( flags
& wxDL_NOW
)
186 shlFlags
|= BIND_IMMEDIATE
;
188 m_handle
= shl_load(libname
.fn_str(), BIND_DEFERRED
, 0);
190 #elif defined(__WINDOWS__)
191 m_handle
= ::LoadLibrary(libname
.c_str());
193 #error "runtime shared lib support not implemented on this platform"
198 wxString
msg(_("Failed to load shared library '%s'"));
199 #if defined(HAVE_DLERROR) && !defined(__EMX__)
202 wxWCharBuffer buffer
= wxConvLocal
.cMB2WC( dlerror() );
203 const wxChar
*err
= buffer
;
205 const wxChar
*err
= dlerror();
209 wxLogError( msg
, err
);
211 wxLogSysError( msg
, libname
.c_str() );
218 void wxDynamicLibrary::Unload()
222 #if defined(__WXPM__) || defined(__EMX__)
223 DosFreeModule( m_handle
);
224 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
226 #elif defined(HAVE_SHL_LOAD)
227 shl_unload( m_handle
);
228 #elif defined(__WINDOWS__)
229 ::FreeLibrary( m_handle
);
230 #elif defined(__WXMAC__) && !defined(__DARWIN__)
231 CloseConnection( (CFragConnectionID
*) &m_handle
);
233 #error "runtime shared lib support not implemented"
239 void *wxDynamicLibrary::GetSymbol(const wxString
&name
, bool *success
) const
241 wxCHECK_MSG( IsLoaded(), NULL
,
242 _T("Can't load symbol from unloaded library") );
247 #if defined(__WXMAC__) && !defined(__DARWIN__)
249 CFragSymbolClass symClass
;
252 c2pstrcpy( (StringPtr
) symName
, name
);
254 strcpy( (char *)symName
, name
);
255 c2pstr( (char *)symName
);
257 if( FindSymbol( dllHandle
, symName
, &symAddress
, &symClass
) == noErr
)
258 symbol
= (void *)symAddress
;
260 #elif defined(__WXPM__) || defined(__EMX__)
261 DosQueryProcAddr( m_handle
, 1L, name
.c_str(), (PFN
*)symbol
);
263 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
264 symbol
= dlsym( m_handle
, name
.fn_str() );
266 #elif defined(HAVE_SHL_LOAD)
267 // use local variable since shl_findsym modifies the handle argument
268 // to indicate where the symbol was found (GD)
269 wxDllType the_handle
= m_handle
;
270 if( shl_findsym( &the_handle
, name
.fn_str(), TYPE_UNDEFINED
, &symbol
) != 0 )
273 #elif defined(__WINDOWS__)
274 symbol
= (void*) ::GetProcAddress( m_handle
, name
.mb_str() );
277 #error "runtime shared lib support not implemented"
282 wxString
msg(_("wxDynamicLibrary failed to GetSymbol '%s'"));
283 #if defined(HAVE_DLERROR) && !defined(__EMX__)
286 wxWCharBuffer buffer
= wxConvLocal
.cMB2WC( dlerror() );
287 const wxChar
*err
= buffer
;
289 const wxChar
*err
= dlerror();
295 wxLogError( msg
, err
);
299 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
310 // ---------------------------------------------------------------------------
312 // ---------------------------------------------------------------------------
315 wxDLImports
* wxPluginLibrary::ms_classes
= NULL
;
317 class wxPluginLibraryModule
: public wxModule
320 wxPluginLibraryModule() { }
322 // TODO: create ms_classes on demand, why always preallocate it?
323 virtual bool OnInit()
325 wxPluginLibrary::ms_classes
= new wxDLImports(wxKEY_STRING
);
326 wxPluginManager::CreateManifest();
330 virtual void OnExit()
332 delete wxPluginLibrary::ms_classes
;
333 wxPluginLibrary::ms_classes
= NULL
;
334 wxPluginManager::ClearManifest();
338 DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule
)
341 IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule
, wxModule
)
344 wxPluginLibrary::wxPluginLibrary(const wxString
&libname
, int flags
)
348 m_before
= wxClassInfo::sm_first
;
349 Load( libname
, flags
);
350 m_after
= wxClassInfo::sm_first
;
359 // Flag us for deletion
364 wxPluginLibrary::~wxPluginLibrary()
373 wxPluginLibrary
*wxPluginLibrary::RefLib()
375 wxCHECK_MSG( m_linkcount
> 0, NULL
,
376 _T("Library had been already deleted!") );
382 bool wxPluginLibrary::UnrefLib()
384 wxASSERT_MSG( m_objcount
== 0,
385 _T("Library unloaded before all objects were destroyed") );
387 if ( --m_linkcount
== 0 )
396 // ------------------------
398 // ------------------------
400 void wxPluginLibrary::UpdateClassInfo()
403 wxHashTable
*t
= wxClassInfo::sm_classTable
;
405 // FIXME: Below is simply a cut and paste specialisation of
406 // wxClassInfo::InitializeClasses. Once this stabilises,
407 // the two should probably be merged.
409 // Actually it's becoming questionable whether we should merge
410 // this info with the main ClassInfo tables since we can nearly
411 // handle this completely internally now and it does expose
412 // certain (minimal % user_stupidy) risks.
414 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
416 if( info
->m_className
)
418 if( t
->Get(info
->m_className
) == 0 )
419 t
->Put(info
->m_className
, (wxObject
*)info
);
421 // Hash all the class names into a local table too so
422 // we can quickly find the entry they correspond to.
423 (*ms_classes
)[info
->m_className
] = this;
427 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
429 if( info
->m_baseClassName1
)
430 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
431 if( info
->m_baseClassName2
)
432 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
436 void wxPluginLibrary::RestoreClassInfo()
440 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
442 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
443 ms_classes
->erase(ms_classes
->find(info
->m_className
));
446 if( wxClassInfo::sm_first
== m_after
)
447 wxClassInfo::sm_first
= m_before
;
450 info
= wxClassInfo::sm_first
;
451 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
453 wxASSERT_MSG( info
, _T("ClassInfo from wxPluginLibrary not found on purge"));
455 info
->m_next
= m_before
;
459 void wxPluginLibrary::RegisterModules()
461 // Plugin libraries might have wxModules, Register and initialise them if
464 // Note that these classes are NOT included in the reference counting since
465 // it's implicit that they will be unloaded if and when the last handle to
466 // the library is. We do have to keep a copy of the module's pointer
467 // though, as there is currently no way to Unregister it without it.
469 wxASSERT_MSG( m_linkcount
== 1,
470 _T("RegisterModules should only be called for the first load") );
472 for ( wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
474 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
476 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
478 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
480 m_wxmodules
.Append(m
);
481 wxModule::RegisterModule(m
);
485 // FIXME: Likewise this is (well was) very similar to InitializeModules()
487 for ( wxModuleList::Node
*node
= m_wxmodules
.GetFirst();
489 node
= node
->GetNext())
491 if( !node
->GetData()->Init() )
493 wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary"));
495 // XXX: Watch this, a different hash implementation might break it,
496 // a good hash implementation would let us fix it though.
498 // The name of the game is to remove any uninitialised modules and
499 // let the dtor Exit the rest on shutdown, (which we'll initiate
502 wxModuleList::Node
*oldNode
= 0;
504 node
= node
->GetNext();
506 wxModule::UnregisterModule( node
->GetData() );
510 --m_linkcount
; // Flag us for deletion
516 void wxPluginLibrary::UnregisterModules()
518 wxModuleList::Node
*node
;
520 for ( node
= m_wxmodules
.GetFirst(); node
; node
= node
->GetNext() )
521 node
->GetData()->Exit();
523 for ( node
= m_wxmodules
.GetFirst(); node
; node
= node
->GetNext() )
524 wxModule::UnregisterModule( node
->GetData() );
526 m_wxmodules
.DeleteContents(TRUE
);
530 // ---------------------------------------------------------------------------
532 // ---------------------------------------------------------------------------
534 wxDLManifest
* wxPluginManager::ms_manifest
= NULL
;
536 // ------------------------
538 // ------------------------
541 wxPluginManager::LoadLibrary(const wxString
&libname
, int flags
)
543 wxString
realname(libname
);
545 if( !(flags
& wxDL_VERBATIM
) )
546 realname
+= wxDynamicLibrary::GetDllExt();
548 wxPluginLibrary
*entry
;
550 if ( flags
& wxDL_NOSHARE
)
556 entry
= FindByName(realname
);
561 wxLogTrace(_T("dll"),
562 _T("LoadLibrary(%s): already loaded."), realname
.c_str());
568 entry
= new wxPluginLibrary( libname
, flags
);
570 if ( entry
->IsLoaded() )
572 (*ms_manifest
)[realname
] = entry
;
574 wxLogTrace(_T("dll"),
575 _T("LoadLibrary(%s): loaded ok."), realname
.c_str());
580 wxLogTrace(_T("dll"),
581 _T("LoadLibrary(%s): failed to load."), realname
.c_str());
583 // we have created entry just above
584 if ( !entry
->UnrefLib() )
586 // ... so UnrefLib() is supposed to delete it
587 wxFAIL_MSG( _T("Currently linked library is not loaded?") );
597 bool wxPluginManager::UnloadLibrary(const wxString
& libname
)
599 wxString realname
= libname
;
601 wxPluginLibrary
*entry
= FindByName(realname
);
605 realname
+= wxDynamicLibrary::GetDllExt();
607 entry
= FindByName(realname
);
612 wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."),
618 wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname
.c_str());
620 if ( !entry
->UnrefLib() )
622 // not really unloaded yet
626 ms_manifest
->erase(ms_manifest
->find(realname
));
631 #if WXWIN_COMPATIBILITY_2_2
632 wxPluginLibrary
*wxPluginManager::GetObjectFromHandle(wxDllType handle
)
634 for ( wxDLManifest::iterator i
= ms_manifest
->begin();
635 i
!= ms_manifest
->end();
638 wxPluginLibrary
* const lib
= i
->second
;
640 if ( lib
->GetLibHandle() == handle
)
646 #endif // WXWIN_COMPATIBILITY_2_2
648 // ------------------------
649 // Class implementation
650 // ------------------------
652 bool wxPluginManager::Load(const wxString
&libname
, int flags
)
654 m_entry
= wxPluginManager::LoadLibrary(libname
, flags
);
659 void wxPluginManager::Unload()
661 wxCHECK_RET( m_entry
, _T("unloading an invalid wxPluginManager?") );
663 for ( wxDLManifest::iterator i
= ms_manifest
->begin();
664 i
!= ms_manifest
->end();
667 if ( i
->second
== m_entry
)
669 ms_manifest
->erase(i
);
679 // ---------------------------------------------------------------------------
680 // wxDllLoader (all these methods are static)
681 // ---------------------------------------------------------------------------
683 #if WXWIN_COMPATIBILITY_2_2
685 wxDllType
wxDllLoader::LoadLibrary(const wxString
&name
, bool *success
)
687 wxPluginLibrary
*p
= wxPluginManager::LoadLibrary
690 wxDL_DEFAULT
| wxDL_VERBATIM
| wxDL_NOSHARE
694 *success
= p
!= NULL
;
696 return p
? p
->GetLibHandle() : 0;
699 void wxDllLoader::UnloadLibrary(wxDllType handle
)
701 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(handle
);
703 wxCHECK_RET( p
, _T("Unloading a library not loaded with wxDllLoader?") );
709 wxDllLoader::GetSymbol(wxDllType dllHandle
, const wxString
&name
, bool *success
)
711 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(dllHandle
);
715 wxFAIL_MSG( _T("Using a library not loaded with wxDllLoader?") );
723 return p
->GetSymbol(name
, success
);
726 #endif // WXWIN_COMPATIBILITY_2_2
728 #endif // wxUSE_DYNAMIC_LOADER