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 licence
11 /////////////////////////////////////////////////////////////////////////////
14 #pragma implementation "dynload.h"
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 #include "wx/wxprec.h"
27 #if wxUSE_DYNAMIC_LOADER
30 #include "wx/msw/private.h"
40 #include "wx/filename.h" // for SplitPath()
41 #include "wx/strconv.h"
43 #include "wx/dynload.h"
44 #include "wx/module.h"
46 #if defined(__DARWIN__)
48 * The dlopen port is a port from dl_next.xs by Anno Siegel.
49 * dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
50 * The method used here is just to supply the sun style dlopen etc.
51 * functions in terms of Darwin NS*.
53 void *dlopen(const char *path
, int mode
/* mode is ignored */);
54 void *dlsym(void *handle
, const char *symbol
);
55 int dlclose(void *handle
);
56 const char *dlerror(void);
59 // ============================================================================
61 // ============================================================================
63 // ---------------------------------------------------------------------------
65 // ---------------------------------------------------------------------------
67 //FIXME: This class isn't really common at all, it should be moved into
68 // platform dependent files.
70 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
71 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".dll");
72 #elif defined(__UNIX__)
74 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".sl");
76 const wxChar
*wxDynamicLibrary::ms_dllext
= _T(".so");
80 wxDllType
wxDynamicLibrary::GetProgramHandle()
82 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
83 return dlopen(0, RTLD_LAZY
);
84 #elif defined (HAVE_SHL_LOAD)
87 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
92 bool wxDynamicLibrary::Load(wxString libname
, int flags
)
94 wxASSERT_MSG(m_handle
== 0, _T("Library already loaded."));
96 // add the proper extension for the DLL ourselves unless told not to
97 if ( !(flags
& wxDL_VERBATIM
) )
99 // and also check that the libname doesn't already have it
101 wxFileName::SplitPath(libname
, NULL
, NULL
, &ext
);
104 libname
+= GetDllExt();
108 // different ways to load a shared library
110 // FIXME: should go to the platform-specific files!
111 #if defined(__WXMAC__) && !defined(__DARWIN__)
116 wxMacFilename2FSSpec( libname
, &myFSSpec
);
118 if( GetDiskFragment( &myFSSpec
,
125 myErrName
) != noErr
)
128 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
134 #elif defined(__WXPM__) || defined(__EMX__)
136 DosLoadModule(err
, sizeof(err
), libname
.c_str(), &m_handle
);
138 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
140 #if defined(__VMS) || defined(__DARWIN__)
141 m_handle
= dlopen(libname
.c_str(), 0); // The second parameter is ignored
142 #else // !__VMS && !__DARWIN__
145 if ( flags
& wxDL_LAZY
)
147 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
148 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
150 rtldFlags
|= RTLD_LAZY
;
152 wxLogDebug(_T("wxDL_LAZY is not supported on this platform"));
155 else if ( flags
& wxDL_NOW
)
158 rtldFlags
|= RTLD_NOW
;
160 wxLogDebug(_T("wxDL_NOW is not supported on this platform"));
164 if ( flags
& wxDL_GLOBAL
)
167 rtldFlags
|= RTLD_GLOBAL
;
169 wxLogDebug(_T("RTLD_GLOBAL is not supported on this platform."));
173 m_handle
= dlopen(libname
.fn_str(), rtldFlags
);
174 #endif // __VMS || __DARWIN__ ?
176 #elif defined(HAVE_SHL_LOAD)
179 if( flags
& wxDL_LAZY
)
181 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
182 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
183 shlFlags
|= BIND_DEFERRED
;
185 else if( flags
& wxDL_NOW
)
187 shlFlags
|= BIND_IMMEDIATE
;
189 m_handle
= shl_load(libname
.fn_str(), BIND_DEFERRED
, 0);
191 #elif defined(__WINDOWS__)
192 m_handle
= ::LoadLibrary(libname
.c_str());
194 #error "runtime shared lib support not implemented on this platform"
199 wxString
msg(_("Failed to load shared library '%s'"));
200 #if defined(HAVE_DLERROR) && !defined(__EMX__)
203 wxWCharBuffer buffer
= wxConvLocal
.cMB2WC( dlerror() );
204 const wxChar
*err
= buffer
;
206 const wxChar
*err
= dlerror();
210 wxLogError( msg
, err
);
212 wxLogSysError( msg
, libname
.c_str() );
219 void wxDynamicLibrary::Unload()
223 #if defined(__WXPM__) || defined(__EMX__)
224 DosFreeModule( m_handle
);
225 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
227 #elif defined(HAVE_SHL_LOAD)
228 shl_unload( m_handle
);
229 #elif defined(__WINDOWS__)
230 ::FreeLibrary( m_handle
);
231 #elif defined(__WXMAC__) && !defined(__DARWIN__)
232 CloseConnection( (CFragConnectionID
*) &m_handle
);
234 #error "runtime shared lib support not implemented"
240 void *wxDynamicLibrary::GetSymbol(const wxString
&name
, bool *success
) const
242 wxCHECK_MSG( IsLoaded(), NULL
,
243 _T("Can't load symbol from unloaded library") );
248 #if defined(__WXMAC__) && !defined(__DARWIN__)
250 CFragSymbolClass symClass
;
253 c2pstrcpy( (StringPtr
) symName
, name
);
255 strcpy( (char *)symName
, name
);
256 c2pstr( (char *)symName
);
258 if( FindSymbol( dllHandle
, symName
, &symAddress
, &symClass
) == noErr
)
259 symbol
= (void *)symAddress
;
261 #elif defined(__WXPM__) || defined(__EMX__)
262 DosQueryProcAddr( m_handle
, 1L, name
.c_str(), (PFN
*)symbol
);
264 #elif defined(HAVE_DLOPEN) || defined(__DARWIN__)
265 symbol
= dlsym( m_handle
, name
.fn_str() );
267 #elif defined(HAVE_SHL_LOAD)
268 // use local variable since shl_findsym modifies the handle argument
269 // to indicate where the symbol was found (GD)
270 wxDllType the_handle
= m_handle
;
271 if( shl_findsym( &the_handle
, name
.fn_str(), TYPE_UNDEFINED
, &symbol
) != 0 )
274 #elif defined(__WINDOWS__)
275 symbol
= (void*) ::GetProcAddress( m_handle
, name
.mb_str() );
278 #error "runtime shared lib support not implemented"
283 #if defined(HAVE_DLERROR) && !defined(__EMX__)
286 wxWCharBuffer buffer
= wxConvLocal
.cMB2WC( dlerror() );
287 const wxChar
*err
= buffer
;
289 const wxChar
*err
= dlerror();
294 wxLogError(wxT("%s"), err
);
298 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
310 wxString
wxDynamicLibrary::CanonicalizeName(const wxString
& name
,
311 wxDynamicLibraryCategory cat
)
314 if ( cat
== wxDL_MODULE
)
315 return name
+ GetDllExt();
317 return wxString(_T("lib")) + name
+ GetDllExt();
319 return name
+ GetDllExt();
324 wxString
wxDynamicLibrary::CanonicalizePluginName(const wxString
& name
,
325 wxPluginCategory cat
)
328 if ( cat
== wxDL_PLUGIN_GUI
)
330 suffix
= wxString::FromAscii(
331 #if defined(__WXMSW__)
333 #elif defined(__WXGTK__)
335 #elif defined(__WXMGL__)
337 #elif defined(__WXMOTIF__)
339 #elif defined(__WXOS2__)
341 #elif defined(__WXX11__)
343 #elif defined(__WXMAC__)
345 #elif defined(__WXCOCOA__)
350 #ifdef __WXUNIVERSAL__
351 suffix
<< _T("univ");
361 if ( !suffix
.empty() )
362 suffix
= wxString(_T("_")) + suffix
;
365 #if (wxMINOR_VERSION % 2) == 0
366 #define wxDLLVER(x,y,z) "-" #x "." #y
368 #define wxDLLVER(x,y,z) "-" #x "." #y "." #z
371 #if (wxMINOR_VERSION % 2) == 0
372 #define wxDLLVER(x,y,z) #x #y
374 #define wxDLLVER(x,y,z) #x #y #z
377 suffix
<< wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION
, wxMINOR_VERSION
,
381 return CanonicalizeName(name
+ suffix
, wxDL_MODULE
);
385 wxString
wxDynamicLibrary::GetPluginsDirectory()
388 wxString format
= wxGetInstallPrefix();
389 format
<< wxFILE_SEP_PATH
390 << wxT("lib") << wxFILE_SEP_PATH
391 << wxT("wx") << wxFILE_SEP_PATH
394 dir
.Printf(format
.c_str(), wxMAJOR_VERSION
, wxMINOR_VERSION
);
397 return wxEmptyString
;
402 // ---------------------------------------------------------------------------
404 // ---------------------------------------------------------------------------
407 wxDLImports
* wxPluginLibrary::ms_classes
= NULL
;
409 class wxPluginLibraryModule
: public wxModule
412 wxPluginLibraryModule() { }
414 // TODO: create ms_classes on demand, why always preallocate it?
415 virtual bool OnInit()
417 wxPluginLibrary::ms_classes
= new wxDLImports(wxKEY_STRING
);
418 wxPluginManager::CreateManifest();
422 virtual void OnExit()
424 delete wxPluginLibrary::ms_classes
;
425 wxPluginLibrary::ms_classes
= NULL
;
426 wxPluginManager::ClearManifest();
430 DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule
)
433 IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule
, wxModule
)
436 wxPluginLibrary::wxPluginLibrary(const wxString
&libname
, int flags
)
440 m_before
= wxClassInfo::sm_first
;
441 Load( libname
, flags
);
442 m_after
= wxClassInfo::sm_first
;
451 // Flag us for deletion
456 wxPluginLibrary::~wxPluginLibrary()
465 wxPluginLibrary
*wxPluginLibrary::RefLib()
467 wxCHECK_MSG( m_linkcount
> 0, NULL
,
468 _T("Library had been already deleted!") );
474 bool wxPluginLibrary::UnrefLib()
476 wxASSERT_MSG( m_objcount
== 0,
477 _T("Library unloaded before all objects were destroyed") );
479 if ( --m_linkcount
== 0 )
488 // ------------------------
490 // ------------------------
492 void wxPluginLibrary::UpdateClassInfo()
495 wxHashTable
*t
= wxClassInfo::sm_classTable
;
497 // FIXME: Below is simply a cut and paste specialisation of
498 // wxClassInfo::InitializeClasses. Once this stabilises,
499 // the two should probably be merged.
501 // Actually it's becoming questionable whether we should merge
502 // this info with the main ClassInfo tables since we can nearly
503 // handle this completely internally now and it does expose
504 // certain (minimal % user_stupidy) risks.
506 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
508 if( info
->m_className
)
510 if( t
->Get(info
->m_className
) == 0 )
511 t
->Put(info
->m_className
, (wxObject
*)info
);
513 // Hash all the class names into a local table too so
514 // we can quickly find the entry they correspond to.
515 (*ms_classes
)[info
->m_className
] = this;
519 #if wxUSE_EXTENDED_RTTI == 0
520 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
522 if( info
->m_baseClassName1
)
523 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
524 if( info
->m_baseClassName2
)
525 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
530 void wxPluginLibrary::RestoreClassInfo()
534 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
536 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
537 ms_classes
->erase(ms_classes
->find(info
->m_className
));
540 if( wxClassInfo::sm_first
== m_after
)
541 wxClassInfo::sm_first
= m_before
;
544 info
= wxClassInfo::sm_first
;
545 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
547 wxASSERT_MSG( info
, _T("ClassInfo from wxPluginLibrary not found on purge"));
549 info
->m_next
= m_before
;
553 void wxPluginLibrary::RegisterModules()
555 // Plugin libraries might have wxModules, Register and initialise them if
558 // Note that these classes are NOT included in the reference counting since
559 // it's implicit that they will be unloaded if and when the last handle to
560 // the library is. We do have to keep a copy of the module's pointer
561 // though, as there is currently no way to Unregister it without it.
563 wxASSERT_MSG( m_linkcount
== 1,
564 _T("RegisterModules should only be called for the first load") );
566 for ( wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
568 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
570 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
572 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
574 m_wxmodules
.push_back(m
);
575 wxModule::RegisterModule(m
);
579 // FIXME: Likewise this is (well was) very similar to InitializeModules()
581 for ( wxModuleList::iterator it
= m_wxmodules
.begin();
582 it
!= m_wxmodules
.end();
587 wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary"));
589 // XXX: Watch this, a different hash implementation might break it,
590 // a good hash implementation would let us fix it though.
592 // The name of the game is to remove any uninitialised modules and
593 // let the dtor Exit the rest on shutdown, (which we'll initiate
596 wxModuleList::iterator oldNode
= m_wxmodules
.end();
599 if( oldNode
!= m_wxmodules
.end() )
600 m_wxmodules
.erase(oldNode
);
601 wxModule::UnregisterModule( *it
);
603 } while( it
!= m_wxmodules
.end() );
605 --m_linkcount
; // Flag us for deletion
611 void wxPluginLibrary::UnregisterModules()
613 wxModuleList::iterator it
;
615 for ( it
= m_wxmodules
.begin(); it
!= m_wxmodules
.end(); ++it
)
618 for ( it
= m_wxmodules
.begin(); it
!= m_wxmodules
.end(); ++it
)
619 wxModule::UnregisterModule( *it
);
621 WX_CLEAR_LIST(wxModuleList
, m_wxmodules
);
625 // ---------------------------------------------------------------------------
627 // ---------------------------------------------------------------------------
629 wxDLManifest
* wxPluginManager::ms_manifest
= NULL
;
631 // ------------------------
633 // ------------------------
636 wxPluginManager::LoadLibrary(const wxString
&libname
, int flags
)
638 wxString
realname(libname
);
640 if( !(flags
& wxDL_VERBATIM
) )
641 realname
+= wxDynamicLibrary::GetDllExt();
643 wxPluginLibrary
*entry
;
645 if ( flags
& wxDL_NOSHARE
)
651 entry
= FindByName(realname
);
656 wxLogTrace(_T("dll"),
657 _T("LoadLibrary(%s): already loaded."), realname
.c_str());
663 entry
= new wxPluginLibrary( libname
, flags
);
665 if ( entry
->IsLoaded() )
667 (*ms_manifest
)[realname
] = entry
;
669 wxLogTrace(_T("dll"),
670 _T("LoadLibrary(%s): loaded ok."), realname
.c_str());
675 wxLogTrace(_T("dll"),
676 _T("LoadLibrary(%s): failed to load."), realname
.c_str());
678 // we have created entry just above
679 if ( !entry
->UnrefLib() )
681 // ... so UnrefLib() is supposed to delete it
682 wxFAIL_MSG( _T("Currently linked library is not loaded?") );
692 bool wxPluginManager::UnloadLibrary(const wxString
& libname
)
694 wxString realname
= libname
;
696 wxPluginLibrary
*entry
= FindByName(realname
);
700 realname
+= wxDynamicLibrary::GetDllExt();
702 entry
= FindByName(realname
);
707 wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."),
713 wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname
.c_str());
715 if ( !entry
->UnrefLib() )
717 // not really unloaded yet
721 ms_manifest
->erase(ms_manifest
->find(realname
));
726 #if WXWIN_COMPATIBILITY_2_2
727 wxPluginLibrary
*wxPluginManager::GetObjectFromHandle(wxDllType handle
)
729 for ( wxDLManifest::iterator i
= ms_manifest
->begin();
730 i
!= ms_manifest
->end();
733 wxPluginLibrary
* const lib
= i
->second
;
735 if ( lib
->GetLibHandle() == handle
)
741 #endif // WXWIN_COMPATIBILITY_2_2
743 // ------------------------
744 // Class implementation
745 // ------------------------
747 bool wxPluginManager::Load(const wxString
&libname
, int flags
)
749 m_entry
= wxPluginManager::LoadLibrary(libname
, flags
);
754 void wxPluginManager::Unload()
756 wxCHECK_RET( m_entry
, _T("unloading an invalid wxPluginManager?") );
758 for ( wxDLManifest::iterator i
= ms_manifest
->begin();
759 i
!= ms_manifest
->end();
762 if ( i
->second
== m_entry
)
764 ms_manifest
->erase(i
);
774 // ---------------------------------------------------------------------------
775 // wxDllLoader (all these methods are static)
776 // ---------------------------------------------------------------------------
778 #if WXWIN_COMPATIBILITY_2_2
780 wxDllType
wxDllLoader::LoadLibrary(const wxString
&name
, bool *success
)
782 wxPluginLibrary
*p
= wxPluginManager::LoadLibrary
785 wxDL_DEFAULT
| wxDL_VERBATIM
| wxDL_NOSHARE
789 *success
= p
!= NULL
;
791 return p
? p
->GetLibHandle() : 0;
794 void wxDllLoader::UnloadLibrary(wxDllType handle
)
796 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(handle
);
798 wxCHECK_RET( p
, _T("Unloading a library not loaded with wxDllLoader?") );
804 wxDllLoader::GetSymbol(wxDllType dllHandle
, const wxString
&name
, bool *success
)
806 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(dllHandle
);
810 wxFAIL_MSG( _T("Using a library not loaded with wxDllLoader?") );
818 return p
->GetSymbol(name
, success
);
821 #endif // WXWIN_COMPATIBILITY_2_2
823 #endif // wxUSE_DYNAMIC_LOADER