]> git.saurik.com Git - wxWidgets.git/blame - src/common/dynlib.cpp
new static structure for using the correct resource file (needed for shared lib)
[wxWidgets.git] / src / common / dynlib.cpp
CommitLineData
7a4b9130
GL
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 license
10/////////////////////////////////////////////////////////////////////////////
11
7b0bfbb2
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
7a4b9130 20#ifdef __GNUG__
a585ca5c 21# pragma implementation "dynlib.h"
7a4b9130
GL
22#endif
23
0c32066b
JS
24#include "wx/wxprec.h"
25
2df7be7f
RR
26#ifdef __BORLANDC__
27 #pragma hdrstop
28#endif
f6bcfd97 29
481fcc78 30#if wxUSE_DYNLIB_CLASS && !wxUSE_DYNAMIC_LOADER
8a0d4cf6 31
f6bcfd97
BP
32#if defined(__WINDOWS__)
33 #include "wx/msw/private.h"
34#endif
35
7b0bfbb2
VZ
36#include "wx/dynlib.h"
37#include "wx/filefn.h"
38#include "wx/intl.h"
39#include "wx/log.h"
40
76a5e5d2
SC
41#if defined(__WXMAC__)
42 #include "wx/mac/private.h"
43#endif
44
7b0bfbb2
VZ
45// ----------------------------------------------------------------------------
46// conditional compilation
47// ----------------------------------------------------------------------------
48
1a787c5d
SN
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)
237c5c02
VZ
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
343a06a5
JJ
59 // otherwise. On True64-Unix RTLD_GLOBAL is not allowed and on VMS the
60 // second argument on dlopen is ignored.
99d96a2b
JJ
61#ifdef __VMS
62# define wxDllOpen(lib) dlopen(lib.fn_str(), 0 )
343a06a5
JJ
63#elif defined( __osf__ )
64# define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY )
99d96a2b
JJ
65#else
66# define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY | RTLD_GLOBAL)
67#endif
68#define wxDllGetSymbol(handle, name) dlsym(handle, name)
a585ca5c 69# define wxDllClose dlclose
8a0d4cf6 70#elif defined(HAVE_SHL_LOAD)
a585ca5c 71# define wxDllOpen(lib) shl_load(lib.fn_str(), BIND_DEFERRED, 0)
237c5c02 72# define wxDllClose shl_unload
846e1424 73
0b9ab0bd
RL
74static 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
f11bdd03
GD
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 */
4c27c3c6
GD
90void *dlopen(const char *path, int mode /* mode is ignored */);
91void *dlsym(void *handle, const char *symbol);
03e11df5 92int dlclose(void *handle);
4c27c3c6 93const char *dlerror(void);
03e11df5
GD
94
95# define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
96# define wxDllGetSymbol(handle, name) dlsym(handle, name)
97# define wxDllClose dlclose
7b0bfbb2 98#elif defined(__WINDOWS__)
90022ddc 99 // using LoadLibraryEx under Win32 to avoid name clash with LoadLibrary
a585ca5c 100# ifdef __WIN32__
f6bcfd97
BP
101#ifdef _UNICODE
102# define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
103#else
104# define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
105#endif
a585ca5c
KB
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
763ca781 111#elif defined(__WXMAC__)
76a5e5d2 112# define wxDllClose(handle) CloseConnection(&((CFragConnectionID)handle))
7b0bfbb2 113#else
a585ca5c 114# error "Don't know how to load shared libraries on this platform."
7b0bfbb2 115#endif // OS
7a4b9130
GL
116
117// ---------------------------------------------------------------------------
7b0bfbb2 118// Global variables
7a4b9130
GL
119// ---------------------------------------------------------------------------
120
7b0bfbb2 121wxLibraries wxTheLibraries;
7a4b9130 122
f6bcfd97
BP
123// ============================================================================
124// implementation
125// ============================================================================
123a7fdd 126
7b0bfbb2
VZ
127// construct the full name from the base shared object name: adds a .dll
128// suffix under Windows or .so under Unix
129static wxString ConstructLibraryName(const wxString& basename)
130{
f6bcfd97
BP
131 wxString fullname;
132 fullname << basename << wxDllLoader::GetDllExt();
27529614 133
7b0bfbb2
VZ
134 return fullname;
135}
7a4b9130 136
7a4b9130 137// ---------------------------------------------------------------------------
7b0bfbb2 138// wxLibrary (one instance per dynamic library)
7a4b9130
GL
139// ---------------------------------------------------------------------------
140
7b0bfbb2 141wxLibrary::wxLibrary(wxDllType handle)
7a4b9130 142{
7b0bfbb2
VZ
143 typedef wxClassInfo *(*t_get_first)(void);
144 t_get_first get_first;
7a4b9130 145
7b0bfbb2 146 m_handle = handle;
7a4b9130 147
7b0bfbb2
VZ
148 // Some system may use a local heap for library.
149 get_first = (t_get_first)GetSymbol("wxGetClassFirst");
150 // It is a wxWindows DLL.
151 if (get_first)
152 PrepareClasses(get_first());
7a4b9130
GL
153}
154
155wxLibrary::~wxLibrary()
156{
7b0bfbb2
VZ
157 if ( m_handle )
158 {
159 wxDllClose(m_handle);
160 }
7a4b9130
GL
161}
162
163wxObject *wxLibrary::CreateObject(const wxString& name)
164{
7b0bfbb2 165 wxClassInfo *info = (wxClassInfo *)classTable.Get(name);
f4a8c29f 166
7b0bfbb2
VZ
167 if (!info)
168 return NULL;
f4a8c29f 169
7b0bfbb2 170 return info->CreateObject();
f4a8c29f
GL
171}
172
856d2e52 173void wxLibrary::PrepareClasses(wxClassInfo *first)
f4a8c29f 174{
7b0bfbb2
VZ
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);
0b9ab0bd 181 info = info->m_next;
7b0bfbb2
VZ
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 }
7a4b9130
GL
194}
195
196void *wxLibrary::GetSymbol(const wxString& symbname)
197{
a585ca5c
KB
198 return wxDllLoader::GetSymbol(m_handle, symbname);
199}
7b0bfbb2 200
a585ca5c
KB
201// ---------------------------------------------------------------------------
202// wxDllLoader
203// ---------------------------------------------------------------------------
7b0bfbb2 204
f6bcfd97
BP
205
206#if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
0b9ab0bd 207const wxString wxDllLoader::ms_dllext( _T(".dll") );
f6bcfd97 208#elif defined(__UNIX__)
0b9ab0bd
RL
209#if defined(__HPUX__)
210const wxString wxDllLoader::ms_dllext( _T(".sl") );
211#else
212const wxString wxDllLoader::ms_dllext( _T(".so") );
213#endif
f6bcfd97 214#endif
f6bcfd97 215
0868079c 216/* static */
0b9ab0bd 217wxDllType wxDllLoader::GetProgramHandle()
0868079c 218{
1a787c5d 219#if defined( HAVE_DLOPEN ) && !defined(__EMX__)
7742efff 220 // optain handle for main program
d236a959 221 return dlopen(NULL, RTLD_NOW/*RTLD_LAZY*/);
7742efff
KB
222#elif defined (HAVE_SHL_LOAD)
223 // shl_findsymbol with NULL handle looks up in main program
d236a959 224 return 0;
0868079c 225#else
58c837a4 226 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
7742efff 227 return 0;
7cc98b3e 228#endif
0868079c
KB
229}
230
a585ca5c 231/* static */
0b9ab0bd 232wxDllType wxDllLoader::LoadLibrary(const wxString & libname, bool *success)
a585ca5c 233{
0b9ab0bd
RL
234 wxDllType handle;
235 bool failed = FALSE;
7b0bfbb2 236
03e11df5 237#if defined(__WXMAC__) && !defined(__UNIX__)
0b9ab0bd
RL
238 FSSpec myFSSpec;
239 Ptr myMainAddr;
240 Str255 myErrName;
241
242 wxMacFilename2FSSpec( libname , &myFSSpec );
243
244 if( GetDiskFragment( &myFSSpec,
245 0,
246 kCFragGoesToEOF,
247 "\p",
248 kPrivateCFragCopy,
76a5e5d2 249 &((CFragConnectionID)handle),
0b9ab0bd
RL
250 &myMainAddr,
251 myErrName ) != noErr )
7cc98b3e 252 {
0b9ab0bd
RL
253 p2cstr( myErrName );
254 wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
255 libname.c_str(),
256 (char*)myErrName );
257 handle = 0;
258 failed = TRUE;
7cc98b3e 259 }
0b9ab0bd 260
1a787c5d 261#elif defined(__WXPM__) || defined(__EMX__)
0b9ab0bd 262 char zError[256] = "";
c2ff79b1 263 wxDllOpen(zError, libname, handle);
0b9ab0bd
RL
264
265#else
93d2bf44 266 handle = wxDllOpen(libname);
0b9ab0bd
RL
267
268#endif
a585ca5c 269
7cc98b3e
VZ
270 if ( !handle )
271 {
f6bcfd97
BP
272 wxString msg(_("Failed to load shared library '%s'"));
273
274#ifdef HAVE_DLERROR
d0166913 275 const wxChar *err = dlerror();
0b9ab0bd 276 if( err )
f6bcfd97 277 {
0b9ab0bd
RL
278 failed = TRUE;
279 wxLogError( msg, err );
f6bcfd97 280 }
0b9ab0bd
RL
281#else
282 failed = TRUE;
283 wxLogSysError( msg, libname.c_str() );
284#endif
7cc98b3e
VZ
285 }
286
287 if ( success )
0b9ab0bd 288 *success = !failed;
7cc98b3e
VZ
289
290 return handle;
a585ca5c
KB
291}
292
752c7d6b
KB
293
294/* static */
0b9ab0bd 295void wxDllLoader::UnloadLibrary(wxDllType handle)
752c7d6b
KB
296{
297 wxDllClose(handle);
298}
299
a585ca5c 300/* static */
0b9ab0bd 301void *wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name, bool *success)
a585ca5c 302{
0b9ab0bd
RL
303 bool failed = FALSE;
304 void *symbol = 0;
a585ca5c 305
03e11df5 306#if defined(__WXMAC__) && !defined(__UNIX__)
0b9ab0bd
RL
307 Ptr symAddress;
308 CFragSymbolClass symClass;
309 Str255 symName;
7cc98b3e 310
03e11df5 311#if TARGET_CARBON
0b9ab0bd 312 c2pstrcpy( (StringPtr) symName, name );
03e11df5 313#else
0b9ab0bd
RL
314 strcpy( (char *) symName, name );
315 c2pstr( (char *) symName );
03e11df5 316#endif
76a5e5d2 317 if( FindSymbol( ((CFragConnectionID)dllHandle), symName, &symAddress, &symClass ) == noErr )
0b9ab0bd 318 symbol = (void *)symAddress;
7cc98b3e 319
0b9ab0bd 320#elif defined(__WXPM__) || defined(__EMX__)
c2ff79b1 321 wxDllGetSymbol(dllHandle, symbol);
0b9ab0bd 322
7b0bfbb2 323#else
f6bcfd97 324 // mb_str() is necessary in Unicode build
4c27c3c6 325 symbol = wxDllGetSymbol(dllHandle, name.mb_str());
0b9ab0bd 326
123a7fdd 327#endif
7b0bfbb2
VZ
328
329 if ( !symbol )
330 {
0b9ab0bd
RL
331 wxString msg(_("wxDllLoader failed to GetSymbol '%s'"));
332
333#ifdef HAVE_DLERROR
d0166913 334 const wxChar *err = dlerror();
0b9ab0bd
RL
335 if( err )
336 {
337 failed = TRUE;
338 wxLogError( msg, err );
339 }
340#else
341 failed = TRUE;
7cc98b3e
VZ
342 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
343 name.c_str());
0b9ab0bd 344#endif
7b0bfbb2 345 }
0b9ab0bd
RL
346
347 if( success )
348 *success = !failed;
349
7b0bfbb2 350 return symbol;
7a4b9130
GL
351}
352
353// ---------------------------------------------------------------------------
354// wxLibraries (only one instance should normally exist)
355// ---------------------------------------------------------------------------
356
65fd5cb0 357wxLibraries::wxLibraries():m_loaded(wxKEY_STRING)
7a4b9130
GL
358{
359}
360
361wxLibraries::~wxLibraries()
362{
7b0bfbb2 363 wxNode *node = m_loaded.First();
7a4b9130 364
7b0bfbb2
VZ
365 while (node) {
366 wxLibrary *lib = (wxLibrary *)node->Data();
367 delete lib;
7a4b9130 368
7b0bfbb2
VZ
369 node = node->Next();
370 }
7a4b9130
GL
371}
372
373wxLibrary *wxLibraries::LoadLibrary(const wxString& name)
374{
0b9ab0bd 375 wxLibrary *lib;
7b0bfbb2 376 wxClassInfo *old_sm_first;
0b9ab0bd 377 wxNode *node = m_loaded.Find(name.GetData());
7a4b9130 378
c2ff79b1
DW
379 if (node != NULL)
380 return ((wxLibrary *)node->Data());
0b9ab0bd 381
7b0bfbb2
VZ
382 // If DLL shares data, this is necessary.
383 old_sm_first = wxClassInfo::sm_first;
384 wxClassInfo::sm_first = NULL;
385
7cc98b3e 386 wxString libname = ConstructLibraryName(name);
856d2e52 387
4dc2c3bb 388 bool success = FALSE;
7cc98b3e 389 wxDllType handle = wxDllLoader::LoadLibrary(libname, &success);
a585ca5c 390 if(success)
7b0bfbb2 391 {
a585ca5c
KB
392 lib = new wxLibrary(handle);
393 wxClassInfo::sm_first = old_sm_first;
0b9ab0bd 394
a585ca5c 395 m_loaded.Append(name.GetData(), lib);
7b0bfbb2 396 }
a585ca5c
KB
397 else
398 lib = NULL;
7b0bfbb2 399 return lib;
7a4b9130
GL
400}
401
402wxObject *wxLibraries::CreateObject(const wxString& path)
403{
7b0bfbb2
VZ
404 wxNode *node = m_loaded.First();
405 wxObject *obj;
7a4b9130 406
7b0bfbb2
VZ
407 while (node) {
408 obj = ((wxLibrary *)node->Data())->CreateObject(path);
409 if (obj)
410 return obj;
7a4b9130 411
7b0bfbb2
VZ
412 node = node->Next();
413 }
414 return NULL;
7a4b9130 415}
8a0d4cf6 416
f11bdd03
GD
417#ifdef __DARWIN__
418// ---------------------------------------------------------------------------
419// For Darwin/Mac OS X
420// supply the sun style dlopen functions in terms of Darwin NS*
421// ---------------------------------------------------------------------------
422
423extern "C" {
424#import <mach-o/dyld.h>
425};
426
427enum dyldErrorSource
428{
429 OFImage,
430};
431
432static char dl_last_error[1024];
433
434static
435void TranslateError(const char *path, enum dyldErrorSource type, int number)
436{
437 unsigned int index;
438 static char *OFIErrorStrings[] =
439 {
440 "%s(%d): Object Image Load Failure\n",
441 "%s(%d): Object Image Load Success\n",
442 "%s(%d): Not an recognisable object file\n",
443 "%s(%d): No valid architecture\n",
444 "%s(%d): Object image has an invalid format\n",
445 "%s(%d): Invalid access (permissions?)\n",
446 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n",
447 };
448#define NUM_OFI_ERRORS (sizeof(OFIErrorStrings) / sizeof(OFIErrorStrings[0]))
449
450 switch (type)
451 {
452 case OFImage:
453 index = number;
454 if (index > NUM_OFI_ERRORS - 1) {
455 index = NUM_OFI_ERRORS - 1;
456 }
457 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
458 break;
459
460 default:
461 sprintf(dl_last_error, "%s(%d): Totally unknown error type %d\n",
462 path, number, type);
463 break;
464 }
465}
466
467const char *dlerror()
468{
469 return dl_last_error;
470}
471
472void *dlopen(const char *path, int mode /* mode is ignored */)
473{
474 int dyld_result;
475 NSObjectFileImage ofile;
476 NSModule handle = NULL;
477
478 dyld_result = NSCreateObjectFileImageFromFile(path, &ofile);
479 if (dyld_result != NSObjectFileImageSuccess)
480 {
481 TranslateError(path, OFImage, dyld_result);
482 }
483 else
484 {
485 // NSLinkModule will cause the run to abort on any link error's
486 // not very friendly but the error recovery functionality is limited.
487 handle = NSLinkModule(ofile, path, TRUE);
488 }
489
490 return handle;
491}
492
493int dlclose(void *handle) /* stub only */
494{
495 return 0;
496}
497
498void *dlsym(void *handle, const char *symbol)
499{
500 void *addr;
501
502 if (NSIsSymbolNameDefined(symbol)) {
503 addr = NSAddressOfSymbol(NSLookupAndBindSymbol(symbol));
504 }
505 else {
506 addr = NULL;
507 }
508 return addr;
509}
510
511#endif // __DARWIN__
512
8a0d4cf6 513#endif // wxUSE_DYNLIB_CLASS