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"
42 #if defined(__DARWIN__)
44 * The dlopen port is a port from dl_next.xs by Anno Siegel.
45 * dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
46 * The method used here is just to supply the sun style dlopen etc.
47 * functions in terms of Darwin NS*.
49 void *dlopen(const char *path
, int mode
/* mode is ignored */);
50 void *dlsym(void *handle
, const char *symbol
);
51 int dlclose(void *handle
);
52 const char *dlerror(void);
55 // ============================================================================
57 // ============================================================================
59 // ---------------------------------------------------------------------------
61 // ---------------------------------------------------------------------------
63 //FIXME: This class isn't really common at all, it should be moved into
64 // platform dependent files.
66 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
67 const wxString
wxDynamicLibrary::ms_dllext( _T(".dll") );
68 #elif defined(__UNIX__)
70 const wxString
wxDynamicLibrary::ms_dllext( _T(".sl") );
72 const wxString
wxDynamicLibrary::ms_dllext( _T(".so") );
76 wxDllType
wxDynamicLibrary::GetProgramHandle()
78 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
79 return dlopen(0, RTLD_LAZY
);
80 #elif defined (HAVE_SHL_LOAD)
83 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
88 bool wxDynamicLibrary::Load(wxString libname
, int flags
)
90 wxASSERT_MSG(m_handle
== 0, _T("Library already loaded."));
92 // add the proper extension for the DLL ourselves unless told not to
93 if ( !(flags
& wxDL_VERBATIM
) )
95 // and also check that the libname doesn't already have it
97 wxFileName::SplitPath(libname
, NULL
, NULL
, &ext
);
100 libname
+= GetDllExt();
104 #if defined(__WXMAC__) && !defined(__DARWIN__)
109 wxMacFilename2FSSpec( libname
, &myFSSpec
);
111 if( GetDiskFragment( &myFSSpec
,
118 myErrName
) != noErr
)
121 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
127 #elif defined(__WXPM__) || defined(__EMX__)
129 DosLoadModule(err
, sizeof(err
), libname
.c_str(), &m_handle
);
131 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
133 #if defined(__VMS) || defined(__DARWIN__)
134 m_handle
= dlopen(libname
.c_str(), 0); // The second parameter is ignored
138 if( flags
& wxDL_LAZY
)
140 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
141 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
142 rtldFlags
|= RTLD_LAZY
;
144 else if( flags
& wxDL_NOW
)
146 rtldFlags
|= RTLD_NOW
;
148 if( flags
& wxDL_GLOBAL
)
151 wxLogDebug(_T("WARNING: RTLD_GLOBAL is not a supported on this platform."));
153 rtldFlags
|= RTLD_GLOBAL
;
156 m_handle
= dlopen(libname
.c_str(), rtldFlags
);
157 #endif // __VMS || __DARWIN__
159 #elif defined(HAVE_SHL_LOAD)
162 if( flags
& wxDL_LAZY
)
164 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
165 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
166 shlFlags
|= BIND_DEFERRED
;
168 else if( flags
& wxDL_NOW
)
170 shlFlags
|= BIND_IMMEDIATE
;
172 m_handle
= shl_load(libname
.c_str(), BIND_DEFERRED
, 0);
174 #elif defined(__WINDOWS__)
175 m_handle
= ::LoadLibrary(libname
.c_str());
178 #error "runtime shared lib support not implemented"
183 wxString
msg(_("Failed to load shared library '%s'"));
184 #if defined(HAVE_DLERROR) && !defined(__EMX__)
185 const wxChar
*err
= dlerror();
187 wxLogError( msg
, err
);
189 wxLogSysError( msg
, libname
.c_str() );
196 void wxDynamicLibrary::Unload()
200 #if defined(__WXPM__) || defined(__EMX__)
201 DosFreeModule( m_handle
);
202 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
204 #elif defined(HAVE_SHL_LOAD)
205 shl_unload( m_handle
);
206 #elif defined(__WINDOWS__)
207 ::FreeLibrary( m_handle
);
208 #elif defined(__WXMAC__) && !defined(__DARWIN__)
209 CloseConnection( (CFragConnectionID
*) &m_handle
);
211 #error "runtime shared lib support not implemented"
217 void *wxDynamicLibrary::GetSymbol(const wxString
&name
, bool *success
) const
219 wxCHECK_MSG( IsLoaded(), NULL
,
220 _T("Can't load symbol from unloaded library") );
225 #if defined(__WXMAC__) && !defined(__DARWIN__)
227 CFragSymbolClass symClass
;
230 c2pstrcpy( (StringPtr
) symName
, name
);
232 strcpy( (char *)symName
, name
);
233 c2pstr( (char *)symName
);
235 if( FindSymbol( dllHandle
, symName
, &symAddress
, &symClass
) == noErr
)
236 symbol
= (void *)symAddress
;
238 #elif defined(__WXPM__) || defined(__EMX__)
239 DosQueryProcAddr( m_handle
, 1L, name
.c_str(), (PFN
*)symbol
);
241 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
242 symbol
= dlsym( m_handle
, name
.c_str() );
244 #elif defined(HAVE_SHL_LOAD)
245 if( shl_findsym( &m_handle
, name
.c_str(), TYPE_UNDEFINED
, &symbol
) != 0 )
248 #elif defined(__WINDOWS__)
249 symbol
= (void*) ::GetProcAddress( m_handle
, name
.mb_str() );
252 #error "runtime shared lib support not implemented"
257 wxString
msg(_("wxDynamicLibrary failed to GetSymbol '%s'"));
258 #if defined(HAVE_DLERROR) && !defined(__EMX__)
259 const wxChar
*err
= dlerror();
263 wxLogError( msg
, err
);
267 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
278 // ---------------------------------------------------------------------------
280 // ---------------------------------------------------------------------------
283 wxDLImports
wxPluginLibrary::ms_classes(wxKEY_STRING
);
285 wxPluginLibrary::wxPluginLibrary(const wxString
&libname
, int flags
)
289 m_before
= wxClassInfo::sm_first
;
290 Load( libname
, flags
);
291 m_after
= wxClassInfo::sm_first
;
299 --m_linkcount
; // Flag us for deletion
302 wxPluginLibrary::~wxPluginLibrary()
311 bool wxPluginLibrary::UnrefLib()
313 wxASSERT_MSG( m_objcount
== 0, _T("Library unloaded before all objects were destroyed") );
314 if( m_linkcount
== 0 || --m_linkcount
== 0 )
322 // ------------------------
324 // ------------------------
326 void wxPluginLibrary::UpdateClassInfo()
329 wxHashTable
*t
= wxClassInfo::sm_classTable
;
331 // FIXME: Below is simply a cut and paste specialisation of
332 // wxClassInfo::InitializeClasses. Once this stabilises,
333 // the two should probably be merged.
335 // Actually it's becoming questionable whether we should merge
336 // this info with the main ClassInfo tables since we can nearly
337 // handle this completely internally now and it does expose
338 // certain (minimal % user_stupidy) risks.
340 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
342 if( info
->m_className
)
344 if( t
->Get(info
->m_className
) == 0 )
345 t
->Put(info
->m_className
, (wxObject
*)info
);
347 // Hash all the class names into a local table too so
348 // we can quickly find the entry they correspond to.
350 if( ms_classes
.Get(info
->m_className
) == 0 )
351 ms_classes
.Put(info
->m_className
, (wxObject
*) this);
355 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
357 if( info
->m_baseClassName1
)
358 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
359 if( info
->m_baseClassName2
)
360 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
364 void wxPluginLibrary::RestoreClassInfo()
368 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
370 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
371 ms_classes
.Delete(info
->m_className
);
374 if( wxClassInfo::sm_first
== m_after
)
375 wxClassInfo::sm_first
= m_before
;
378 info
= wxClassInfo::sm_first
;
379 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
381 wxASSERT_MSG( info
, _T("ClassInfo from wxPluginLibrary not found on purge"))
383 info
->m_next
= m_before
;
387 void wxPluginLibrary::RegisterModules()
389 // Plugin libraries might have wxModules, Register and initialise them if
392 // Note that these classes are NOT included in the reference counting since
393 // it's implicit that they will be unloaded if and when the last handle to
394 // the library is. We do have to keep a copy of the module's pointer
395 // though, as there is currently no way to Unregister it without it.
397 wxASSERT_MSG( m_linkcount
== 1,
398 _T("RegisterModules should only be called for the first load") );
400 for(wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
402 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
404 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
406 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
408 m_wxmodules
.Append(m
);
409 wxModule::RegisterModule(m
);
413 // FIXME: Likewise this is (well was) very similar to InitializeModules()
415 for(wxModuleList::Node
*node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
417 if( !node
->GetData()->Init() )
419 wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary"));
421 // XXX: Watch this, a different hash implementation might break it,
422 // a good hash implementation would let us fix it though.
424 // The name of the game is to remove any uninitialised modules and
425 // let the dtor Exit the rest on shutdown, (which we'll initiate
428 wxModuleList::Node
*oldNode
= 0;
430 node
= node
->GetNext();
432 wxModule::UnregisterModule( node
->GetData() );
436 --m_linkcount
; // Flag us for deletion
442 void wxPluginLibrary::UnregisterModules()
444 wxModuleList::Node
*node
;
446 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
447 node
->GetData()->Exit();
449 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
450 wxModule::UnregisterModule( node
->GetData() );
452 m_wxmodules
.DeleteContents(TRUE
);
456 // ---------------------------------------------------------------------------
458 // ---------------------------------------------------------------------------
460 wxDLManifest
wxPluginManager::ms_manifest(wxKEY_STRING
);
462 // ------------------------
464 // ------------------------
466 wxPluginLibrary
*wxPluginManager::LoadLibrary(const wxString
&libname
, int flags
)
468 wxString
realname(libname
);
470 if( !(flags
& wxDL_VERBATIM
) )
471 realname
+= wxDynamicLibrary::GetDllExt();
473 wxPluginLibrary
*entry
= (wxPluginLibrary
*) ms_manifest
.Get(realname
);
481 entry
= new wxPluginLibrary( libname
, flags
);
483 if( entry
->IsLoaded() )
485 ms_manifest
.Put(realname
, (wxObject
*) entry
);
489 wxCHECK_MSG( entry
->UnrefLib(), 0,
490 _T("Currently linked library is, ..not loaded??") );
497 bool wxPluginManager::UnloadLibrary(const wxString
&libname
)
499 wxPluginLibrary
*entry
= (wxPluginLibrary
*) ms_manifest
.Get(libname
);
502 entry
= (wxPluginLibrary
*) ms_manifest
.Get(libname
+ wxDynamicLibrary::GetDllExt());
505 return entry
->UnrefLib();
507 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname
.c_str());
511 #if WXWIN_COMPATIBILITY_2_2
512 wxPluginLibrary
*wxPluginManager::GetObjectFromHandle(wxDllType handle
)
515 ms_manifest
.BeginFind();
517 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
518 if( ((wxPluginLibrary
*)node
->GetData())->GetLibHandle() == handle
)
519 return (wxPluginLibrary
*)node
->GetData();
525 // ------------------------
526 // Class implementation
527 // ------------------------
529 bool wxPluginManager::Load(const wxString
&libname
, int flags
)
531 m_entry
= wxPluginManager::LoadLibrary(libname
, flags
);
535 void wxPluginManager::Unload()
538 ms_manifest
.BeginFind();
540 // It's either this or store the name of the lib just to do this.
542 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
543 if( (wxPluginLibrary
*)node
->GetData() == m_entry
)
546 if( m_entry
&& m_entry
->UnrefLib() )
553 // ---------------------------------------------------------------------------
554 // wxDllLoader (all these methods are static)
555 // ---------------------------------------------------------------------------
557 #if WXWIN_COMPATIBILITY_2_2
559 wxDllType
wxDllLoader::LoadLibrary(const wxString
&name
)
561 wxPluginLibrary
*p
= wxPluginManager::LoadLibrary(name
, wxDL_DEFAULT
| wxDL_VERBATIM
);
562 return p
->GetLibHandle();
565 void wxDllLoader::UnloadLibrary(wxDllType handle
)
567 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(handle
);
571 void *wxDllLoader::GetSymbol(wxDllType dllHandle
, const wxString
&name
, bool *success
)
573 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(dllHandle
);
574 return p
->GetSymbol(name
, success
);
577 #endif // WXWIN_COMPATIBILITY_2_2
579 #endif // wxUSE_DYNAMIC_LOADER