]> git.saurik.com Git - wxWidgets.git/blame - src/common/dynload.cpp
corrected return value
[wxWidgets.git] / src / common / dynload.cpp
CommitLineData
0b9ab0bd
RL
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
75static 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
90void *dlopen(const char *path, int mode); // mode is ignored
91void *dlsym(void *handle, const char *symbol);
92int dlclose(void *handle);
93const 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__)
134const wxString wxDllLoader::ms_dllext( _T(".dll") );
135#elif defined(__UNIX__)
136#if defined(__HPUX__)
137const wxString wxDllLoader::ms_dllext( _T(".sl") );
138#else
139const wxString wxDllLoader::ms_dllext( _T(".so") );
140#endif
141#endif
142
143wxDllType 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
157wxDllType 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
a1706592 195 const wxChar *err = dlerror();
0b9ab0bd
RL
196 if( err )
197 wxLogError( msg, err );
198#else
199 wxLogSysError( msg, libname.c_str() );
200#endif
201 }
202 return handle;
203}
204
205void wxDllLoader::UnloadLibrary(wxDllType handle)
206{
207 wxDllClose(handle);
208}
209
210void *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
a1706592 240 const wxChar *err = dlerror();
0b9ab0bd
RL
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
264wxDLImports wxDLManifestEntry::ms_classes(wxKEY_STRING);
265
266wxDLManifestEntry::wxDLManifestEntry( const wxString &libname )
267 : m_before(wxClassInfo::sm_first)
268 , m_handle(wxDllLoader::LoadLibrary( libname ))
269 , m_after(wxClassInfo::sm_first)
7c1e2b44
RL
270 , m_linkcount(1)
271 , m_objcount(0)
0b9ab0bd
RL
272{
273 if( m_handle != 0 )
274 {
275 UpdateClassInfo();
276 RegisterModules();
277 }
278 else
7c1e2b44 279 --m_linkcount; // Flag us for deletion
0b9ab0bd
RL
280}
281
282wxDLManifestEntry::~wxDLManifestEntry()
283{
01610529
RL
284 if( m_handle != 0 )
285 {
286 UnregisterModules();
287 RestoreClassInfo();
288 wxDllLoader::UnloadLibrary(m_handle);
289 }
0b9ab0bd
RL
290}
291
7c1e2b44
RL
292bool 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}
0b9ab0bd
RL
302
303// ------------------------
304// Private methods
305// ------------------------
306
307void 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
345void 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
368void 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
7c1e2b44 378 wxASSERT_MSG( m_linkcount == 1,
0b9ab0bd
RL
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
7c1e2b44 417 --m_linkcount; // Flag us for deletion
0b9ab0bd
RL
418 break;
419 }
420 }
421}
422
423void 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
441wxDLManifest wxDynamicLibrary::ms_manifest(wxKEY_STRING);
442
443// ------------------------
444// Static accessors
445// ------------------------
446
447wxDLManifestEntry *wxDynamicLibrary::Link(const wxString &libname)
448{
449 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
450
451 if( entry )
452 {
7c1e2b44 453 entry->RefLib();
0b9ab0bd
RL
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 {
01610529 465 wxCHECK_MSG( entry->UnrefLib(), 0,
0b9ab0bd
RL
466 _T("Currently linked library is, ..not loaded??") );
467 entry = 0;
468 }
469 }
470 return entry;
471}
472
473bool wxDynamicLibrary::Unlink(const wxString &libname)
474{
475 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
476
477 if( entry )
7c1e2b44 478 return entry->UnrefLib();
0b9ab0bd
RL
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
488wxDynamicLibrary::wxDynamicLibrary(const wxString &libname)
489{
490 m_entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
491
492 if( m_entry != 0 )
493 {
7c1e2b44 494 m_entry->RefLib();
0b9ab0bd
RL
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
505wxDynamicLibrary::~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
7c1e2b44 516 if( m_entry && m_entry->UnrefLib() )
0b9ab0bd
RL
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
527extern "C" {
528#import <mach-o/dyld.h>
529};
530
531enum dyldErrorSource
532{
533 OFImage,
534};
535
536static char dl_last_error[1024];
537
538static
539void 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
571const char *dlerror()
572{
573 return dl_last_error;
574}
575void *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
596int dlclose(void *handle) /* stub only */
597{
598 return 0;
599}
600
601void *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