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