]> git.saurik.com Git - wxWidgets.git/blame - src/common/dynlib.cpp
Unicode compilation fixes
[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
55d99c7a 9// Licence: wxWindows licence
7a4b9130
GL
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 101#ifdef _UNICODE
1c193821
JS
102#ifdef __WXWINCE__
103# define wxDllOpen(lib) ::LoadLibrary(lib)
104#else
f6bcfd97 105# define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
1c193821 106#endif
f6bcfd97
BP
107#else
108# define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
109#endif
a585ca5c
KB
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
763ca781 115#elif defined(__WXMAC__)
76a5e5d2 116# define wxDllClose(handle) CloseConnection(&((CFragConnectionID)handle))
7b0bfbb2 117#else
a585ca5c 118# error "Don't know how to load shared libraries on this platform."
7b0bfbb2 119#endif // OS
7a4b9130
GL
120
121// ---------------------------------------------------------------------------
7b0bfbb2 122// Global variables
7a4b9130
GL
123// ---------------------------------------------------------------------------
124
7b0bfbb2 125wxLibraries wxTheLibraries;
7a4b9130 126
f6bcfd97
BP
127// ============================================================================
128// implementation
129// ============================================================================
123a7fdd 130
7b0bfbb2
VZ
131// construct the full name from the base shared object name: adds a .dll
132// suffix under Windows or .so under Unix
133static wxString ConstructLibraryName(const wxString& basename)
134{
f6bcfd97
BP
135 wxString fullname;
136 fullname << basename << wxDllLoader::GetDllExt();
27529614 137
7b0bfbb2
VZ
138 return fullname;
139}
7a4b9130 140
7a4b9130 141// ---------------------------------------------------------------------------
7b0bfbb2 142// wxLibrary (one instance per dynamic library)
7a4b9130
GL
143// ---------------------------------------------------------------------------
144
7b0bfbb2 145wxLibrary::wxLibrary(wxDllType handle)
7a4b9130 146{
7b0bfbb2
VZ
147 typedef wxClassInfo *(*t_get_first)(void);
148 t_get_first get_first;
7a4b9130 149
7b0bfbb2 150 m_handle = handle;
7a4b9130 151
7b0bfbb2 152 // Some system may use a local heap for library.
55b7aaea 153 get_first = (t_get_first)GetSymbol(_T("wxGetClassFirst"));
7b0bfbb2
VZ
154 // It is a wxWindows DLL.
155 if (get_first)
156 PrepareClasses(get_first());
7a4b9130
GL
157}
158
159wxLibrary::~wxLibrary()
160{
7b0bfbb2
VZ
161 if ( m_handle )
162 {
163 wxDllClose(m_handle);
164 }
7a4b9130
GL
165}
166
167wxObject *wxLibrary::CreateObject(const wxString& name)
168{
7b0bfbb2 169 wxClassInfo *info = (wxClassInfo *)classTable.Get(name);
f4a8c29f 170
7b0bfbb2
VZ
171 if (!info)
172 return NULL;
f4a8c29f 173
7b0bfbb2 174 return info->CreateObject();
f4a8c29f
GL
175}
176
856d2e52 177void wxLibrary::PrepareClasses(wxClassInfo *first)
f4a8c29f 178{
7b0bfbb2
VZ
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);
0b9ab0bd 185 info = info->m_next;
7b0bfbb2
VZ
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 }
7a4b9130
GL
198}
199
200void *wxLibrary::GetSymbol(const wxString& symbname)
201{
a585ca5c
KB
202 return wxDllLoader::GetSymbol(m_handle, symbname);
203}
7b0bfbb2 204
a585ca5c
KB
205// ---------------------------------------------------------------------------
206// wxDllLoader
207// ---------------------------------------------------------------------------
7b0bfbb2 208
f6bcfd97
BP
209
210#if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
0b9ab0bd 211const wxString wxDllLoader::ms_dllext( _T(".dll") );
f6bcfd97 212#elif defined(__UNIX__)
0b9ab0bd
RL
213#if defined(__HPUX__)
214const wxString wxDllLoader::ms_dllext( _T(".sl") );
215#else
216const wxString wxDllLoader::ms_dllext( _T(".so") );
217#endif
337b2454
SC
218#elif defined(__WXMAC__)
219const wxString wxDllLoader::ms_dllext( _T("") );
f6bcfd97 220#endif
f6bcfd97 221
0868079c 222/* static */
0b9ab0bd 223wxDllType wxDllLoader::GetProgramHandle()
0868079c 224{
1a787c5d 225#if defined( HAVE_DLOPEN ) && !defined(__EMX__)
7742efff 226 // optain handle for main program
d236a959 227 return dlopen(NULL, RTLD_NOW/*RTLD_LAZY*/);
7742efff
KB
228#elif defined (HAVE_SHL_LOAD)
229 // shl_findsymbol with NULL handle looks up in main program
d236a959 230 return 0;
0868079c 231#else
58c837a4 232 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
7742efff 233 return 0;
7cc98b3e 234#endif
0868079c
KB
235}
236
a585ca5c 237/* static */
0b9ab0bd 238wxDllType wxDllLoader::LoadLibrary(const wxString & libname, bool *success)
a585ca5c 239{
0b9ab0bd
RL
240 wxDllType handle;
241 bool failed = FALSE;
7b0bfbb2 242
03e11df5 243#if defined(__WXMAC__) && !defined(__UNIX__)
0b9ab0bd
RL
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,
76a5e5d2 255 &((CFragConnectionID)handle),
0b9ab0bd
RL
256 &myMainAddr,
257 myErrName ) != noErr )
7cc98b3e 258 {
0b9ab0bd
RL
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;
7cc98b3e 265 }
0b9ab0bd 266
1a787c5d 267#elif defined(__WXPM__) || defined(__EMX__)
0b9ab0bd 268 char zError[256] = "";
c2ff79b1 269 wxDllOpen(zError, libname, handle);
0b9ab0bd
RL
270
271#else
93d2bf44 272 handle = wxDllOpen(libname);
0b9ab0bd
RL
273
274#endif
a585ca5c 275
7cc98b3e
VZ
276 if ( !handle )
277 {
f6bcfd97
BP
278 wxString msg(_("Failed to load shared library '%s'"));
279
280#ifdef HAVE_DLERROR
d0166913 281 const wxChar *err = dlerror();
0b9ab0bd 282 if( err )
f6bcfd97 283 {
0b9ab0bd
RL
284 failed = TRUE;
285 wxLogError( msg, err );
f6bcfd97 286 }
0b9ab0bd
RL
287#else
288 failed = TRUE;
289 wxLogSysError( msg, libname.c_str() );
290#endif
7cc98b3e
VZ
291 }
292
293 if ( success )
0b9ab0bd 294 *success = !failed;
7cc98b3e
VZ
295
296 return handle;
a585ca5c
KB
297}
298
752c7d6b
KB
299
300/* static */
0b9ab0bd 301void wxDllLoader::UnloadLibrary(wxDllType handle)
752c7d6b
KB
302{
303 wxDllClose(handle);
304}
305
a585ca5c 306/* static */
0b9ab0bd 307void *wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name, bool *success)
a585ca5c 308{
0b9ab0bd
RL
309 bool failed = FALSE;
310 void *symbol = 0;
a585ca5c 311
03e11df5 312#if defined(__WXMAC__) && !defined(__UNIX__)
0b9ab0bd
RL
313 Ptr symAddress;
314 CFragSymbolClass symClass;
315 Str255 symName;
7cc98b3e 316
c4e41ce3
SC
317 wxMacStringToPascal( name.c_str() , symName ) ;
318
76a5e5d2 319 if( FindSymbol( ((CFragConnectionID)dllHandle), symName, &symAddress, &symClass ) == noErr )
0b9ab0bd 320 symbol = (void *)symAddress;
7cc98b3e 321
0b9ab0bd 322#elif defined(__WXPM__) || defined(__EMX__)
c2ff79b1 323 wxDllGetSymbol(dllHandle, symbol);
0b9ab0bd 324
b7b35e50
VZ
325#else // Windows or Unix
326
f6bcfd97 327 // mb_str() is necessary in Unicode build
b7b35e50
VZ
328 //
329 // "void *" cast is needed by gcc 3.1 + w32api 1.4, don't ask me why
1c193821
JS
330#ifdef __WXWINCE__
331 symbol = (void *) wxDllGetSymbol(dllHandle, name.c_str());
332#else
333 symbol = (void *) wxDllGetSymbol(dllHandle, name.mb_str());
334#endif
0b9ab0bd 335
b7b35e50 336#endif // OS
7b0bfbb2
VZ
337
338 if ( !symbol )
339 {
0b9ab0bd 340#ifdef HAVE_DLERROR
d0166913 341 const wxChar *err = dlerror();
0b9ab0bd
RL
342 if( err )
343 {
ee682a94 344 wxLogError(wxT("%s"), err);
0b9ab0bd
RL
345 }
346#else
347 failed = TRUE;
7cc98b3e
VZ
348 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
349 name.c_str());
0b9ab0bd 350#endif
7b0bfbb2 351 }
0b9ab0bd
RL
352
353 if( success )
354 *success = !failed;
355
7b0bfbb2 356 return symbol;
7a4b9130
GL
357}
358
359// ---------------------------------------------------------------------------
360// wxLibraries (only one instance should normally exist)
361// ---------------------------------------------------------------------------
362
65fd5cb0 363wxLibraries::wxLibraries():m_loaded(wxKEY_STRING)
7a4b9130
GL
364{
365}
366
367wxLibraries::~wxLibraries()
368{
7b0bfbb2 369 wxNode *node = m_loaded.First();
7a4b9130 370
7b0bfbb2
VZ
371 while (node) {
372 wxLibrary *lib = (wxLibrary *)node->Data();
373 delete lib;
7a4b9130 374
7b0bfbb2
VZ
375 node = node->Next();
376 }
7a4b9130
GL
377}
378
379wxLibrary *wxLibraries::LoadLibrary(const wxString& name)
380{
0b9ab0bd 381 wxLibrary *lib;
7b0bfbb2 382 wxClassInfo *old_sm_first;
0b9ab0bd 383 wxNode *node = m_loaded.Find(name.GetData());
7a4b9130 384
c2ff79b1
DW
385 if (node != NULL)
386 return ((wxLibrary *)node->Data());
0b9ab0bd 387
7b0bfbb2
VZ
388 // If DLL shares data, this is necessary.
389 old_sm_first = wxClassInfo::sm_first;
390 wxClassInfo::sm_first = NULL;
391
7cc98b3e 392 wxString libname = ConstructLibraryName(name);
856d2e52 393
4dc2c3bb 394 bool success = FALSE;
7cc98b3e 395 wxDllType handle = wxDllLoader::LoadLibrary(libname, &success);
a585ca5c 396 if(success)
7b0bfbb2 397 {
a585ca5c
KB
398 lib = new wxLibrary(handle);
399 wxClassInfo::sm_first = old_sm_first;
0b9ab0bd 400
a585ca5c 401 m_loaded.Append(name.GetData(), lib);
7b0bfbb2 402 }
a585ca5c
KB
403 else
404 lib = NULL;
7b0bfbb2 405 return lib;
7a4b9130
GL
406}
407
408wxObject *wxLibraries::CreateObject(const wxString& path)
409{
7b0bfbb2
VZ
410 wxNode *node = m_loaded.First();
411 wxObject *obj;
7a4b9130 412
7b0bfbb2
VZ
413 while (node) {
414 obj = ((wxLibrary *)node->Data())->CreateObject(path);
415 if (obj)
416 return obj;
7a4b9130 417
7b0bfbb2
VZ
418 node = node->Next();
419 }
420 return NULL;
7a4b9130 421}
8a0d4cf6 422
229d3f1c
GD
423#endif // wxUSE_DYNLIB_CLASS && !wxUSE_DYNAMIC_LOADER
424
425#if defined(__DARWIN__) && (wxUSE_DYNLIB_CLASS || wxUSE_DYNAMIC_LOADER)
f11bdd03
GD
426// ---------------------------------------------------------------------------
427// For Darwin/Mac OS X
428// supply the sun style dlopen functions in terms of Darwin NS*
429// ---------------------------------------------------------------------------
430
229d3f1c
GD
431#include <stdio.h>
432#include <mach-o/dyld.h>
f11bdd03
GD
433
434static char dl_last_error[1024];
435
436static
f9ee64b1 437void TranslateError(const char *path, int number)
f11bdd03
GD
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
f9ee64b1
GD
452 index = number;
453 if (index > NUM_OFI_ERRORS - 1) {
454 index = NUM_OFI_ERRORS - 1;
f11bdd03 455 }
f9ee64b1 456 sprintf(dl_last_error, OFIErrorStrings[index], path, number);
f11bdd03
GD
457}
458
459const char *dlerror()
460{
461 return dl_last_error;
462}
463
1b0674f7 464void *dlopen(const char *path, int WXUNUSED(mode) /* mode is ignored */)
f11bdd03
GD
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 {
f9ee64b1 473 TranslateError(path, dyld_result);
f11bdd03
GD
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.
f9ee64b1 479 handle = NSLinkModule(ofile, path, NSLINKMODULE_OPTION_BINDNOW);
f11bdd03
GD
480 }
481
482 return handle;
483}
484
f9ee64b1 485int dlclose(void *handle)
f11bdd03 486{
a8522481 487 NSUnLinkModule( handle, NSUNLINKMODULE_OPTION_NONE);
f11bdd03
GD
488 return 0;
489}
490
0154fd2c 491void *dlsym(void *handle, const char *symbol)
f11bdd03
GD
492{
493 void *addr;
0154fd2c
SC
494
495 NSSymbol nsSymbol = NSLookupSymbolInModule( handle , symbol ) ;
f11bdd03 496
0154fd2c
SC
497 if ( nsSymbol)
498 {
499 addr = NSAddressOfSymbol(nsSymbol);
f11bdd03 500 }
0154fd2c
SC
501 else
502 {
503 addr = NULL;
f11bdd03
GD
504 }
505 return addr;
506}
507
229d3f1c 508#endif // defined(__DARWIN__) && (wxUSE_DYNLIB_CLASS || wxUSE_DYNAMIC_LOADER)