]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynload.cpp
removed obsolete docs
[wxWidgets.git] / src / common / dynload.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dynload.cpp
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)
6 // Modified by:
7 // Created: 03/12/01
8 // RCS-ID: $Id$
9 // Copyright: (c) 2001 Ron Lee <ron@debian.org>
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
12
13 #ifdef __GNUG__
14 #pragma implementation "dynload.h"
15 #endif
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_DYNAMIC_LOADER
28
29 #ifdef __WINDOWS__
30 #include "wx/msw/private.h"
31 #endif
32
33 #ifndef WX_PRECOMP
34 #include "wx/log.h"
35 #include "wx/intl.h"
36 #endif
37
38 #include "wx/dynload.h"
39
40 // ----------------------------------------------------------------------------
41 // conditional compilation
42 // ----------------------------------------------------------------------------
43
44 #if defined(__WXPM__) || defined(__EMX__)
45 #define INCL_DOS
46 #include <os2.h>
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)
50
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.
57
58 #ifdef __VMS
59 #define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
60
61 #elif defined( __osf__ )
62 #define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY)
63
64 #else
65 #define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY | RTLD_GLOBAL)
66 #endif // __VMS
67
68 #define wxDllGetSymbol(handle, name) dlsym(handle, name)
69 #define wxDllClose dlclose
70
71 #elif defined(HAVE_SHL_LOAD)
72 #define wxDllOpen(lib) shl_load(lib.fn_str(), BIND_DEFERRED, 0)
73 #define wxDllClose shl_unload
74
75 static inline void *wxDllGetSymbol(shl_t handle, const wxString& name)
76 {
77 void *sym;
78 return ( shl_findsym(&handle, name.mb_str(), TYPE_UNDEFINED, &sym) == 0 )
79 ? sym : 0;
80 }
81
82 #elif defined(__DARWIN__)
83
84 // Porting notes:
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*.
89
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);
94
95 #define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
96 #define wxDllGetSymbol(handle, name) dlsym(handle, name)
97 #define wxDllClose dlclose
98
99 #elif defined(__WINDOWS__)
100
101 // using LoadLibraryEx under Win32 to avoid name clash with LoadLibrary
102
103 #ifdef __WIN32__
104
105 #ifdef _UNICODE
106 #define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
107 #else
108 #define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
109 #endif
110
111 #else // Win16
112 #define wxDllOpen(lib) ::LoadLibrary(lib)
113 #endif // Win32/16
114 #define wxDllGetSymbol(handle, name) ::GetProcAddress(handle, name)
115 #define wxDllClose ::FreeLibrary
116
117 #elif defined(__WXMAC__)
118 #define wxDllClose(handle) CloseConnection(&handle)
119 #else
120 #error "Don't know how to load shared libraries on this platform."
121 #endif
122
123
124 // ============================================================================
125 // implementation
126 // ============================================================================
127
128 // ---------------------------------------------------------------------------
129 // wxDllLoader (all these methods are static)
130 // ---------------------------------------------------------------------------
131
132
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") );
138 #else
139 const wxString wxDllLoader::ms_dllext( _T(".so") );
140 #endif
141 #endif
142
143 wxDllType wxDllLoader::GetProgramHandle()
144 {
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
150 return 0;
151 #else
152 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
153 return 0;
154 #endif
155 }
156
157 wxDllType wxDllLoader::LoadLibrary(const wxString &name)
158 {
159 wxString libname( name + wxDllLoader::GetDllExt() );
160 wxDllType handle;
161
162 #if defined(__WXMAC__) && !defined(__UNIX__)
163 FSSpec myFSSpec;
164 Ptr myMainAddr;
165 Str255 myErrName;
166
167 wxMacFilename2FSSpec( libname , &myFSSpec );
168
169 if( GetDiskFragment( &myFSSpec,
170 0,
171 kCFragGoesToEOF,
172 "\p",
173 kPrivateCFragCopy,
174 &handle,
175 &myMainAddr,
176 myErrName ) != noErr )
177 {
178 p2cstr( myErrName );
179 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
180 libname.c_str(),
181 (char*)myErrName );
182 handle = 0;
183 }
184
185 #elif defined(__WXPM__) || defined(__EMX__)
186 char zError[256] = "";
187 wxDllOpen(zError, libname, handle);
188 #else
189 handle = wxDllOpen(libname);
190 #endif
191 if ( !handle )
192 {
193 wxString msg(_("Failed to load shared library '%s'"));
194 #ifdef HAVE_DLERROR
195 const wxChar *err = dlerror();
196 if( err )
197 wxLogError( msg, err );
198 #else
199 wxLogSysError( msg, libname.c_str() );
200 #endif
201 }
202 return handle;
203 }
204
205 void wxDllLoader::UnloadLibrary(wxDllType handle)
206 {
207 wxDllClose(handle);
208 }
209
210 void *wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name, bool *success)
211 {
212 bool failed = FALSE;
213 void *symbol = 0;
214
215 #if defined(__WXMAC__) && !defined(__UNIX__)
216 Ptr symAddress;
217 CFragSymbolClass symClass;
218 Str255 symName;
219 #if TARGET_CARBON
220 c2pstrcpy( (StringPtr) symName, name );
221 #else
222 strcpy( (char *) symName, name );
223 c2pstr( (char *) symName );
224 #endif
225 if( FindSymbol( dllHandle, symName, &symAddress, &symClass ) == noErr )
226 symbol = (void *)symAddress;
227
228 #elif defined(__WXPM__) || defined(__EMX__)
229 wxDllGetSymbol(dllHandle, symbol);
230 #else
231
232 // mb_str() is necessary in Unicode build
233 symbol = wxDllGetSymbol(dllHandle, name.mb_str());
234 #endif
235
236 if ( !symbol )
237 {
238 wxString msg(_("wxDllLoader failed to GetSymbol '%s'"));
239 #ifdef HAVE_DLERROR
240 const wxChar *err = dlerror();
241 if( err )
242 {
243 failed = TRUE;
244 wxLogError( msg, err );
245 }
246 #else
247 failed = TRUE;
248 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
249 name.c_str());
250 #endif
251 }
252 if( success )
253 *success = !failed;
254
255 return symbol;
256 }
257
258
259 // ---------------------------------------------------------------------------
260 // wxDLManifestEntry
261 // ---------------------------------------------------------------------------
262
263
264 wxDLImports wxDLManifestEntry::ms_classes(wxKEY_STRING);
265
266 wxDLManifestEntry::wxDLManifestEntry( const wxString &libname )
267 : m_before(wxClassInfo::sm_first)
268 , m_handle(wxDllLoader::LoadLibrary( libname ))
269 , m_after(wxClassInfo::sm_first)
270 , m_linkcount(1)
271 , m_objcount(0)
272 {
273 if( m_handle != 0 )
274 {
275 UpdateClassInfo();
276 RegisterModules();
277 }
278 else
279 --m_linkcount; // Flag us for deletion
280 }
281
282 wxDLManifestEntry::~wxDLManifestEntry()
283 {
284 if( m_handle != 0 )
285 {
286 UnregisterModules();
287 RestoreClassInfo();
288 wxDllLoader::UnloadLibrary(m_handle);
289 }
290 }
291
292 bool wxDLManifestEntry::UnrefLib()
293 {
294 wxASSERT_MSG( m_objcount == 0, _T("Library unloaded before all objects were destroyed") );
295 if( m_linkcount == 0 || --m_linkcount == 0 )
296 {
297 delete this;
298 return TRUE;
299 }
300 return FALSE;
301 }
302
303 // ------------------------
304 // Private methods
305 // ------------------------
306
307 void wxDLManifestEntry::UpdateClassInfo()
308 {
309 wxClassInfo *info;
310 wxHashTable *t = wxClassInfo::sm_classTable;
311
312 // FIXME: Below is simply a cut and paste specialisation of
313 // wxClassInfo::InitializeClasses. Once this stabilises,
314 // the two should probably be merged.
315 //
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.
320
321 for(info = m_after; info != m_before; info = info->m_next)
322 {
323 if( info->m_className )
324 {
325 if( t->Get(info->m_className) == 0 )
326 t->Put(info->m_className, (wxObject *)info);
327
328 // Hash all the class names into a local table too so
329 // we can quickly find the entry they correspond to.
330
331 if( ms_classes.Get(info->m_className) == 0 )
332 ms_classes.Put(info->m_className, (wxObject *) this);
333 }
334 }
335
336 for(info = m_after; info != m_before; info = info->m_next)
337 {
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);
342 }
343 }
344
345 void wxDLManifestEntry::RestoreClassInfo()
346 {
347 wxClassInfo *info;
348
349 for(info = m_after; info != m_before; info = info->m_next)
350 {
351 wxClassInfo::sm_classTable->Delete(info->m_className);
352 ms_classes.Delete(info->m_className);
353 }
354
355 if( wxClassInfo::sm_first == m_after )
356 wxClassInfo::sm_first = m_before;
357 else
358 {
359 info = wxClassInfo::sm_first;
360 while( info->m_next && info->m_next != m_after ) info = info->m_next;
361
362 wxASSERT_MSG( info, _T("ClassInfo from wxDynamicLibrary not found on purge"))
363
364 info->m_next = m_before;
365 }
366 }
367
368 void wxDLManifestEntry::RegisterModules()
369 {
370 // Plugin libraries might have wxModules, Register and initialise them if
371 // they do.
372 //
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.
377
378 wxASSERT_MSG( m_linkcount == 1,
379 _T("RegisterModules should only be called for the first load") );
380
381 for(wxClassInfo *info = m_after; info != m_before; info = info->m_next)
382 {
383 if( info->IsKindOf(CLASSINFO(wxModule)) )
384 {
385 wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
386
387 wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") );
388
389 m_wxmodules.Append(m);
390 wxModule::RegisterModule(m);
391 }
392 }
393
394 // FIXME: Likewise this is (well was) very similar to InitializeModules()
395
396 for(wxModuleList::Node *node = m_wxmodules.GetFirst(); node; node->GetNext())
397 {
398 if( !node->GetData()->Init() )
399 {
400 wxLogDebug(_T("wxModule::Init() failed for wxDynamicLibrary"));
401
402 // XXX: Watch this, a different hash implementation might break it,
403 // a good hash implementation would let us fix it though.
404
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
407 // shortly).
408
409 wxModuleList::Node *oldNode = 0;
410 do {
411 node = node->GetNext();
412 delete oldNode;
413 wxModule::UnregisterModule( node->GetData() );
414 oldNode = node;
415 } while( node );
416
417 --m_linkcount; // Flag us for deletion
418 break;
419 }
420 }
421 }
422
423 void wxDLManifestEntry::UnregisterModules()
424 {
425 wxModuleList::Node *node;
426
427 for(node = m_wxmodules.GetFirst(); node; node->GetNext())
428 node->GetData()->Exit();
429
430 for(node = m_wxmodules.GetFirst(); node; node->GetNext())
431 wxModule::UnregisterModule( node->GetData() );
432
433 m_wxmodules.DeleteContents(TRUE);
434 }
435
436
437 // ---------------------------------------------------------------------------
438 // wxDynamicLibrary
439 // ---------------------------------------------------------------------------
440
441 wxDLManifest wxDynamicLibrary::ms_manifest(wxKEY_STRING);
442
443 // ------------------------
444 // Static accessors
445 // ------------------------
446
447 wxDLManifestEntry *wxDynamicLibrary::Link(const wxString &libname)
448 {
449 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
450
451 if( entry )
452 {
453 entry->RefLib();
454 }
455 else
456 {
457 entry = new wxDLManifestEntry( libname );
458
459 if( entry->IsLoaded() )
460 {
461 ms_manifest.Put(libname, (wxObject*) entry);
462 }
463 else
464 {
465 wxCHECK_MSG( entry->UnrefLib(), 0,
466 _T("Currently linked library is, ..not loaded??") );
467 entry = 0;
468 }
469 }
470 return entry;
471 }
472
473 bool wxDynamicLibrary::Unlink(const wxString &libname)
474 {
475 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
476
477 if( entry )
478 return entry->UnrefLib();
479
480 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname.c_str());
481 return 0;
482 }
483
484 // ------------------------
485 // Class implementation
486 // ------------------------
487
488 wxDynamicLibrary::wxDynamicLibrary(const wxString &libname)
489 {
490 m_entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
491
492 if( m_entry != 0 )
493 {
494 m_entry->RefLib();
495 }
496 else
497 {
498 m_entry = new wxDLManifestEntry( libname );
499 ms_manifest.Put(libname, (wxObject*) m_entry);
500
501 wxASSERT_MSG( m_entry != 0, _T("Failed to create manifest entry") );
502 }
503 }
504
505 wxDynamicLibrary::~wxDynamicLibrary()
506 {
507 wxNode *node;
508 ms_manifest.BeginFind();
509
510 // It's either this or store the name of the lib just to do this.
511
512 for(node = ms_manifest.Next(); node; node = ms_manifest.Next())
513 if( (wxDLManifestEntry*)node->GetData() == m_entry )
514 break;
515
516 if( m_entry && m_entry->UnrefLib() )
517 delete node;
518 }
519
520
521 #ifdef __DARWIN__
522 // ---------------------------------------------------------------------------
523 // For Darwin/Mac OS X
524 // supply the sun style dlopen functions in terms of Darwin NS*
525 // ---------------------------------------------------------------------------
526
527 extern "C" {
528 #import <mach-o/dyld.h>
529 };
530
531 enum dyldErrorSource
532 {
533 OFImage,
534 };
535
536 static char dl_last_error[1024];
537
538 static
539 void TranslateError(const char *path, enum dyldErrorSource type, int number)
540 {
541 unsigned int index;
542 static char *OFIErrorStrings[] =
543 {
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",
551 };
552 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
553
554 switch (type)
555 {
556 case OFImage:
557 index = number;
558 if (index > NUM_OFI_ERRORS - 1) {
559 index = NUM_OFI_ERRORS - 1;
560 }
561 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
562 break;
563
564 default:
565 sprintf(dl_last_error, "%s(%d): Totally unknown error type %d\n",
566 path, number, type);
567 break;
568 }
569 }
570
571 const char *dlerror()
572 {
573 return dl_last_error;
574 }
575 void *dlopen(const char *path, int mode /* mode is ignored */)
576 {
577 int dyld_result;
578 NSObjectFileImage ofile;
579 NSModule handle = 0;
580
581 dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
582 if(dyld_result != NSObjectFileImageSuccess)
583 {
584 TranslateError(path, OFImage, dyld_result);
585 }
586 else
587 {
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);
591 }
592
593 return handle;
594 }
595
596 int dlclose(void *handle) /* stub only */
597 {
598 return 0;
599 }
600
601 void *dlsym(void *handle, const char *symbol)
602 {
603 return NSIsSymbolNameDefined(symbol)
604 ? NSAddressOfSymbol( NSLookupAndBindSymbol(symbol) )
605 : 0 ;
606 }
607
608 #endif // __DARWIN__
609 #endif // wxUSE_DYNAMIC_LOADER
610
611 // vi:sts=4:sw=4:et