]> git.saurik.com Git - wxWidgets.git/blob - src/common/dynlib.cpp
Committing in .
[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 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__)
80 void *dlopen(const char *path, int mode /* mode is ignored */);
81 void *dlsym(void *handle, const char *symbol);
82 int dlclose(void *handle);
83 const 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
111 wxLibraries 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
119 static 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
131 wxLibrary::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
145 wxLibrary::~wxLibrary()
146 {
147 if ( m_handle )
148 {
149 wxDllClose(m_handle);
150 }
151 }
152
153 wxObject *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
163 void 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
186 void *wxLibrary::GetSymbol(const wxString& symbname)
187 {
188 return wxDllLoader::GetSymbol(m_handle, symbname);
189 }
190
191 // ---------------------------------------------------------------------------
192 // wxDllLoader
193 // ---------------------------------------------------------------------------
194
195 /* static */
196 wxString 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 */
214 wxDllType
215 wxDllLoader::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 */
230 wxDllType
231 wxDllLoader::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 */
296 void
297 wxDllLoader::UnloadLibrary(wxDllType handle)
298 {
299 wxDllClose(handle);
300 }
301
302 /* static */
303 void *
304 wxDllLoader::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
341 wxLibraries::wxLibraries():m_loaded(wxKEY_STRING)
342 {
343 }
344
345 wxLibraries::~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
357 wxLibrary *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
419 wxObject *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