1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/common/dynlib.cpp
3// Purpose:     Dynamic library management
4// Author:      Guilhem Lavaux
5// Modified by:
6// Created:     20/07/98
7// RCS-ID:      $Id: dynlib.cpp 41807 2006-10-09 15:58:56Z VZ $
8// Copyright:   (c) 1998 Guilhem Lavaux
9//                  2000-2005 Vadim Zeitlin
10// Licence:     wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
13//FIXME:  This class isn't really common at all, it should be moved into
14//        platform dependent files (already done for Windows and Unix)
15
16// ============================================================================
17// declarations
18// ============================================================================
19
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
23
24#include  "wx/wxprec.h"
25
26#ifdef __BORLANDC__
27    #pragma hdrstop
28#endif
29
30#if wxUSE_DYNLIB_CLASS
31
32#include "wx/dynlib.h"
33
34#ifndef WX_PRECOMP
35    #include "wx/intl.h"
36    #include "wx/log.h"
37    #include "wx/app.h"
38    #include "wx/utils.h"
39#endif //WX_PRECOMP
40
41#include "wx/filefn.h"
42#include "wx/filename.h"        // for SplitPath()
43#include "wx/platinfo.h"
44
45#include "wx/arrimpl.cpp"
46
47#if defined(__WXMAC__)
48    #include "wx/mac/private.h"
49#endif
50
51WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray)
52
53// ============================================================================
54// implementation
55// ============================================================================
56
57// ---------------------------------------------------------------------------
58// wxDynamicLibrary
59// ---------------------------------------------------------------------------
60
61#if defined(__WXPM__) || defined(__EMX__)
62    const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll");
63#elif defined(__WXMAC__) && !defined(__DARWIN__)
64    const wxChar *wxDynamicLibrary::ms_dllext = wxEmptyString;
65#endif
66
67// for MSW/Unix it is defined in platform-specific file
68#if !(defined(__WXMSW__) || defined(__UNIX__)) || defined(__EMX__)
69
70wxDllType wxDynamicLibrary::GetProgramHandle()
71{
72   wxFAIL_MSG( wxT("GetProgramHandle() is not implemented under this platform"));
73   return 0;
74}
75
76#endif // __WXMSW__ || __UNIX__
77
78
79bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags)
80{
81    wxASSERT_MSG(m_handle == 0, _T("Library already loaded."));
82
83    // add the proper extension for the DLL ourselves unless told not to
84    wxString libname = libnameOrig;
85    if ( !(flags & wxDL_VERBATIM) )
86    {
87        // and also check that the libname doesn't already have it
88        wxString ext;
89        wxFileName::SplitPath(libname, NULL, NULL, &ext);
90        if ( ext.empty() )
91        {
92            libname += GetDllExt();
93        }
94    }
95
96    // different ways to load a shared library
97    //
98    // FIXME: should go to the platform-specific files!
99#if defined(__WXMAC__) && !defined(__DARWIN__)
100    FSSpec      myFSSpec;
101    Ptr         myMainAddr;
102    Str255      myErrName;
103
104    wxMacFilename2FSSpec( libname , &myFSSpec );
105
106    if( GetDiskFragment( &myFSSpec,
107                         0,
108                         kCFragGoesToEOF,
109                         "\p",
110                         kPrivateCFragCopy,
111                         &m_handle,
112                         &myMainAddr,
113                         myErrName ) != noErr )
114    {
115        wxLogSysError( _("Failed to load shared library '%s' Error '%s'"),
116                       libname.c_str(),
117                       wxMacMakeStringFromPascal( myErrName ).c_str() );
118        m_handle = 0;
119    }
120
121#elif defined(__WXPM__) || defined(__EMX__)
122    char err[256] = "";
123    DosLoadModule(err, sizeof(err), (PSZ)libname.c_str(), &m_handle);
124#else // this should be the only remaining branch eventually
125    m_handle = RawLoad(libname, flags);
126#endif
127
128    if ( m_handle == 0 )
129    {
130#ifdef wxHAVE_DYNLIB_ERROR
131        Error();
132#else
133        wxLogSysError(_("Failed to load shared library '%s'"), libname.c_str());
134#endif
135    }
136
137    return IsLoaded();
138}
139
140// for MSW and Unix this is implemented in the platform-specific file
141//
142// TODO: move the rest to os2/dlpm.cpp and mac/dlmac.cpp!
143#if (!defined(__WXMSW__) && !defined(__UNIX__)) || defined(__EMX__)
144
145/* static */
146void wxDynamicLibrary::Unload(wxDllType handle)
147{
148#if defined(__OS2__) || defined(__EMX__)
149    DosFreeModule( handle );
150#elif defined(__WXMAC__) && !defined(__DARWIN__)
151    CloseConnection( (CFragConnectionID*) &handle );
152#else
153    #error  "runtime shared lib support not implemented"
154#endif
155}
156
157#endif // !(__WXMSW__ || __UNIX__)
158
159void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const
160{
161    wxCHECK_MSG( IsLoaded(), NULL,
162                 _T("Can't load symbol from unloaded library") );
163
164    void    *symbol = 0;
165
166    wxUnusedVar(symbol);
167#if defined(__WXMAC__) && !defined(__DARWIN__)
168    Ptr                 symAddress;
169    CFragSymbolClass    symClass;
170    Str255              symName;
171#if TARGET_CARBON
172    c2pstrcpy( (StringPtr) symName, name.fn_str() );
173#else
174    strcpy( (char *)symName, name.fn_str() );
175    c2pstr( (char *)symName );
176#endif
177    if( FindSymbol( m_handle, symName, &symAddress, &symClass ) == noErr )
178        symbol = (void *)symAddress;
179#elif defined(__WXPM__) || defined(__EMX__)
180    DosQueryProcAddr( m_handle, 1L, (PSZ)name.c_str(), (PFN*)symbol );
181#else
182    symbol = RawGetSymbol(m_handle, name);
183#endif
184
185    if ( success )
186        *success = symbol != NULL;
187
188    return symbol;
189}
190
191void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const
192{
193    void *symbol = DoGetSymbol(name, success);
194    if ( !symbol )
195    {
196#ifdef wxHAVE_DYNLIB_ERROR
197        Error();
198#else
199        wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"),
200                      name.c_str());
201#endif
202    }
203
204    return symbol;
205}
206
207// ----------------------------------------------------------------------------
208// informational methods
209// ----------------------------------------------------------------------------
210
211/*static*/
212wxString
213wxDynamicLibrary::CanonicalizeName(const wxString& name,
214                                   wxDynamicLibraryCategory cat)
215{
216    wxString nameCanonic;
217
218    // under Unix the library names usually start with "lib" prefix, add it
219#if defined(__UNIX__) && !defined(__EMX__)
220    switch ( cat )
221    {
222        default:
223            wxFAIL_MSG( _T("unknown wxDynamicLibraryCategory value") );
224            // fall through
225
226        case wxDL_MODULE:
227            // don't do anything for modules, their names are arbitrary
228            break;
229
230        case wxDL_LIBRARY:
231            // library names should start with "lib" under Unix
232            nameCanonic = _T("lib");
233            break;
234    }
235#else // !__UNIX__
236    wxUnusedVar(cat);
237#endif // __UNIX__/!__UNIX__
238
239    nameCanonic << name << GetDllExt();
240    return nameCanonic;
241}
242
243/*static*/
244wxString wxDynamicLibrary::CanonicalizePluginName(const wxString& name,
245                                                  wxPluginCategory cat)
246{
247    wxString suffix;
248    if ( cat == wxDL_PLUGIN_GUI )
249    {
250        suffix = wxPlatformInfo::Get().GetPortIdShortName();
251    }
252#if wxUSE_UNICODE
253    suffix << _T('u');
254#endif
255#ifdef __WXDEBUG__
256    suffix << _T('d');
257#endif
258
259    if ( !suffix.empty() )
260        suffix = wxString(_T("_")) + suffix;
261
262#define WXSTRINGIZE(x)  #x
263#if defined(__UNIX__) && !defined(__EMX__)
264    #if (wxMINOR_VERSION % 2) == 0
265        #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y)
266    #else
267        #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) "." WXSTRINGIZE(z)
268    #endif
269#else
270    #if (wxMINOR_VERSION % 2) == 0
271        #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y)
272    #else
273        #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) WXSTRINGIZE(z)
274    #endif
275#endif
276
277    suffix << wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION, wxMINOR_VERSION,
278                                           wxRELEASE_NUMBER));
279#undef wxDLLVER
280#undef WXSTRINGIZE
281
282#ifdef __WINDOWS__
283    // Add compiler identification:
284    #if defined(__GNUG__)
285        suffix << _T("_gcc");
286    #elif defined(__VISUALC__)
287        suffix << _T("_vc");
288    #elif defined(__WATCOMC__)
289        suffix << _T("_wat");
290    #elif defined(__BORLANDC__)
291        suffix << _T("_bcc");
292    #endif
293#endif
294
295    return CanonicalizeName(name + suffix, wxDL_MODULE);
296}
297
298/*static*/
299wxString wxDynamicLibrary::GetPluginsDirectory()
300{
301#ifdef __UNIX__
302    wxString format = wxGetInstallPrefix();
303    wxString dir;
304    format << wxFILE_SEP_PATH
305           << wxT("lib") << wxFILE_SEP_PATH
306           << wxT("wx") << wxFILE_SEP_PATH
307#if (wxMINOR_VERSION % 2) == 0
308           << wxT("%i.%i");
309    dir.Printf(format.c_str(), wxMAJOR_VERSION, wxMINOR_VERSION);
310#else
311           << wxT("%i.%i.%i");
312    dir.Printf(format.c_str(),
313               wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER);
314#endif
315    return dir;
316
317#else // ! __UNIX__
318    return wxEmptyString;
319#endif
320}
321
322
323#endif // wxUSE_DYNLIB_CLASS
324