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/dynload.h"
40 // ----------------------------------------------------------------------------
41 // conditional compilation
42 // ----------------------------------------------------------------------------
44 #if defined(__WXPM__) || defined(__EMX__)
47 #define wxDllOpen(error, lib, handle) DosLoadModule(error, sizeof(error), lib, &handle)
48 #define wxDllGetSymbol(handle, modaddr) DosQueryProcAddr(handle, 1L, NULL, (PFN*)modaddr)
49 #define wxDllClose(handle) DosFreeModule(handle)
51 #elif defined(HAVE_DLOPEN)
52 // note about dlopen() flags: we use RTLD_NOW to have more Windows-like
53 // behaviour (Win won't let you load a library with missing symbols) and
54 // RTLD_GLOBAL because it is needed sometimes and probably doesn't hurt
55 // otherwise. On True64-Unix RTLD_GLOBAL is not allowed and on VMS the
56 // second argument on dlopen is ignored.
59 #define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
61 #elif defined( __osf__ )
62 #define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY)
65 #define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY | RTLD_GLOBAL)
68 #define wxDllGetSymbol(handle, name) dlsym(handle, name)
69 #define wxDllClose dlclose
71 #elif defined(HAVE_SHL_LOAD)
72 #define wxDllOpen(lib) shl_load(lib.fn_str(), BIND_DEFERRED, 0)
73 #define wxDllClose shl_unload
75 static inline void *wxDllGetSymbol(shl_t handle
, const wxString
& name
)
78 return ( shl_findsym(&handle
, name
.mb_str(), TYPE_UNDEFINED
, &sym
) == 0 )
82 #elif defined(__DARWIN__)
85 // The dlopen port is a port from dl_next.xs by Anno Siegel.
86 // dl_next.xs is itself a port from dl_dlopen.xs by Paul Marquess.
87 // The method used here is just to supply the sun style dlopen etc.
88 // functions in terms of Darwin NS*.
90 void *dlopen(const char *path
, int mode
); // mode is ignored
91 void *dlsym(void *handle
, const char *symbol
);
92 int dlclose(void *handle
);
93 const char *dlerror(void);
95 #define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
96 #define wxDllGetSymbol(handle, name) dlsym(handle, name)
97 #define wxDllClose dlclose
99 #elif defined(__WINDOWS__)
101 // using LoadLibraryEx under Win32 to avoid name clash with LoadLibrary
106 #define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
108 #define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
112 #define wxDllOpen(lib) ::LoadLibrary(lib)
114 #define wxDllGetSymbol(handle, name) ::GetProcAddress(handle, name)
115 #define wxDllClose ::FreeLibrary
117 #elif defined(__WXMAC__)
118 #define wxDllClose(handle) CloseConnection(&handle)
120 #error "Don't know how to load shared libraries on this platform."
124 // ============================================================================
126 // ============================================================================
128 // ---------------------------------------------------------------------------
129 // wxDllLoader (all these methods are static)
130 // ---------------------------------------------------------------------------
133 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
134 const wxString
wxDllLoader::ms_dllext( _T(".dll") );
135 #elif defined(__UNIX__)
136 #if defined(__HPUX__)
137 const wxString
wxDllLoader::ms_dllext( _T(".sl") );
139 const wxString
wxDllLoader::ms_dllext( _T(".so") );
143 wxDllType
wxDllLoader::GetProgramHandle()
145 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
146 // obtain handle for main program
147 return dlopen(NULL
, RTLD_NOW
/*RTLD_LAZY*/);
148 #elif defined (HAVE_SHL_LOAD)
149 // shl_findsymbol with NULL handle looks up in main program
152 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
157 wxDllType
wxDllLoader::LoadLibrary(const wxString
&name
)
159 wxString
libname( name
+ wxDllLoader::GetDllExt() );
162 #if defined(__WXMAC__) && !defined(__UNIX__)
167 wxMacFilename2FSSpec( libname
, &myFSSpec
);
169 if( GetDiskFragment( &myFSSpec
,
176 myErrName
) != noErr
)
179 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
185 #elif defined(__WXPM__) || defined(__EMX__)
186 char zError
[256] = "";
187 wxDllOpen(zError
, libname
, handle
);
189 handle
= wxDllOpen(libname
);
193 wxString
msg(_("Failed to load shared library '%s'"));
195 const wxChar
*err
= dlerror();
197 wxLogError( msg
, err
);
199 wxLogSysError( msg
, libname
.c_str() );
205 void wxDllLoader::UnloadLibrary(wxDllType handle
)
210 void *wxDllLoader::GetSymbol(wxDllType dllHandle
, const wxString
&name
, bool *success
)
215 #if defined(__WXMAC__) && !defined(__UNIX__)
217 CFragSymbolClass symClass
;
220 c2pstrcpy( (StringPtr
) symName
, name
);
222 strcpy( (char *) symName
, name
);
223 c2pstr( (char *) symName
);
225 if( FindSymbol( dllHandle
, symName
, &symAddress
, &symClass
) == noErr
)
226 symbol
= (void *)symAddress
;
228 #elif defined(__WXPM__) || defined(__EMX__)
229 wxDllGetSymbol(dllHandle
, symbol
);
232 // mb_str() is necessary in Unicode build
233 symbol
= wxDllGetSymbol(dllHandle
, name
.mb_str());
238 wxString
msg(_("wxDllLoader failed to GetSymbol '%s'"));
240 const wxChar
*err
= dlerror();
244 wxLogError( msg
, err
);
248 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
259 // ---------------------------------------------------------------------------
261 // ---------------------------------------------------------------------------
264 wxDLImports
wxDLManifestEntry::ms_classes(wxKEY_STRING
);
266 wxDLManifestEntry::wxDLManifestEntry( const wxString
&libname
)
267 : m_before(wxClassInfo::sm_first
)
268 , m_handle(wxDllLoader::LoadLibrary( libname
))
269 , m_after(wxClassInfo::sm_first
)
279 --m_linkcount
; // Flag us for deletion
282 wxDLManifestEntry::~wxDLManifestEntry()
288 wxDllLoader::UnloadLibrary(m_handle
);
292 bool wxDLManifestEntry::UnrefLib()
294 wxASSERT_MSG( m_objcount
== 0, _T("Library unloaded before all objects were destroyed") );
295 if( m_linkcount
== 0 || --m_linkcount
== 0 )
303 // ------------------------
305 // ------------------------
307 void wxDLManifestEntry::UpdateClassInfo()
310 wxHashTable
*t
= wxClassInfo::sm_classTable
;
312 // FIXME: Below is simply a cut and paste specialisation of
313 // wxClassInfo::InitializeClasses. Once this stabilises,
314 // the two should probably be merged.
316 // Actually it's becoming questionable whether we should merge
317 // this info with the main ClassInfo tables since we can nearly
318 // handle this completely internally now and it does expose
319 // certain (minimal % user_stupidy) risks.
321 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
323 if( info
->m_className
)
325 if( t
->Get(info
->m_className
) == 0 )
326 t
->Put(info
->m_className
, (wxObject
*)info
);
328 // Hash all the class names into a local table too so
329 // we can quickly find the entry they correspond to.
331 if( ms_classes
.Get(info
->m_className
) == 0 )
332 ms_classes
.Put(info
->m_className
, (wxObject
*) this);
336 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
338 if( info
->m_baseClassName1
)
339 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
340 if( info
->m_baseClassName2
)
341 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
345 void wxDLManifestEntry::RestoreClassInfo()
349 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
351 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
352 ms_classes
.Delete(info
->m_className
);
355 if( wxClassInfo::sm_first
== m_after
)
356 wxClassInfo::sm_first
= m_before
;
359 info
= wxClassInfo::sm_first
;
360 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
362 wxASSERT_MSG( info
, _T("ClassInfo from wxDynamicLibrary not found on purge"))
364 info
->m_next
= m_before
;
368 void wxDLManifestEntry::RegisterModules()
370 // Plugin libraries might have wxModules, Register and initialise them if
373 // Note that these classes are NOT included in the reference counting since
374 // it's implicit that they will be unloaded if and when the last handle to
375 // the library is. We do have to keep a copy of the module's pointer
376 // though, as there is currently no way to Unregister it without it.
378 wxASSERT_MSG( m_linkcount
== 1,
379 _T("RegisterModules should only be called for the first load") );
381 for(wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
383 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
385 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
387 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
389 m_wxmodules
.Append(m
);
390 wxModule::RegisterModule(m
);
394 // FIXME: Likewise this is (well was) very similar to InitializeModules()
396 for(wxModuleList::Node
*node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
398 if( !node
->GetData()->Init() )
400 wxLogDebug(_T("wxModule::Init() failed for wxDynamicLibrary"));
402 // XXX: Watch this, a different hash implementation might break it,
403 // a good hash implementation would let us fix it though.
405 // The name of the game is to remove any uninitialised modules and
406 // let the dtor Exit the rest on shutdown, (which we'll initiate
409 wxModuleList::Node
*oldNode
= 0;
411 node
= node
->GetNext();
413 wxModule::UnregisterModule( node
->GetData() );
417 --m_linkcount
; // Flag us for deletion
423 void wxDLManifestEntry::UnregisterModules()
425 wxModuleList::Node
*node
;
427 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
428 node
->GetData()->Exit();
430 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
431 wxModule::UnregisterModule( node
->GetData() );
433 m_wxmodules
.DeleteContents(TRUE
);
437 // ---------------------------------------------------------------------------
439 // ---------------------------------------------------------------------------
441 wxDLManifest
wxDynamicLibrary::ms_manifest(wxKEY_STRING
);
443 // ------------------------
445 // ------------------------
447 wxDLManifestEntry
*wxDynamicLibrary::Link(const wxString
&libname
)
449 wxDLManifestEntry
*entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
457 entry
= new wxDLManifestEntry( libname
);
459 if( entry
->IsLoaded() )
461 ms_manifest
.Put(libname
, (wxObject
*) entry
);
465 wxCHECK_MSG( entry
->UnrefLib(), 0,
466 _T("Currently linked library is, ..not loaded??") );
473 bool wxDynamicLibrary::Unlink(const wxString
&libname
)
475 wxDLManifestEntry
*entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
478 return entry
->UnrefLib();
480 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname
.c_str());
484 // ------------------------
485 // Class implementation
486 // ------------------------
488 wxDynamicLibrary::wxDynamicLibrary(const wxString
&libname
)
490 m_entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
498 m_entry
= new wxDLManifestEntry( libname
);
499 ms_manifest
.Put(libname
, (wxObject
*) m_entry
);
501 wxASSERT_MSG( m_entry
!= 0, _T("Failed to create manifest entry") );
505 wxDynamicLibrary::~wxDynamicLibrary()
508 ms_manifest
.BeginFind();
510 // It's either this or store the name of the lib just to do this.
512 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
513 if( (wxDLManifestEntry
*)node
->GetData() == m_entry
)
516 if( m_entry
&& m_entry
->UnrefLib() )
522 // ---------------------------------------------------------------------------
523 // For Darwin/Mac OS X
524 // supply the sun style dlopen functions in terms of Darwin NS*
525 // ---------------------------------------------------------------------------
528 #import <mach-o/dyld.h>
536 static char dl_last_error
[1024];
539 void TranslateError(const char *path
, enum dyldErrorSource type
, int number
)
542 static char *OFIErrorStrings
[] =
544 "%s(%d): Object Image Load Failure\n",
545 "%s(%d): Object Image Load Success\n",
546 "%s(%d): Not an recognisable object file\n",
547 "%s(%d): No valid architecture\n",
548 "%s(%d): Object image has an invalid format\n",
549 "%s(%d): Invalid access (permissions?)\n",
550 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
552 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
558 if (index
> NUM_OFI_ERRORS
- 1) {
559 index
= NUM_OFI_ERRORS
- 1;
561 sprintf(dl_last_error
, OFIErrorStrings
[index
], path
, number
);
565 sprintf(dl_last_error
, "%s(%d): Totally unknown error type %d\n",
571 const char *dlerror()
573 return dl_last_error
;
575 void *dlopen(const char *path
, int mode
/* mode is ignored */)
578 NSObjectFileImage ofile
;
581 dyld_result
= NSCreateObjectFileImageFromFile(path
, &ofile
);
582 if(dyld_result
!= NSObjectFileImageSuccess
)
584 TranslateError(path
, OFImage
, dyld_result
);
588 // NSLinkModule will cause the run to abort on any link error's
589 // not very friendly but the error recovery functionality is limited.
590 handle
= NSLinkModule(ofile
, path
, TRUE
);
596 int dlclose(void *handle
) /* stub only */
601 void *dlsym(void *handle
, const char *symbol
)
603 return NSIsSymbolNameDefined(symbol
)
604 ? NSAddressOfSymbol( NSLookupAndBindSymbol(symbol
) )
609 #endif // wxUSE_DYNAMIC_LOADER