]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynlib.cpp
always NUL-terminate log messages, even if they're longer than buffer size
[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 # define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
103 #else
104 # define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
105 #endif
106 # else // Win16
107 # define wxDllOpen(lib) ::LoadLibrary(lib)
108 # endif // Win32/16
109 # define wxDllGetSymbol(handle, name) ::GetProcAddress(handle, name)
110 # define wxDllClose ::FreeLibrary
111 #elif defined(__WXMAC__)
112 # define wxDllClose(handle) CloseConnection(&((CFragConnectionID)handle))
113 #else
114 # error "Don't know how to load shared libraries on this platform."
115 #endif // OS
116
117 // ---------------------------------------------------------------------------
118 // Global variables
119 // ---------------------------------------------------------------------------
120
121 wxLibraries wxTheLibraries;
122
123 // ============================================================================
124 // implementation
125 // ============================================================================
126
127 // construct the full name from the base shared object name: adds a .dll
128 // suffix under Windows or .so under Unix
129 static wxString ConstructLibraryName(const wxString& basename)
130 {
131 wxString fullname;
132 fullname << basename << wxDllLoader::GetDllExt();
133
134 return fullname;
135 }
136
137 // ---------------------------------------------------------------------------
138 // wxLibrary (one instance per dynamic library)
139 // ---------------------------------------------------------------------------
140
141 wxLibrary::wxLibrary(wxDllType handle)
142 {
143 typedef wxClassInfo *(*t_get_first)(void);
144 t_get_first get_first;
145
146 m_handle = handle;
147
148 // Some system may use a local heap for library.
149 get_first = (t_get_first)GetSymbol(_T("wxGetClassFirst"));
150 // It is a wxWindows DLL.
151 if (get_first)
152 PrepareClasses(get_first());
153 }
154
155 wxLibrary::~wxLibrary()
156 {
157 if ( m_handle )
158 {
159 wxDllClose(m_handle);
160 }
161 }
162
163 wxObject *wxLibrary::CreateObject(const wxString& name)
164 {
165 wxClassInfo *info = (wxClassInfo *)classTable.Get(name);
166
167 if (!info)
168 return NULL;
169
170 return info->CreateObject();
171 }
172
173 void wxLibrary::PrepareClasses(wxClassInfo *first)
174 {
175 // Index all class infos by their class name
176 wxClassInfo *info = first;
177 while (info)
178 {
179 if (info->m_className)
180 classTable.Put(info->m_className, (wxObject *)info);
181 info = info->m_next;
182 }
183
184 // Set base pointers for each wxClassInfo
185 info = first;
186 while (info)
187 {
188 if (info->GetBaseClassName1())
189 info->m_baseInfo1 = (wxClassInfo *)classTable.Get(info->GetBaseClassName1());
190 if (info->GetBaseClassName2())
191 info->m_baseInfo2 = (wxClassInfo *)classTable.Get(info->GetBaseClassName2());
192 info = info->m_next;
193 }
194 }
195
196 void *wxLibrary::GetSymbol(const wxString& symbname)
197 {
198 return wxDllLoader::GetSymbol(m_handle, symbname);
199 }
200
201 // ---------------------------------------------------------------------------
202 // wxDllLoader
203 // ---------------------------------------------------------------------------
204
205
206 #if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
207 const wxString wxDllLoader::ms_dllext( _T(".dll") );
208 #elif defined(__UNIX__)
209 #if defined(__HPUX__)
210 const wxString wxDllLoader::ms_dllext( _T(".sl") );
211 #else
212 const wxString wxDllLoader::ms_dllext( _T(".so") );
213 #endif
214 #elif defined(__WXMAC__)
215 const wxString wxDllLoader::ms_dllext( _T("") );
216 #endif
217
218 /* static */
219 wxDllType wxDllLoader::GetProgramHandle()
220 {
221 #if defined( HAVE_DLOPEN ) && !defined(__EMX__)
222 // optain handle for main program
223 return dlopen(NULL, RTLD_NOW/*RTLD_LAZY*/);
224 #elif defined (HAVE_SHL_LOAD)
225 // shl_findsymbol with NULL handle looks up in main program
226 return 0;
227 #else
228 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
229 return 0;
230 #endif
231 }
232
233 /* static */
234 wxDllType wxDllLoader::LoadLibrary(const wxString & libname, bool *success)
235 {
236 wxDllType handle;
237 bool failed = FALSE;
238
239 #if defined(__WXMAC__) && !defined(__UNIX__)
240 FSSpec myFSSpec;
241 Ptr myMainAddr;
242 Str255 myErrName;
243
244 wxMacFilename2FSSpec( libname , &myFSSpec );
245
246 if( GetDiskFragment( &myFSSpec,
247 0,
248 kCFragGoesToEOF,
249 "\p",
250 kPrivateCFragCopy,
251 &((CFragConnectionID)handle),
252 &myMainAddr,
253 myErrName ) != noErr )
254 {
255 p2cstr( myErrName );
256 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
257 libname.c_str(),
258 (char*)myErrName );
259 handle = 0;
260 failed = TRUE;
261 }
262
263 #elif defined(__WXPM__) || defined(__EMX__)
264 char zError[256] = "";
265 wxDllOpen(zError, libname, handle);
266
267 #else
268 handle = wxDllOpen(libname);
269
270 #endif
271
272 if ( !handle )
273 {
274 wxString msg(_("Failed to load shared library '%s'"));
275
276 #ifdef HAVE_DLERROR
277 const wxChar *err = dlerror();
278 if( err )
279 {
280 failed = TRUE;
281 wxLogError( msg, err );
282 }
283 #else
284 failed = TRUE;
285 wxLogSysError( msg, libname.c_str() );
286 #endif
287 }
288
289 if ( success )
290 *success = !failed;
291
292 return handle;
293 }
294
295
296 /* static */
297 void wxDllLoader::UnloadLibrary(wxDllType handle)
298 {
299 wxDllClose(handle);
300 }
301
302 /* static */
303 void *wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name, bool *success)
304 {
305 bool failed = FALSE;
306 void *symbol = 0;
307
308 #if defined(__WXMAC__) && !defined(__UNIX__)
309 Ptr symAddress;
310 CFragSymbolClass symClass;
311 Str255 symName;
312
313 wxMacStringToPascal( name.c_str() , symName ) ;
314
315 if( FindSymbol( ((CFragConnectionID)dllHandle), symName, &symAddress, &symClass ) == noErr )
316 symbol = (void *)symAddress;
317
318 #elif defined(__WXPM__) || defined(__EMX__)
319 wxDllGetSymbol(dllHandle, symbol);
320
321 #else // Windows or Unix
322
323 // mb_str() is necessary in Unicode build
324 //
325 // "void *" cast is needed by gcc 3.1 + w32api 1.4, don't ask me why
326 symbol = (void *)wxDllGetSymbol(dllHandle, name.mb_str());
327
328 #endif // OS
329
330 if ( !symbol )
331 {
332 #ifdef HAVE_DLERROR
333 const wxChar *err = dlerror();
334 if( err )
335 {
336 wxLogError(wxT("%s"), err);
337 }
338 #else
339 failed = TRUE;
340 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
341 name.c_str());
342 #endif
343 }
344
345 if( success )
346 *success = !failed;
347
348 return symbol;
349 }
350
351 // ---------------------------------------------------------------------------
352 // wxLibraries (only one instance should normally exist)
353 // ---------------------------------------------------------------------------
354
355 wxLibraries::wxLibraries():m_loaded(wxKEY_STRING)
356 {
357 }
358
359 wxLibraries::~wxLibraries()
360 {
361 wxNode *node = m_loaded.First();
362
363 while (node) {
364 wxLibrary *lib = (wxLibrary *)node->Data();
365 delete lib;
366
367 node = node->Next();
368 }
369 }
370
371 wxLibrary *wxLibraries::LoadLibrary(const wxString& name)
372 {
373 wxLibrary *lib;
374 wxClassInfo *old_sm_first;
375 wxNode *node = m_loaded.Find(name.GetData());
376
377 if (node != NULL)
378 return ((wxLibrary *)node->Data());
379
380 // If DLL shares data, this is necessary.
381 old_sm_first = wxClassInfo::sm_first;
382 wxClassInfo::sm_first = NULL;
383
384 wxString libname = ConstructLibraryName(name);
385
386 bool success = FALSE;
387 wxDllType handle = wxDllLoader::LoadLibrary(libname, &success);
388 if(success)
389 {
390 lib = new wxLibrary(handle);
391 wxClassInfo::sm_first = old_sm_first;
392
393 m_loaded.Append(name.GetData(), lib);
394 }
395 else
396 lib = NULL;
397 return lib;
398 }
399
400 wxObject *wxLibraries::CreateObject(const wxString& path)
401 {
402 wxNode *node = m_loaded.First();
403 wxObject *obj;
404
405 while (node) {
406 obj = ((wxLibrary *)node->Data())->CreateObject(path);
407 if (obj)
408 return obj;
409
410 node = node->Next();
411 }
412 return NULL;
413 }
414
415 #endif // wxUSE_DYNLIB_CLASS && !wxUSE_DYNAMIC_LOADER
416
417 #if defined(__DARWIN__) && (wxUSE_DYNLIB_CLASS || wxUSE_DYNAMIC_LOADER)
418 // ---------------------------------------------------------------------------
419 // For Darwin/Mac OS X
420 // supply the sun style dlopen functions in terms of Darwin NS*
421 // ---------------------------------------------------------------------------
422
423 #include <stdio.h>
424 #include <mach-o/dyld.h>
425
426 static char dl_last_error[1024];
427
428 static
429 void TranslateError(const char *path, int number)
430 {
431 unsigned int index;
432 static char *OFIErrorStrings[] =
433 {
434 "%s(%d): Object Image Load Failure\n",
435 "%s(%d): Object Image Load Success\n",
436 "%s(%d): Not an recognisable object file\n",
437 "%s(%d): No valid architecture\n",
438 "%s(%d): Object image has an invalid format\n",
439 "%s(%d): Invalid access (permissions?)\n",
440 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
441 };
442 #define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
443
444 index = number;
445 if (index > NUM_OFI_ERRORS - 1) {
446 index = NUM_OFI_ERRORS - 1;
447 }
448 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
449 }
450
451 const char *dlerror()
452 {
453 return dl_last_error;
454 }
455
456 void *dlopen(const char *path, int WXUNUSED(mode) /* mode is ignored */)
457 {
458 int dyld_result;
459 NSObjectFileImage ofile;
460 NSModule handle = NULL;
461
462 dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
463 if (dyld_result != NSObjectFileImageSuccess)
464 {
465 TranslateError(path, dyld_result);
466 }
467 else
468 {
469 // NSLinkModule will cause the run to abort on any link error's
470 // not very friendly but the error recovery functionality is limited.
471 handle = NSLinkModule(ofile, path, NSLINKMODULE_OPTION_BINDNOW);
472 }
473
474 return handle;
475 }
476
477 int dlclose(void *handle)
478 {
479 NSUnLinkModule( handle, NSUNLINKMODULE_OPTION_NONE);
480 return 0;
481 }
482
483 void *dlsym(void *handle, const char *symbol)
484 {
485 void *addr;
486
487 NSSymbol nsSymbol = NSLookupSymbolInModule( handle , symbol ) ;
488
489 if ( nsSymbol)
490 {
491 addr = NSAddressOfSymbol(nsSymbol);
492 }
493 else
494 {
495 addr = NULL;
496 }
497 return addr;
498 }
499
500 #endif // defined(__DARWIN__) && (wxUSE_DYNLIB_CLASS || wxUSE_DYNAMIC_LOADER)