]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynlib.cpp
Fixed preview navigation as per ancient bug report
[wxWidgets.git] / src / common / dynlib.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dynlib.cpp
3 // Purpose: Dynamic library management
4 // Author: Guilhem Lavaux
5 // Modified by:
6 // Created: 20/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Guilhem Lavaux
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 # pragma implementation "dynlib.h"
22 #endif
23
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #if wxUSE_DYNLIB_CLASS && !wxUSE_DYNAMIC_LOADER
31
32 #if defined(__WINDOWS__)
33 #include "wx/msw/private.h"
34 #endif
35
36 #include "wx/dynlib.h"
37 #include "wx/filefn.h"
38 #include "wx/intl.h"
39 #include "wx/log.h"
40
41 #if defined(__WXMAC__)
42 #include "wx/mac/private.h"
43 #endif
44
45 // ----------------------------------------------------------------------------
46 // conditional compilation
47 // ----------------------------------------------------------------------------
48
49 #if defined(__WXPM__) || defined(__EMX__)
50 # define INCL_DOS
51 # include <os2.h>
52 # define wxDllOpen(error, lib, handle) DosLoadModule(error, sizeof(error), lib, &handle)
53 # define wxDllGetSymbol(handle, modaddr) DosQueryProcAddr(handle, 1L, NULL, (PFN*)modaddr)
54 # define wxDllClose(handle) DosFreeModule(handle)
55 #elif defined(HAVE_DLOPEN)
56 // note about dlopen() flags: we use RTLD_NOW to have more Windows-like
57 // behaviour (Win won't let you load a library with missing symbols) and
58 // RTLD_GLOBAL because it is needed sometimes and probably doesn't hurt
59 // otherwise. On True64-Unix RTLD_GLOBAL is not allowed and on VMS the
60 // second argument on dlopen is ignored.
61 #ifdef __VMS
62 # define wxDllOpen(lib) dlopen(lib.fn_str(), 0 )
63 #elif defined( __osf__ )
64 # define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY )
65 #else
66 # define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY | RTLD_GLOBAL)
67 #endif
68 #define wxDllGetSymbol(handle, name) dlsym(handle, name)
69 # define wxDllClose dlclose
70 #elif defined(HAVE_SHL_LOAD)
71 # define wxDllOpen(lib) shl_load(lib.fn_str(), BIND_DEFERRED, 0)
72 # define wxDllClose shl_unload
73
74 static inline void *wxDllGetSymbol(shl_t handle, const wxString& name)
75 {
76 void *sym;
77 if ( shl_findsym(&handle, name.mb_str(), TYPE_UNDEFINED, &sym) == 0 )
78 return sym;
79 else
80 return 0;
81 }
82
83 #elif defined(__DARWIN__)
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 #elif defined(__WINDOWS__)
99 // using LoadLibraryEx under Win32 to avoid name clash with LoadLibrary
100 # ifdef __WIN32__
101 #ifdef _UNICODE
102 #ifdef __WXWINCE__
103 # define wxDllOpen(lib) ::LoadLibrary(lib)
104 #else
105 # define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
106 #endif
107 #else
108 # define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
109 #endif
110 # else // Win16
111 # define wxDllOpen(lib) ::LoadLibrary(lib)
112 # endif // Win32/16
113 # define wxDllGetSymbol(handle, name) ::GetProcAddress(handle, name)
114 # define wxDllClose ::FreeLibrary
115 #elif defined(__WXMAC__)
116 # define wxDllClose(handle) CloseConnection(&((CFragConnectionID)handle))
117 #else
118 # error "Don't know how to load shared libraries on this platform."
119 #endif // OS
120
121 // ---------------------------------------------------------------------------
122 // Global variables
123 // ---------------------------------------------------------------------------
124
125 wxLibraries wxTheLibraries;
126
127 // ============================================================================
128 // implementation
129 // ============================================================================
130
131 // construct the full name from the base shared object name: adds a .dll
132 // suffix under Windows or .so under Unix
133 static wxString ConstructLibraryName(const wxString& basename)
134 {
135 wxString fullname;
136 fullname << basename << wxDllLoader::GetDllExt();
137
138 return fullname;
139 }
140
141 // ---------------------------------------------------------------------------
142 // wxLibrary (one instance per dynamic library)
143 // ---------------------------------------------------------------------------
144
145 wxLibrary::wxLibrary(wxDllType handle)
146 {
147 typedef wxClassInfo *(*t_get_first)(void);
148 t_get_first get_first;
149
150 m_handle = handle;
151
152 // Some system may use a local heap for library.
153 get_first = (t_get_first)GetSymbol(_T("wxGetClassFirst"));
154 // It is a wxWindows DLL.
155 if (get_first)
156 PrepareClasses(get_first());
157 }
158
159 wxLibrary::~wxLibrary()
160 {
161 if ( m_handle )
162 {
163 wxDllClose(m_handle);
164 }
165 }
166
167 wxObject *wxLibrary::CreateObject(const wxString& name)
168 {
169 wxClassInfo *info = (wxClassInfo *)classTable.Get(name);
170
171 if (!info)
172 return NULL;
173
174 return info->CreateObject();
175 }
176
177 void wxLibrary::PrepareClasses(wxClassInfo *first)
178 {
179 // Index all class infos by their class name
180 wxClassInfo *info = first;
181 while (info)
182 {
183 if (info->m_className)
184 classTable.Put(info->m_className, (wxObject *)info);
185 info = info->m_next;
186 }
187
188 // Set base pointers for each wxClassInfo
189 info = first;
190 while (info)
191 {
192 if (info->GetBaseClassName1())
193 info->m_baseInfo1 = (wxClassInfo *)classTable.Get(info->GetBaseClassName1());
194 if (info->GetBaseClassName2())
195 info->m_baseInfo2 = (wxClassInfo *)classTable.Get(info->GetBaseClassName2());
196 info = info->m_next;
197 }
198 }
199
200 void *wxLibrary::GetSymbol(const wxString& symbname)
201 {
202 return wxDllLoader::GetSymbol(m_handle, symbname);
203 }
204
205 // ---------------------------------------------------------------------------
206 // wxDllLoader
207 // ---------------------------------------------------------------------------
208
209
210 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
211 const wxString wxDllLoader::ms_dllext( _T(".dll") );
212 #elif defined(__UNIX__)
213 #if defined(__HPUX__)
214 const wxString wxDllLoader::ms_dllext( _T(".sl") );
215 #else
216 const wxString wxDllLoader::ms_dllext( _T(".so") );
217 #endif
218 #elif defined(__WXMAC__)
219 const wxString wxDllLoader::ms_dllext( _T("") );
220 #endif
221
222 /* static */
223 wxDllType wxDllLoader::GetProgramHandle()
224 {
225 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
226 // optain handle for main program
227 return dlopen(NULL, RTLD_NOW/*RTLD_LAZY*/);
228 #elif defined (HAVE_SHL_LOAD)
229 // shl_findsymbol with NULL handle looks up in main program
230 return 0;
231 #else
232 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
233 return 0;
234 #endif
235 }
236
237 /* static */
238 wxDllType wxDllLoader::LoadLibrary(const wxString & libname, bool *success)
239 {
240 wxDllType handle;
241 bool failed = FALSE;
242
243 #if defined(__WXMAC__) && !defined(__UNIX__)
244 FSSpec myFSSpec;
245 Ptr myMainAddr;
246 Str255 myErrName;
247
248 wxMacFilename2FSSpec( libname , &myFSSpec );
249
250 if( GetDiskFragment( &myFSSpec,
251 0,
252 kCFragGoesToEOF,
253 "\p",
254 kPrivateCFragCopy,
255 &((CFragConnectionID)handle),
256 &myMainAddr,
257 myErrName ) != noErr )
258 {
259 p2cstr( myErrName );
260 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
261 libname.c_str(),
262 (char*)myErrName );
263 handle = 0;
264 failed = TRUE;
265 }
266
267 #elif defined(__WXPM__) || defined(__EMX__)
268 char zError[256] = "";
269 wxDllOpen(zError, libname, handle);
270
271 #else
272 handle = wxDllOpen(libname);
273
274 #endif
275
276 if ( !handle )
277 {
278 wxString msg(_("Failed to load shared library '%s'"));
279
280 #ifdef HAVE_DLERROR
281 const wxChar *err = dlerror();
282 if( err )
283 {
284 failed = TRUE;
285 wxLogError( msg, err );
286 }
287 #else
288 failed = TRUE;
289 wxLogSysError( msg, libname.c_str() );
290 #endif
291 }
292
293 if ( success )
294 *success = !failed;
295
296 return handle;
297 }
298
299
300 /* static */
301 void wxDllLoader::UnloadLibrary(wxDllType handle)
302 {
303 wxDllClose(handle);
304 }
305
306 /* static */
307 void *wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name, bool *success)
308 {
309 bool failed = FALSE;
310 void *symbol = 0;
311
312 #if defined(__WXMAC__) && !defined(__UNIX__)
313 Ptr symAddress;
314 CFragSymbolClass symClass;
315 Str255 symName;
316
317 wxMacStringToPascal( name.c_str() , symName ) ;
318
319 if( FindSymbol( ((CFragConnectionID)dllHandle), symName, &symAddress, &symClass ) == noErr )
320 symbol = (void *)symAddress;
321
322 #elif defined(__WXPM__) || defined(__EMX__)
323 wxDllGetSymbol(dllHandle, symbol);
324
325 #else // Windows or Unix
326
327 // mb_str() is necessary in Unicode build
328 //
329 // "void *" cast is needed by gcc 3.1 + w32api 1.4, don't ask me why
330 #ifdef __WXWINCE__
331 symbol = (void *) wxDllGetSymbol(dllHandle, name.c_str());
332 #else
333 symbol = (void *) wxDllGetSymbol(dllHandle, name.mb_str());
334 #endif
335
336 #endif // OS
337
338 if ( !symbol )
339 {
340 #ifdef HAVE_DLERROR
341 const wxChar *err = dlerror();
342 if( err )
343 {
344 wxLogError(wxT("%s"), err);
345 }
346 #else
347 failed = TRUE;
348 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
349 name.c_str());
350 #endif
351 }
352
353 if( success )
354 *success = !failed;
355
356 return symbol;
357 }
358
359 // ---------------------------------------------------------------------------
360 // wxLibraries (only one instance should normally exist)
361 // ---------------------------------------------------------------------------
362
363 wxLibraries::wxLibraries():m_loaded(wxKEY_STRING)
364 {
365 }
366
367 wxLibraries::~wxLibraries()
368 {
369 wxNode *node = m_loaded.First();
370
371 while (node) {
372 wxLibrary *lib = (wxLibrary *)node->Data();
373 delete lib;
374
375 node = node->Next();
376 }
377 }
378
379 wxLibrary *wxLibraries::LoadLibrary(const wxString& name)
380 {
381 wxLibrary *lib;
382 wxClassInfo *old_sm_first;
383 wxNode *node = m_loaded.Find(name.GetData());
384
385 if (node != NULL)
386 return ((wxLibrary *)node->Data());
387
388 // If DLL shares data, this is necessary.
389 old_sm_first = wxClassInfo::sm_first;
390 wxClassInfo::sm_first = NULL;
391
392 wxString libname = ConstructLibraryName(name);
393
394 bool success = FALSE;
395 wxDllType handle = wxDllLoader::LoadLibrary(libname, &success);
396 if(success)
397 {
398 lib = new wxLibrary(handle);
399 wxClassInfo::sm_first = old_sm_first;
400
401 m_loaded.Append(name.GetData(), lib);
402 }
403 else
404 lib = NULL;
405 return lib;
406 }
407
408 wxObject *wxLibraries::CreateObject(const wxString& path)
409 {
410 wxNode *node = m_loaded.First();
411 wxObject *obj;
412
413 while (node) {
414 obj = ((wxLibrary *)node->Data())->CreateObject(path);
415 if (obj)
416 return obj;
417
418 node = node->Next();
419 }
420 return NULL;
421 }
422
423 #endif // wxUSE_DYNLIB_CLASS && !wxUSE_DYNAMIC_LOADER
424
425 #if defined(__DARWIN__) && (wxUSE_DYNLIB_CLASS || wxUSE_DYNAMIC_LOADER)
426 // ---------------------------------------------------------------------------
427 // For Darwin/Mac OS X
428 // supply the sun style dlopen functions in terms of Darwin NS*
429 // ---------------------------------------------------------------------------
430
431 #include <stdio.h>
432 #include <mach-o/dyld.h>
433
434 static char dl_last_error[1024];
435
436 static
437 void TranslateError(const char *path, int number)
438 {
439 unsigned int index;
440 static char *OFIErrorStrings[] =
441 {
442 "%s(%d): Object Image Load Failure\n",
443 "%s(%d): Object Image Load Success\n",
444 "%s(%d): Not an recognisable object file\n",
445 "%s(%d): No valid architecture\n",
446 "%s(%d): Object image has an invalid format\n",
447 "%s(%d): Invalid access (permissions?)\n",
448 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
449 };
450 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
451
452 index = number;
453 if (index > NUM_OFI_ERRORS - 1) {
454 index = NUM_OFI_ERRORS - 1;
455 }
456 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
457 }
458
459 const char *dlerror()
460 {
461 return dl_last_error;
462 }
463
464 void *dlopen(const char *path, int WXUNUSED(mode) /* mode is ignored */)
465 {
466 int dyld_result;
467 NSObjectFileImage ofile;
468 NSModule handle = NULL;
469
470 dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
471 if (dyld_result != NSObjectFileImageSuccess)
472 {
473 TranslateError(path, dyld_result);
474 }
475 else
476 {
477 // NSLinkModule will cause the run to abort on any link error's
478 // not very friendly but the error recovery functionality is limited.
479 handle = NSLinkModule(ofile, path, NSLINKMODULE_OPTION_BINDNOW);
480 }
481
482 return handle;
483 }
484
485 int dlclose(void *handle)
486 {
487 NSUnLinkModule( handle, NSUNLINKMODULE_OPTION_NONE);
488 return 0;
489 }
490
491 void *dlsym(void *handle, const char *symbol)
492 {
493 void *addr;
494
495 NSSymbol nsSymbol = NSLookupSymbolInModule( handle , symbol ) ;
496
497 if ( nsSymbol)
498 {
499 addr = NSAddressOfSymbol(nsSymbol);
500 }
501 else
502 {
503 addr = NULL;
504 }
505 return addr;
506 }
507
508 #endif // defined(__DARWIN__) && (wxUSE_DYNLIB_CLASS || wxUSE_DYNAMIC_LOADER)