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 // ============================================================================
44 // ============================================================================
46 // ---------------------------------------------------------------------------
48 // ---------------------------------------------------------------------------
50 //FIXME: This class isn't really common at all, it should be moved into
51 // platform dependent files.
53 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
54 const wxString
wxDynamicLibrary::ms_dllext( _T(".dll") );
55 #elif defined(__UNIX__)
57 const wxString
wxDynamicLibrary::ms_dllext( _T(".sl") );
59 const wxString
wxDynamicLibrary::ms_dllext( _T(".so") );
63 wxDllType
wxDynamicLibrary::GetProgramHandle()
65 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
66 return dlopen(0, RTLD_LAZY
);
67 #elif defined (HAVE_SHL_LOAD)
70 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
75 bool wxDynamicLibrary::Load(wxString libname
, int flags
)
77 wxASSERT_MSG(m_handle
== 0, _T("Library already loaded."));
79 // add the proper extension for the DLL ourselves unless told not to
80 if ( !(flags
& wxDL_VERBATIM
) )
82 // and also check that the libname doesn't already have it
84 wxFileName::SplitPath(libname
, NULL
, NULL
, &ext
);
87 libname
+= GetDllExt();
91 #if defined(__WXMAC__) && !defined(__UNIX__)
96 wxMacFilename2FSSpec( libname
, &myFSSpec
);
98 if( GetDiskFragment( &myFSSpec
,
105 myErrName
) != noErr
)
108 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
114 #elif defined(__WXPM__) || defined(__EMX__)
116 DosLoadModule(err
, sizeof(err
), libname
.c_str(), &m_handle
)
118 #elif defined(HAVE_DLOPEN)
121 m_handle
= dlopen(libname
.c_str(), 0); // The second parameter is ignored
125 if( flags
& wxDL_LAZY
)
127 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
128 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
129 rtldFlags
|= RTLD_LAZY
;
131 else if( flags
& wxDL_NOW
)
133 rtldFlags
|= RTLD_NOW
;
135 if( flags
& wxDL_GLOBAL
)
138 wxLogDebug(_T("WARNING: RTLD_GLOBAL is not a supported on this platform."));
140 rtldFlags
|= RTLD_GLOBAL
;
143 m_handle
= dlopen(libname
.c_str(), rtldFlags
);
146 #elif defined(HAVE_SHL_LOAD)
149 if( flags
& wxDL_LAZY
)
151 wxASSERT_MSG( (flags
& wxDL_NOW
) == 0,
152 _T("wxDL_LAZY and wxDL_NOW are mutually exclusive.") );
153 shlFlags
|= BIND_DEFERRED
;
155 else if( flags
& wxDL_NOW
)
157 shlFlags
|= BIND_IMMEDIATE
;
159 m_handle
= shl_load(libname
.c_str(), BIND_DEFERRED
, 0);
161 #elif defined(__DARWIN__)
162 NSObjectFileImage ofile
;
163 int dyld_result
= NSCreateObjectFileImageFromFile(libname
.c_str(), &ofile
);
165 if (dyld_result
!= NSObjectFileImageSuccess
)
167 TranslateError(libname
.c_str(), OFImage
, dyld_result
);
171 // NSLinkModule will cause the run to abort on any link error's
172 // not very friendly but the error recovery functionality is limited.
173 m_handle
= NSLinkModule(ofile
, libname
.c_str(), TRUE
);
176 #elif defined(__WINDOWS__)
177 m_handle
= ::LoadLibrary(libname
.c_str());
180 #error "runtime shared lib support not implemented"
185 wxString
msg(_("Failed to load shared library '%s'"));
187 const wxChar
*err
= dlerror();
189 wxLogError( msg
, err
);
191 wxLogSysError( msg
, libname
.c_str() );
198 void wxDynamicLibrary::Unload()
202 #if defined(__WXPM__) || defined(__EMX__)
203 DosFreeModule( m_handle
);
204 #elif defined(HAVE_DLOPEN)
206 #elif defined(HAVE_SHL_LOAD)
207 shl_unload( m_handle
);
208 #elif defined(__WINDOWS__)
209 ::FreeLibrary( m_handle
);
210 #elif defined(__WXMAC__)
211 CloseConnection( &m_handle
);
213 #error "runtime shared lib support not implemented"
219 void *wxDynamicLibrary::GetSymbol(const wxString
&name
, bool *success
) const
221 wxCHECK_MSG( IsLoaded(), NULL
,
222 _T("Can't load symbol from unloaded library") );
227 #if defined(__WXMAC__) && !defined(__UNIX__)
229 CFragSymbolClass symClass
;
232 c2pstrcpy( (StringPtr
) symName
, name
);
234 strcpy( (char *)symName
, name
);
235 c2pstr( (char *)symName
);
237 if( FindSymbol( dllHandle
, symName
, &symAddress
, &symClass
) == noErr
)
238 symbol
= (void *)symAddress
;
240 #elif defined(__WXPM__) || defined(__EMX__)
241 DosQueryProcAddr( m_handle
, 1L, name
.c_str(), (PFN
*)symbol
);
243 #elif defined(HAVE_DLOPEN)
244 symbol
= dlsym( m_handle
, name
.c_str() );
246 #elif defined(HAVE_SHL_LOAD)
247 if( shl_findsym( &m_handle
, name
.c_str(), TYPE_UNDEFINED
, &symbol
) != 0 )
250 #elif defined(__DARWIN__)
251 if( NSIsSymbolNameDefined( name
.c_str() ) )
252 symbol
= NSAddressOfSymbol( NSLookupAndBindSymbol( name
.c_str() ) );
254 #elif defined(__WINDOWS__)
255 symbol
= (void*) ::GetProcAddress( m_handle
, name
.mb_str() );
258 #error "runtime shared lib support not implemented"
263 wxString
msg(_("wxDynamicLibrary failed to GetSymbol '%s'"));
265 const wxChar
*err
= dlerror();
269 wxLogError( msg
, err
);
273 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
284 // ---------------------------------------------------------------------------
286 // ---------------------------------------------------------------------------
289 wxDLImports
wxPluginLibrary::ms_classes(wxKEY_STRING
);
291 wxPluginLibrary::wxPluginLibrary(const wxString
&libname
, int flags
)
295 m_before
= wxClassInfo::sm_first
;
296 Load( libname
, flags
);
297 m_after
= wxClassInfo::sm_first
;
305 --m_linkcount
; // Flag us for deletion
308 wxPluginLibrary::~wxPluginLibrary()
317 bool wxPluginLibrary::UnrefLib()
319 wxASSERT_MSG( m_objcount
== 0, _T("Library unloaded before all objects were destroyed") );
320 if( m_linkcount
== 0 || --m_linkcount
== 0 )
328 // ------------------------
330 // ------------------------
332 void wxPluginLibrary::UpdateClassInfo()
335 wxHashTable
*t
= wxClassInfo::sm_classTable
;
337 // FIXME: Below is simply a cut and paste specialisation of
338 // wxClassInfo::InitializeClasses. Once this stabilises,
339 // the two should probably be merged.
341 // Actually it's becoming questionable whether we should merge
342 // this info with the main ClassInfo tables since we can nearly
343 // handle this completely internally now and it does expose
344 // certain (minimal % user_stupidy) risks.
346 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
348 if( info
->m_className
)
350 if( t
->Get(info
->m_className
) == 0 )
351 t
->Put(info
->m_className
, (wxObject
*)info
);
353 // Hash all the class names into a local table too so
354 // we can quickly find the entry they correspond to.
356 if( ms_classes
.Get(info
->m_className
) == 0 )
357 ms_classes
.Put(info
->m_className
, (wxObject
*) this);
361 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
363 if( info
->m_baseClassName1
)
364 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
365 if( info
->m_baseClassName2
)
366 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
370 void wxPluginLibrary::RestoreClassInfo()
374 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
376 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
377 ms_classes
.Delete(info
->m_className
);
380 if( wxClassInfo::sm_first
== m_after
)
381 wxClassInfo::sm_first
= m_before
;
384 info
= wxClassInfo::sm_first
;
385 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
387 wxASSERT_MSG( info
, _T("ClassInfo from wxPluginLibrary not found on purge"))
389 info
->m_next
= m_before
;
393 void wxPluginLibrary::RegisterModules()
395 // Plugin libraries might have wxModules, Register and initialise them if
398 // Note that these classes are NOT included in the reference counting since
399 // it's implicit that they will be unloaded if and when the last handle to
400 // the library is. We do have to keep a copy of the module's pointer
401 // though, as there is currently no way to Unregister it without it.
403 wxASSERT_MSG( m_linkcount
== 1,
404 _T("RegisterModules should only be called for the first load") );
406 for(wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
408 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
410 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
412 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
414 m_wxmodules
.Append(m
);
415 wxModule::RegisterModule(m
);
419 // FIXME: Likewise this is (well was) very similar to InitializeModules()
421 for(wxModuleList::Node
*node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
423 if( !node
->GetData()->Init() )
425 wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary"));
427 // XXX: Watch this, a different hash implementation might break it,
428 // a good hash implementation would let us fix it though.
430 // The name of the game is to remove any uninitialised modules and
431 // let the dtor Exit the rest on shutdown, (which we'll initiate
434 wxModuleList::Node
*oldNode
= 0;
436 node
= node
->GetNext();
438 wxModule::UnregisterModule( node
->GetData() );
442 --m_linkcount
; // Flag us for deletion
448 void wxPluginLibrary::UnregisterModules()
450 wxModuleList::Node
*node
;
452 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
453 node
->GetData()->Exit();
455 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
456 wxModule::UnregisterModule( node
->GetData() );
458 m_wxmodules
.DeleteContents(TRUE
);
462 // ---------------------------------------------------------------------------
464 // ---------------------------------------------------------------------------
466 wxDLManifest
wxPluginManager::ms_manifest(wxKEY_STRING
);
468 // ------------------------
470 // ------------------------
472 wxPluginLibrary
*wxPluginManager::LoadLibrary(const wxString
&libname
, int flags
)
474 wxString
realname(libname
);
476 if( !(flags
& wxDL_VERBATIM
) )
477 realname
+= wxDynamicLibrary::GetDllExt();
479 wxPluginLibrary
*entry
= (wxPluginLibrary
*) ms_manifest
.Get(realname
);
487 entry
= new wxPluginLibrary( libname
, flags
);
489 if( entry
->IsLoaded() )
491 ms_manifest
.Put(realname
, (wxObject
*) entry
);
495 wxCHECK_MSG( entry
->UnrefLib(), 0,
496 _T("Currently linked library is, ..not loaded??") );
503 bool wxPluginManager::UnloadLibrary(const wxString
&libname
)
505 wxPluginLibrary
*entry
= (wxPluginLibrary
*) ms_manifest
.Get(libname
);
508 entry
= (wxPluginLibrary
*) ms_manifest
.Get(libname
+ wxDynamicLibrary::GetDllExt());
511 return entry
->UnrefLib();
513 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname
.c_str());
517 #if WXWIN_COMPATIBILITY_2_2
518 wxPluginLibrary
*wxPluginManager::GetObjectFromHandle(wxDllType handle
)
521 ms_manifest
.BeginFind();
523 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
524 if( ((wxPluginLibrary
*)node
->GetData())->GetLibHandle() == handle
)
525 return (wxPluginLibrary
*)node
->GetData();
531 // ------------------------
532 // Class implementation
533 // ------------------------
535 bool wxPluginManager::Load(const wxString
&libname
, int flags
)
537 m_entry
= wxPluginManager::LoadLibrary(libname
, flags
);
541 void wxPluginManager::Unload()
544 ms_manifest
.BeginFind();
546 // It's either this or store the name of the lib just to do this.
548 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
549 if( (wxPluginLibrary
*)node
->GetData() == m_entry
)
552 if( m_entry
&& m_entry
->UnrefLib() )
561 // ---------------------------------------------------------------------------
562 // For Darwin/Mac OS X
563 // supply the sun style dlopen functions in terms of Darwin NS*
564 // ---------------------------------------------------------------------------
567 #import <mach-o/dyld.h>
575 static char dl_last_error
[1024];
577 static void TranslateError(const char *path
, enum dyldErrorSource type
, int number
)
580 static char *OFIErrorStrings
[] =
582 "%s(%d): Object Image Load Failure\n",
583 "%s(%d): Object Image Load Success\n",
584 "%s(%d): Not an recognisable object file\n",
585 "%s(%d): No valid architecture\n",
586 "%s(%d): Object image has an invalid format\n",
587 "%s(%d): Invalid access (permissions?)\n",
588 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
590 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
596 if (index
> NUM_OFI_ERRORS
- 1) {
597 index
= NUM_OFI_ERRORS
- 1;
599 sprintf(dl_last_error
, OFIErrorStrings
[index
], path
, number
);
603 sprintf(dl_last_error
, "%s(%d): Totally unknown error type %d\n",
612 // ---------------------------------------------------------------------------
613 // wxDllLoader (all these methods are static)
614 // ---------------------------------------------------------------------------
616 #if WXWIN_COMPATIBILITY_2_2
618 wxDllType
wxDllLoader::LoadLibrary(const wxString
&name
)
620 wxPluginLibrary
*p
= wxPluginManager::LoadLibrary(name
, wxDL_DEFAULT
| wxDL_VERBATIM
);
621 return p
->GetLibHandle();
624 void wxDllLoader::UnloadLibrary(wxDllType handle
)
626 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(handle
);
630 void *wxDllLoader::GetSymbol(wxDllType dllHandle
, const wxString
&name
, bool *success
)
632 wxPluginLibrary
*p
= wxPluginManager::GetObjectFromHandle(dllHandle
);
633 return p
->GetSymbol(name
, success
);
636 #endif // WXWIN_COMPATIBILITY_2_2
638 #endif // wxUSE_DYNAMIC_LOADER