]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/dynlib.cpp
merged MapBitmap() from 2.2 branch
[wxWidgets.git] / src / common / dynlib.cpp
... / ...
CommitLineData
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
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
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#include "wx/tokenzr.h"
41
42// ----------------------------------------------------------------------------
43// conditional compilation
44// ----------------------------------------------------------------------------
45
46#if defined(__WXPM__) || defined(__EMX__)
47# define INCL_DOS
48# include <os2.h>
49# define wxDllOpen(error, lib, handle) DosLoadModule(error, sizeof(error), lib, &handle)
50# define wxDllGetSymbol(handle, modaddr) DosQueryProcAddr(handle, 1L, NULL, (PFN*)modaddr)
51# define wxDllClose(handle) DosFreeModule(handle)
52#elif defined(HAVE_DLOPEN)
53 // note about dlopen() flags: we use RTLD_NOW to have more Windows-like
54 // behaviour (Win won't let you load a library with missing symbols) and
55 // RTLD_GLOBAL because it is needed sometimes and probably doesn't hurt
56 // otherwise. On True64-Unix RTLD_GLOBAL is not allowed and on VMS the
57 // second argument on dlopen is ignored.
58#ifdef __VMS
59# define wxDllOpen(lib) dlopen(lib.fn_str(), 0 )
60#elif defined( __osf__ )
61# define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY )
62#else
63# define wxDllOpen(lib) dlopen(lib.fn_str(), RTLD_LAZY | RTLD_GLOBAL)
64#endif
65#define wxDllGetSymbol(handle, name) dlsym(handle, name)
66# define wxDllClose dlclose
67#elif defined(HAVE_SHL_LOAD)
68# define wxDllOpen(lib) shl_load(lib.fn_str(), BIND_DEFERRED, 0)
69# define wxDllClose shl_unload
70
71 static inline void *wxDllGetSymbol(shl_t handle, const wxString& name)
72 {
73 void *sym;
74 if ( shl_findsym(&handle, name.mb_str(), TYPE_UNDEFINED, &sym) == 0 )
75 return sym;
76 else
77 return (void *)0;
78 }
79#elif defined(__APPLE__) && defined(__UNIX__)
80void *dlopen(const char *path, int mode /* mode is ignored */);
81void *dlsym(void *handle, const char *symbol);
82int dlclose(void *handle);
83const char *dlerror(void);
84
85# define wxDllOpen(lib) dlopen(lib.fn_str(), 0)
86# define wxDllGetSymbol(handle, name) dlsym(handle, name)
87# define wxDllClose dlclose
88#elif defined(__WINDOWS__)
89 // using LoadLibraryEx under Win32 to avoid name clash with LoadLibrary
90# ifdef __WIN32__
91#ifdef _UNICODE
92# define wxDllOpen(lib) ::LoadLibraryExW(lib, 0, 0)
93#else
94# define wxDllOpen(lib) ::LoadLibraryExA(lib, 0, 0)
95#endif
96# else // Win16
97# define wxDllOpen(lib) ::LoadLibrary(lib)
98# endif // Win32/16
99# define wxDllGetSymbol(handle, name) ::GetProcAddress(handle, name)
100# define wxDllClose ::FreeLibrary
101#elif defined(__WXMAC__)
102# define wxDllClose(handle) CloseConnection(&handle)
103#else
104# error "Don't know how to load shared libraries on this platform."
105#endif // OS
106
107// ---------------------------------------------------------------------------
108// Global variables
109// ---------------------------------------------------------------------------
110
111wxLibraries wxTheLibraries;
112
113// ============================================================================
114// implementation
115// ============================================================================
116
117// construct the full name from the base shared object name: adds a .dll
118// suffix under Windows or .so under Unix
119static wxString ConstructLibraryName(const wxString& basename)
120{
121 wxString fullname;
122 fullname << basename << wxDllLoader::GetDllExt();
123
124 return fullname;
125}
126
127// ---------------------------------------------------------------------------
128// wxLibrary (one instance per dynamic library)
129// ---------------------------------------------------------------------------
130
131wxLibrary::wxLibrary(wxDllType handle)
132{
133 typedef wxClassInfo *(*t_get_first)(void);
134 t_get_first get_first;
135
136 m_handle = handle;
137
138 // Some system may use a local heap for library.
139 get_first = (t_get_first)GetSymbol("wxGetClassFirst");
140 // It is a wxWindows DLL.
141 if (get_first)
142 PrepareClasses(get_first());
143}
144
145wxLibrary::~wxLibrary()
146{
147 if ( m_handle )
148 {
149 wxDllClose(m_handle);
150 }
151}
152
153wxObject *wxLibrary::CreateObject(const wxString& name)
154{
155 wxClassInfo *info = (wxClassInfo *)classTable.Get(name);
156
157 if (!info)
158 return NULL;
159
160 return info->CreateObject();
161}
162
163void wxLibrary::PrepareClasses(wxClassInfo *first)
164{
165 // Index all class infos by their class name
166 wxClassInfo *info = first;
167 while (info)
168 {
169 if (info->m_className)
170 classTable.Put(info->m_className, (wxObject *)info);
171 info = (wxClassInfo *)info->GetNext();
172 }
173
174 // Set base pointers for each wxClassInfo
175 info = first;
176 while (info)
177 {
178 if (info->GetBaseClassName1())
179 info->m_baseInfo1 = (wxClassInfo *)classTable.Get(info->GetBaseClassName1());
180 if (info->GetBaseClassName2())
181 info->m_baseInfo2 = (wxClassInfo *)classTable.Get(info->GetBaseClassName2());
182 info = info->m_next;
183 }
184}
185
186void *wxLibrary::GetSymbol(const wxString& symbname)
187{
188 return wxDllLoader::GetSymbol(m_handle, symbname);
189}
190
191// ---------------------------------------------------------------------------
192// wxDllLoader
193// ---------------------------------------------------------------------------
194
195/* static */
196wxString wxDllLoader::GetDllExt()
197{
198 wxString ext;
199
200#if defined(__WINDOWS__) || defined(__WXPM__) || defined(__EMX__)
201 ext = _T(".dll");
202#elif defined(__UNIX__)
203# if defined(__HPUX__)
204 ext = _T(".sl");
205# else //__HPUX__
206 ext = _T(".so");
207# endif //__HPUX__
208#endif
209
210 return ext;
211}
212
213/* static */
214wxDllType
215wxDllLoader::GetProgramHandle(void)
216{
217#if defined( HAVE_DLOPEN ) && !defined(__EMX__)
218 // optain handle for main program
219 return dlopen(NULL, RTLD_NOW/*RTLD_LAZY*/);
220#elif defined (HAVE_SHL_LOAD)
221 // shl_findsymbol with NULL handle looks up in main program
222 return 0;
223#else
224 wxFAIL_MSG( wxT("This method is not implemented under Windows or OS/2"));
225 return 0;
226#endif
227}
228
229/* static */
230wxDllType
231wxDllLoader::LoadLibrary(const wxString & libname, bool *success)
232{
233 wxDllType handle;
234
235#if defined(__WXMAC__) && !defined(__UNIX__)
236 FSSpec myFSSpec ;
237 Ptr myMainAddr ;
238 Str255 myErrName ;
239
240 wxMacFilename2FSSpec( libname , &myFSSpec ) ;
241 if (GetDiskFragment( &myFSSpec , 0 , kCFragGoesToEOF , "\p" , kPrivateCFragCopy , &handle , &myMainAddr ,
242 myErrName ) != noErr )
243 {
244 p2cstr( myErrName ) ;
245 wxLogSysError( _("Failed to load shared library '%s' Error '%s'") , libname.c_str() , (char*)myErrName ) ;
246 handle = NULL ;
247 }
248#elif defined(__WXPM__) || defined(__EMX__)
249 char zError[256] = "";
250 wxDllOpen(zError, libname, handle);
251#else // !Mac
252 handle = wxDllOpen(libname);
253#endif // OS
254
255 if ( !handle )
256 {
257 wxString msg(_("Failed to load shared library '%s'"));
258
259#ifdef HAVE_DLERROR
260 const char *errmsg = dlerror();
261 if ( errmsg )
262 {
263 // the error string format is "libname: ...", but we already have
264 // libname, so cut it off
265 const char *p = strchr(errmsg, ':');
266 if ( p )
267 {
268 if ( *++p == ' ' )
269 p++;
270 }
271 else
272 {
273 p = errmsg;
274 }
275
276 msg += _T(" (%s)");
277 wxLogError(msg, libname.c_str(), p);
278 }
279 else
280#endif // HAVE_DLERROR
281 {
282 wxLogSysError(msg, libname.c_str());
283 }
284 }
285
286 if ( success )
287 {
288 *success = handle != 0;
289 }
290
291 return handle;
292}
293
294
295/* static */
296void
297wxDllLoader::UnloadLibrary(wxDllType handle)
298{
299 wxDllClose(handle);
300}
301
302/* static */
303void *
304wxDllLoader::GetSymbol(wxDllType dllHandle, const wxString &name)
305{
306 void *symbol = NULL; // return value
307
308#if defined(__WXMAC__) && !defined(__UNIX__)
309 Ptr symAddress ;
310 CFragSymbolClass symClass ;
311 Str255 symName ;
312
313#if TARGET_CARBON
314 c2pstrcpy( (StringPtr) symName , name ) ;
315#else
316 strcpy( (char *) symName , name ) ;
317 c2pstr( (char *) symName ) ;
318#endif
319
320 if ( FindSymbol( dllHandle , symName , &symAddress , &symClass ) == noErr )
321 symbol = (void *)symAddress ;
322#elif defined( __WXPM__ ) || defined(__EMX__)
323 wxDllGetSymbol(dllHandle, symbol);
324#else
325 // mb_str() is necessary in Unicode build
326 symbol = wxDllGetSymbol(dllHandle, name.mb_str());
327#endif
328
329 if ( !symbol )
330 {
331 wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
332 name.c_str());
333 }
334 return symbol;
335}
336
337// ---------------------------------------------------------------------------
338// wxLibraries (only one instance should normally exist)
339// ---------------------------------------------------------------------------
340
341wxLibraries::wxLibraries():m_loaded(wxKEY_STRING)
342{
343}
344
345wxLibraries::~wxLibraries()
346{
347 wxNode *node = m_loaded.First();
348
349 while (node) {
350 wxLibrary *lib = (wxLibrary *)node->Data();
351 delete lib;
352
353 node = node->Next();
354 }
355}
356
357wxLibrary *wxLibraries::LoadLibrary(const wxString& name)
358{
359 wxNode *node;
360 wxLibrary *lib;
361 wxClassInfo *old_sm_first;
362
363#if defined(__VISAGECPP__)
364 node = m_loaded.Find(name.GetData());
365 if (node != NULL)
366 return ((wxLibrary *)node->Data());
367#else // !OS/2
368 if ( (node = m_loaded.Find(name.GetData())) != NULL)
369 return ((wxLibrary *)node->Data());
370#endif
371 // If DLL shares data, this is necessary.
372 old_sm_first = wxClassInfo::sm_first;
373 wxClassInfo::sm_first = NULL;
374
375 wxString libname = ConstructLibraryName(name);
376
377/*
378 Unix automatically builds that library name, at least for dlopen()
379*/
380#if 0
381#if defined(__UNIX__)
382 // found the first file in LD_LIBRARY_PATH with this name
383 wxString libPath("/lib:/usr/lib"); // system path first
384 const char *envLibPath = getenv("LD_LIBRARY_PATH");
385 if ( envLibPath )
386 libPath << wxT(':') << envLibPath;
387 wxStringTokenizer tokenizer(libPath, wxT(':'));
388 while ( tokenizer.HasMoreToken() )
389 {
390 wxString fullname(tokenizer.NextToken());
391
392 fullname << wxT('/') << libname;
393 if ( wxFileExists(fullname) )
394 {
395 libname = fullname;
396
397 // found the library
398 break;
399 }
400 }
401 //else: not found in the path, leave the name as is (secutiry risk?)
402
403#endif // __UNIX__
404#endif
405
406 bool success = FALSE;
407 wxDllType handle = wxDllLoader::LoadLibrary(libname, &success);
408 if(success)
409 {
410 lib = new wxLibrary(handle);
411 wxClassInfo::sm_first = old_sm_first;
412 m_loaded.Append(name.GetData(), lib);
413 }
414 else
415 lib = NULL;
416 return lib;
417}
418
419wxObject *wxLibraries::CreateObject(const wxString& path)
420{
421 wxNode *node = m_loaded.First();
422 wxObject *obj;
423
424 while (node) {
425 obj = ((wxLibrary *)node->Data())->CreateObject(path);
426 if (obj)
427 return obj;
428
429 node = node->Next();
430 }
431 return NULL;
432}
433
434#endif // wxUSE_DYNLIB_CLASS