]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynload.cpp
'Y' positioning fixes for OS/2 controls
[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 UnregisterModules();
285 RestoreClassInfo();
286
287 wxDllLoader::UnloadLibrary(m_handle);
288 }
289
290 bool 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 }
300
301 // ------------------------
302 // Private methods
303 // ------------------------
304
305 void 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
343 void 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
366 void 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
376 wxASSERT_MSG( m_linkcount == 1,
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
415 --m_linkcount; // Flag us for deletion
416 break;
417 }
418 }
419 }
420
421 void 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
439 wxDLManifest wxDynamicLibrary::ms_manifest(wxKEY_STRING);
440
441 // ------------------------
442 // Static accessors
443 // ------------------------
444
445 wxDLManifestEntry *wxDynamicLibrary::Link(const wxString &libname)
446 {
447 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
448
449 if( entry )
450 {
451 entry->RefLib();
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 {
463 wxCHECK_MSG( !entry->UnrefLib(), 0,
464 _T("Currently linked library is, ..not loaded??") );
465 entry = 0;
466 }
467 }
468 return entry;
469 }
470
471 bool wxDynamicLibrary::Unlink(const wxString &libname)
472 {
473 wxDLManifestEntry *entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
474
475 if( entry )
476 return entry->UnrefLib();
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
486 wxDynamicLibrary::wxDynamicLibrary(const wxString &libname)
487 {
488 m_entry = (wxDLManifestEntry*) ms_manifest.Get(libname);
489
490 if( m_entry != 0 )
491 {
492 m_entry->RefLib();
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
503 wxDynamicLibrary::~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
514 if( m_entry && m_entry->UnrefLib() )
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
525 extern "C" {
526 #import <mach-o/dyld.h>
527 };
528
529 enum dyldErrorSource
530 {
531 OFImage,
532 };
533
534 static char dl_last_error[1024];
535
536 static
537 void 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
569 const char *dlerror()
570 {
571 return dl_last_error;
572 }
573 void *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
594 int dlclose(void *handle) /* stub only */
595 {
596 return 0;
597 }
598
599 void *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