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 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 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
)
278 --m_count
; // Flag us for deletion
281 wxDLManifestEntry::~wxDLManifestEntry()
286 wxDllLoader::UnloadLibrary(m_handle
);
290 // ------------------------
292 // ------------------------
294 void wxDLManifestEntry::UpdateClassInfo()
297 wxHashTable
*t
= wxClassInfo::sm_classTable
;
299 // FIXME: Below is simply a cut and paste specialisation of
300 // wxClassInfo::InitializeClasses. Once this stabilises,
301 // the two should probably be merged.
303 // Actually it's becoming questionable whether we should merge
304 // this info with the main ClassInfo tables since we can nearly
305 // handle this completely internally now and it does expose
306 // certain (minimal % user_stupidy) risks.
308 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
310 if( info
->m_className
)
312 if( t
->Get(info
->m_className
) == 0 )
313 t
->Put(info
->m_className
, (wxObject
*)info
);
315 // Hash all the class names into a local table too so
316 // we can quickly find the entry they correspond to.
318 if( ms_classes
.Get(info
->m_className
) == 0 )
319 ms_classes
.Put(info
->m_className
, (wxObject
*) this);
323 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
325 if( info
->m_baseClassName1
)
326 info
->m_baseInfo1
= (wxClassInfo
*)t
->Get(info
->m_baseClassName1
);
327 if( info
->m_baseClassName2
)
328 info
->m_baseInfo2
= (wxClassInfo
*)t
->Get(info
->m_baseClassName2
);
332 void wxDLManifestEntry::RestoreClassInfo()
336 for(info
= m_after
; info
!= m_before
; info
= info
->m_next
)
338 wxClassInfo::sm_classTable
->Delete(info
->m_className
);
339 ms_classes
.Delete(info
->m_className
);
342 if( wxClassInfo::sm_first
== m_after
)
343 wxClassInfo::sm_first
= m_before
;
346 info
= wxClassInfo::sm_first
;
347 while( info
->m_next
&& info
->m_next
!= m_after
) info
= info
->m_next
;
349 wxASSERT_MSG( info
, _T("ClassInfo from wxDynamicLibrary not found on purge"))
351 info
->m_next
= m_before
;
355 void wxDLManifestEntry::RegisterModules()
357 // Plugin libraries might have wxModules, Register and initialise them if
360 // Note that these classes are NOT included in the reference counting since
361 // it's implicit that they will be unloaded if and when the last handle to
362 // the library is. We do have to keep a copy of the module's pointer
363 // though, as there is currently no way to Unregister it without it.
365 wxASSERT_MSG( m_count
== 1,
366 _T("RegisterModules should only be called for the first load") );
368 for(wxClassInfo
*info
= m_after
; info
!= m_before
; info
= info
->m_next
)
370 if( info
->IsKindOf(CLASSINFO(wxModule
)) )
372 wxModule
*m
= wxDynamicCast(info
->CreateObject(), wxModule
);
374 wxASSERT_MSG( m
, _T("wxDynamicCast of wxModule failed") );
376 m_wxmodules
.Append(m
);
377 wxModule::RegisterModule(m
);
381 // FIXME: Likewise this is (well was) very similar to InitializeModules()
383 for(wxModuleList::Node
*node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
385 if( !node
->GetData()->Init() )
387 wxLogDebug(_T("wxModule::Init() failed for wxDynamicLibrary"));
389 // XXX: Watch this, a different hash implementation might break it,
390 // a good hash implementation would let us fix it though.
392 // The name of the game is to remove any uninitialised modules and
393 // let the dtor Exit the rest on shutdown, (which we'll initiate
396 wxModuleList::Node
*oldNode
= 0;
398 node
= node
->GetNext();
400 wxModule::UnregisterModule( node
->GetData() );
404 --m_count
; // Flag us for deletion
410 void wxDLManifestEntry::UnregisterModules()
412 wxModuleList::Node
*node
;
414 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
415 node
->GetData()->Exit();
417 for(node
= m_wxmodules
.GetFirst(); node
; node
->GetNext())
418 wxModule::UnregisterModule( node
->GetData() );
420 m_wxmodules
.DeleteContents(TRUE
);
424 // ---------------------------------------------------------------------------
426 // ---------------------------------------------------------------------------
428 wxDLManifest
wxDynamicLibrary::ms_manifest(wxKEY_STRING
);
430 // ------------------------
432 // ------------------------
434 wxDLManifestEntry
*wxDynamicLibrary::Link(const wxString
&libname
)
436 wxDLManifestEntry
*entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
444 entry
= new wxDLManifestEntry( libname
);
446 if( entry
->IsLoaded() )
448 ms_manifest
.Put(libname
, (wxObject
*) entry
);
452 wxCHECK_MSG( !entry
->Unref(), 0,
453 _T("Currently linked library is, ..not loaded??") );
460 bool wxDynamicLibrary::Unlink(const wxString
&libname
)
462 wxDLManifestEntry
*entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
465 return entry
->Unref();
467 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname
.c_str());
471 // ------------------------
472 // Class implementation
473 // ------------------------
475 wxDynamicLibrary::wxDynamicLibrary(const wxString
&libname
)
477 m_entry
= (wxDLManifestEntry
*) ms_manifest
.Get(libname
);
485 m_entry
= new wxDLManifestEntry( libname
);
486 ms_manifest
.Put(libname
, (wxObject
*) m_entry
);
488 wxASSERT_MSG( m_entry
!= 0, _T("Failed to create manifest entry") );
492 wxDynamicLibrary::~wxDynamicLibrary()
495 ms_manifest
.BeginFind();
497 // It's either this or store the name of the lib just to do this.
499 for(node
= ms_manifest
.Next(); node
; node
= ms_manifest
.Next())
500 if( (wxDLManifestEntry
*)node
->GetData() == m_entry
)
503 if( m_entry
&& m_entry
->Unref() )
509 // ---------------------------------------------------------------------------
510 // For Darwin/Mac OS X
511 // supply the sun style dlopen functions in terms of Darwin NS*
512 // ---------------------------------------------------------------------------
515 #import <mach-o/dyld.h>
523 static char dl_last_error
[1024];
526 void TranslateError(const char *path
, enum dyldErrorSource type
, int number
)
529 static char *OFIErrorStrings
[] =
531 "%s(%d): Object Image Load Failure\n",
532 "%s(%d): Object Image Load Success\n",
533 "%s(%d): Not an recognisable object file\n",
534 "%s(%d): No valid architecture\n",
535 "%s(%d): Object image has an invalid format\n",
536 "%s(%d): Invalid access (permissions?)\n",
537 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
539 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
545 if (index
> NUM_OFI_ERRORS
- 1) {
546 index
= NUM_OFI_ERRORS
- 1;
548 sprintf(dl_last_error
, OFIErrorStrings
[index
], path
, number
);
552 sprintf(dl_last_error
, "%s(%d): Totally unknown error type %d\n",
558 const char *dlerror()
560 return dl_last_error
;
562 void *dlopen(const char *path
, int mode
/* mode is ignored */)
565 NSObjectFileImage ofile
;
568 dyld_result
= NSCreateObjectFileImageFromFile(path
, &ofile
);
569 if(dyld_result
!= NSObjectFileImageSuccess
)
571 TranslateError(path
, OFImage
, dyld_result
);
575 // NSLinkModule will cause the run to abort on any link error's
576 // not very friendly but the error recovery functionality is limited.
577 handle
= NSLinkModule(ofile
, path
, TRUE
);
583 int dlclose(void *handle
) /* stub only */
588 void *dlsym(void *handle
, const char *symbol
)
590 return NSIsSymbolNameDefined(symbol
)
591 ? NSAddressOfSymbol( NSLookupAndBindSymbol(symbol
) )
596 #endif // wxUSE_DYNAMIC_LOADER