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()
287 wxDllLoader::UnloadLibrary(m_handle
);
290 bool wxDLManifestEntry::UnrefLib()
292 wxASSERT_MSG( m_objcount
== 0, _T("Library unloaded before all objects were destroyed") );
293 if( m_linkcount
== 0 || --m_linkcount
== 0 )
301 // ------------------------
303 // ------------------------
305 void wxDLManifestEntry::UpdateClassInfo()
308 wxHashTable
*t
= wxClassInfo::sm_classTable
;
310 // FIXME: Below is simply a cut and paste specialisation of
311 // wxClassInfo::InitializeClasses. Once this stabilises,
312 // the two should probably be merged.
314 // Actually it's becoming questionable whether we should merge
315 // this info with the main ClassInfo tables since we can nearly
316 // handle this completely internally now and it does expose
317 // certain (minimal % user_stupidy) risks.
319 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
321 if( info
->m_className
)
323 if( t
->Get(info
->m_className
) == 0 )
324 t
->Put(info
->m_className
, (wxObject
*)info
);
326 // Hash all the class names into a local table too so
327 // we can quickly find the entry they correspond to.
329 if( ms_classes
.Get(info
->m_className
) == 0 )
330 ms_classes
.Put(info
->m_className
, (wxObject
*) this);
334 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
336 if( info
->m_baseClassName1
)
337 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
338 if( info
->m_baseClassName2
)
339 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
343 void wxDLManifestEntry::RestoreClassInfo()
347 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
349 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
350 ms_classes
.Delete(info
->m_className
);
353 if( wxClassInfo::sm_first
== m_after
)
354 wxClassInfo::sm_first
= m_before
;
357 info
= wxClassInfo::sm_first
;
358 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
360 wxASSERT_MSG( info
, _T("ClassInfo from wxDynamicLibrary not found on purge"))
362 info
->m_next
= m_before
;
366 void wxDLManifestEntry::RegisterModules()
368 // Plugin libraries might have wxModules, Register and initialise them if
371 // Note that these classes are NOT included in the reference counting since
372 // it's implicit that they will be unloaded if and when the last handle to
373 // the library is. We do have to keep a copy of the module's pointer
374 // though, as there is currently no way to Unregister it without it.
376 wxASSERT_MSG( m_linkcount
== 1,
377 _T("RegisterModules should only be called for the first load") );
379 for(wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
381 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
383 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
385 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
387 m_wxmodules
.Append(m
);
388 wxModule::RegisterModule(m
);
392 // FIXME: Likewise this is (well was) very similar to InitializeModules()
394 for(wxModuleList::Node
*node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
396 if( !node
->GetData()->Init() )
398 wxLogDebug(_T("wxModule::Init() failed for wxDynamicLibrary"));
400 // XXX: Watch this, a different hash implementation might break it,
401 // a good hash implementation would let us fix it though.
403 // The name of the game is to remove any uninitialised modules and
404 // let the dtor Exit the rest on shutdown, (which we'll initiate
407 wxModuleList::Node
*oldNode
= 0;
409 node
= node
->GetNext();
411 wxModule::UnregisterModule( node
->GetData() );
415 --m_linkcount
; // Flag us for deletion
421 void wxDLManifestEntry::UnregisterModules()
423 wxModuleList::Node
*node
;
425 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
426 node
->GetData()->Exit();
428 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
429 wxModule::UnregisterModule( node
->GetData() );
431 m_wxmodules
.DeleteContents(TRUE
);
435 // ---------------------------------------------------------------------------
437 // ---------------------------------------------------------------------------
439 wxDLManifest
wxDynamicLibrary::ms_manifest(wxKEY_STRING
);
441 // ------------------------
443 // ------------------------
445 wxDLManifestEntry
*wxDynamicLibrary::Link(const wxString
&libname
)
447 wxDLManifestEntry
*entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
455 entry
= new wxDLManifestEntry( libname
);
457 if( entry
->IsLoaded() )
459 ms_manifest
.Put(libname
, (wxObject
*) entry
);
463 wxCHECK_MSG( !entry
->UnrefLib(), 0,
464 _T("Currently linked library is, ..not loaded??") );
471 bool wxDynamicLibrary::Unlink(const wxString
&libname
)
473 wxDLManifestEntry
*entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
476 return entry
->UnrefLib();
478 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname
.c_str());
482 // ------------------------
483 // Class implementation
484 // ------------------------
486 wxDynamicLibrary::wxDynamicLibrary(const wxString
&libname
)
488 m_entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
496 m_entry
= new wxDLManifestEntry( libname
);
497 ms_manifest
.Put(libname
, (wxObject
*) m_entry
);
499 wxASSERT_MSG( m_entry
!= 0, _T("Failed to create manifest entry") );
503 wxDynamicLibrary::~wxDynamicLibrary()
506 ms_manifest
.BeginFind();
508 // It's either this or store the name of the lib just to do this.
510 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
511 if( (wxDLManifestEntry
*)node
->GetData() == m_entry
)
514 if( m_entry
&& m_entry
->UnrefLib() )
520 // ---------------------------------------------------------------------------
521 // For Darwin/Mac OS X
522 // supply the sun style dlopen functions in terms of Darwin NS*
523 // ---------------------------------------------------------------------------
526 #import <mach-o/dyld.h>
534 static char dl_last_error
[1024];
537 void TranslateError(const char *path
, enum dyldErrorSource type
, int number
)
540 static char *OFIErrorStrings
[] =
542 "%s(%d): Object Image Load Failure\n",
543 "%s(%d): Object Image Load Success\n",
544 "%s(%d): Not an recognisable object file\n",
545 "%s(%d): No valid architecture\n",
546 "%s(%d): Object image has an invalid format\n",
547 "%s(%d): Invalid access (permissions?)\n",
548 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
550 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
556 if (index
> NUM_OFI_ERRORS
- 1) {
557 index
= NUM_OFI_ERRORS
- 1;
559 sprintf(dl_last_error
, OFIErrorStrings
[index
], path
, number
);
563 sprintf(dl_last_error
, "%s(%d): Totally unknown error type %d\n",
569 const char *dlerror()
571 return dl_last_error
;
573 void *dlopen(const char *path
, int mode
/* mode is ignored */)
576 NSObjectFileImage ofile
;
579 dyld_result
= NSCreateObjectFileImageFromFile(path
, &ofile
);
580 if(dyld_result
!= NSObjectFileImageSuccess
)
582 TranslateError(path
, OFImage
, dyld_result
);
586 // NSLinkModule will cause the run to abort on any link error's
587 // not very friendly but the error recovery functionality is limited.
588 handle
= NSLinkModule(ofile
, path
, TRUE
);
594 int dlclose(void *handle
) /* stub only */
599 void *dlsym(void *handle
, const char *symbol
)
601 return NSIsSymbolNameDefined(symbol
)
602 ? NSAddressOfSymbol( NSLookupAndBindSymbol(symbol
) )
607 #endif // wxUSE_DYNAMIC_LOADER