]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynload.cpp
toplevel code transferred to wxTopLevelWindow
[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 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 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_count(1)
271 {
272 if( m_handle != 0 )
273 {
274 UpdateClassInfo();
275 RegisterModules();
276 }
277 else
278 --m_count; // Flag us for deletion
279 }
280
281 wxDLManifestEntry::~wxDLManifestEntry()
282 {
283 UnregisterModules();
284 RestoreClassInfo();
285
286 wxDllLoader::UnloadLibrary(m_handle);
287 }
288
289
290 // ------------------------
291 // Private methods
292 // ------------------------
293
294 void wxDLManifestEntry::UpdateClassInfo()
295 {
296 wxClassInfo *info;
297 wxHashTable *t = wxClassInfo::sm_classTable;
298
299 // FIXME: Below is simply a cut and paste specialisation of
300 // wxClassInfo::InitializeClasses. Once this stabilises,
301 // the two should probably be merged.
302 //
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.
307
308 for(info = m_after; info != m_before; info = info->m_next)
309 {
310 if( info->m_className )
311 {
312 if( t->Get(info->m_className) == 0 )
313 t->Put(info->m_className, (wxObject *)info);
314
315 // Hash all the class names into a local table too so
316 // we can quickly find the entry they correspond to.
317
318 if( ms_classes.Get(info->m_className) == 0 )
319 ms_classes.Put(info->m_className, (wxObject *) this);
320 }
321 }
322
323 for(info = m_after; info != m_before; info = info->m_next)
324 {
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);
329 }
330 }
331
332 void wxDLManifestEntry::RestoreClassInfo()
333 {
334 wxClassInfo *info;
335
336 for(info = m_after; info != m_before; info = info->m_next)
337 {
338 wxClassInfo::sm_classTable->Delete(info->m_className);
339 ms_classes.Delete(info->m_className);
340 }
341
342 if( wxClassInfo::sm_first == m_after )
343 wxClassInfo::sm_first = m_before;
344 else
345 {
346 info = wxClassInfo::sm_first;
347 while( info->m_next && info->m_next != m_after ) info = info->m_next;
348
349 wxASSERT_MSG( info, _T("ClassInfo from wxDynamicLibrary not found on purge"))
350
351 info->m_next = m_before;
352 }
353 }
354
355 void wxDLManifestEntry::RegisterModules()
356 {
357 // Plugin libraries might have wxModules, Register and initialise them if
358 // they do.
359 //
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.
364
365 wxASSERT_MSG( m_count == 1,
366 _T("RegisterModules should only be called for the first load") );
367
368 for(wxClassInfo *info = m_after; info != m_before; info = info->m_next)
369 {
370 if( info->IsKindOf(CLASSINFO(wxModule)) )
371 {
372 wxModule *m = wxDynamicCast(info->CreateObject(), wxModule);
373
374 wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") );
375
376 m_wxmodules.Append(m);
377 wxModule::RegisterModule(m);
378 }
379 }
380
381 // FIXME: Likewise this is (well was) very similar to InitializeModules()
382
383 for(wxModuleList::Node *node = m_wxmodules.GetFirst(); node; node->GetNext())
384 {
385 if( !node->GetData()->Init() )
386 {
387 wxLogDebug(_T("wxModule::Init() failed for wxDynamicLibrary"));
388
389 // XXX: Watch this, a different hash implementation might break it,
390 // a good hash implementation would let us fix it though.
391
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
394 // shortly).
395
396 wxModuleList::Node *oldNode = 0;
397 do {
398 node = node->GetNext();
399 delete oldNode;
400 wxModule::UnregisterModule( node->GetData() );
401 oldNode = node;
402 } while( node );
403
404 --m_count; // Flag us for deletion
405 break;
406 }
407 }
408 }
409
410 void wxDLManifestEntry::UnregisterModules()
411 {
412 wxModuleList::Node *node;
413
414 for(node = m_wxmodules.GetFirst(); node; node->GetNext())
415 node->GetData()->Exit();
416
417 for(node = m_wxmodules.GetFirst(); node; node->GetNext())
418 wxModule::UnregisterModule( node->GetData() );
419
420 m_wxmodules.DeleteContents(TRUE);
421 }
422
423
424 // ---------------------------------------------------------------------------
425 // wxDynamicLibrary
426 // ---------------------------------------------------------------------------
427
428 wxDLManifest wxDynamicLibrary::ms_manifest(wxKEY_STRING);
429
430 // ------------------------
431 // Static accessors
432 // ------------------------
433
434 wxDLManifestEntry *wxDynamicLibrary::Link(const wxString &libname)
435 {
436 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
437
438 if( entry )
439 {
440 entry->Ref();
441 }
442 else
443 {
444 entry = new wxDLManifestEntry( libname );
445
446 if( entry->IsLoaded() )
447 {
448 ms_manifest.Put(libname, (wxObject*) entry);
449 }
450 else
451 {
452 wxCHECK_MSG( !entry->Unref(), 0,
453 _T("Currently linked library is, ..not loaded??") );
454 entry = 0;
455 }
456 }
457 return entry;
458 }
459
460 bool wxDynamicLibrary::Unlink(const wxString &libname)
461 {
462 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
463
464 if( entry )
465 return entry->Unref();
466
467 wxLogDebug(_T("Attempt to Unlink library '%s' (which is not linked)."), libname.c_str());
468 return 0;
469 }
470
471 // ------------------------
472 // Class implementation
473 // ------------------------
474
475 wxDynamicLibrary::wxDynamicLibrary(const wxString &libname)
476 {
477 m_entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
478
479 if( m_entry != 0 )
480 {
481 m_entry->Ref();
482 }
483 else
484 {
485 m_entry = new wxDLManifestEntry( libname );
486 ms_manifest.Put(libname, (wxObject*) m_entry);
487
488 wxASSERT_MSG( m_entry != 0, _T("Failed to create manifest entry") );
489 }
490 }
491
492 wxDynamicLibrary::~wxDynamicLibrary()
493 {
494 wxNode *node;
495 ms_manifest.BeginFind();
496
497 // It's either this or store the name of the lib just to do this.
498
499 for(node = ms_manifest.Next(); node; node = ms_manifest.Next())
500 if( (wxDLManifestEntry*)node->GetData() == m_entry )
501 break;
502
503 if( m_entry && m_entry->Unref() )
504 delete node;
505 }
506
507
508 #ifdef __DARWIN__
509 // ---------------------------------------------------------------------------
510 // For Darwin/Mac OS X
511 // supply the sun style dlopen functions in terms of Darwin NS*
512 // ---------------------------------------------------------------------------
513
514 extern "C" {
515 #import <mach-o/dyld.h>
516 };
517
518 enum dyldErrorSource
519 {
520 OFImage,
521 };
522
523 static char dl_last_error[1024];
524
525 static
526 void TranslateError(const char *path, enum dyldErrorSource type, int number)
527 {
528 unsigned int index;
529 static char *OFIErrorStrings[] =
530 {
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",
538 };
539 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
540
541 switch (type)
542 {
543 case OFImage:
544 index = number;
545 if (index > NUM_OFI_ERRORS - 1) {
546 index = NUM_OFI_ERRORS - 1;
547 }
548 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
549 break;
550
551 default:
552 sprintf(dl_last_error, "%s(%d): Totally unknown error type %d\n",
553 path, number, type);
554 break;
555 }
556 }
557
558 const char *dlerror()
559 {
560 return dl_last_error;
561 }
562 void *dlopen(const char *path, int mode /* mode is ignored */)
563 {
564 int dyld_result;
565 NSObjectFileImage ofile;
566 NSModule handle = 0;
567
568 dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
569 if(dyld_result != NSObjectFileImageSuccess)
570 {
571 TranslateError(path, OFImage, dyld_result);
572 }
573 else
574 {
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);
578 }
579
580 return handle;
581 }
582
583 int dlclose(void *handle) /* stub only */
584 {
585 return 0;
586 }
587
588 void *dlsym(void *handle, const char *symbol)
589 {
590 return NSIsSymbolNameDefined(symbol)
591 ? NSAddressOfSymbol( NSLookupAndBindSymbol(symbol) )
592 : 0 ;
593 }
594
595 #endif // __DARWIN__
596 #endif // wxUSE_DYNAMIC_LOADER
597
598 // vi:sts=4:sw=4:et