summaryrefslogtreecommitdiff
path: root/library/qlibrary.cpp
Unidiff
Diffstat (limited to 'library/qlibrary.cpp') (more/less context) (show whitespace changes)
-rw-r--r--library/qlibrary.cpp437
1 files changed, 437 insertions, 0 deletions
diff --git a/library/qlibrary.cpp b/library/qlibrary.cpp
new file mode 100644
index 0000000..4aabbc5
--- a/dev/null
+++ b/library/qlibrary.cpp
@@ -0,0 +1,437 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21
22#include "qlibrary_p.h"
23
24// uncomment this to get error messages
25//#define QT_DEBUG_COMPONENT 1
26// uncomment this to get error and success messages
27//#define QT_DEBUG_COMPONENT 2
28
29#ifndef QT_DEBUG_COMPONENT
30# if defined(QT_DEBUG)
31# define QT_DEBUG_COMPONENT 1
32# endif
33#endif
34
35#ifndef QT_NO_COMPONENT
36
37// KAI C++ has at the moment problems with unloading the Qt plugins. So don't
38// unload them as a workaround for now.
39#if defined(Q_CC_KAI) || defined(Q_OS_MAC)
40#define QT_NO_LIBRARY_UNLOAD
41#endif
42
43#if defined(Q_WS_WIN) && !defined(QT_MAKEDLL)
44#define QT_NO_LIBRARY_UNLOAD
45#endif
46
47/* Platform independent QLibraryPrivate implementations */
48#ifndef QT_LITE_COMPONENT
49
50#include "qtimer.h"
51
52extern Q_EXPORT QApplication *qApp;
53
54QLibraryPrivate::QLibraryPrivate( QLibrary *lib )
55 : QObject( 0, lib->library().latin1() ), pHnd( 0 ), libIface( 0 ), unloadTimer( 0 ), library( lib )
56{
57}
58
59QLibraryPrivate::~QLibraryPrivate()
60{
61 if ( libIface )
62 libIface->release();
63 killTimer();
64}
65
66/*
67 Only components that implement the QLibraryInterface can
68 be unloaded automatically.
69*/
70void QLibraryPrivate::tryUnload()
71{
72 if ( library->policy() == QLibrary::Manual || !pHnd || !libIface )
73 return;
74
75 if ( !libIface->canUnload() )
76 return;
77
78#if defined(QT_DEBUG_COMPONENT) && QT_DEBUG_COMPONENT == 2
79 if ( library->unload() )
80 qDebug( "%s has been automatically unloaded", library->library().latin1() );
81#else
82 library->unload();
83#endif
84}
85
86#else // QT_LITE_COMPOINENT
87
88QLibraryPrivate::QLibraryPrivate( QLibrary *lib )
89 : pHnd( 0 ), libIface( 0 ), library( lib )
90{
91}
92
93#endif // QT_LITE_COMPOINENT
94
95void QLibraryPrivate::startTimer()
96{
97#ifndef QT_LITE_COMPONENT
98 unloadTimer = new QTimer( this );
99 connect( unloadTimer, SIGNAL( timeout() ), this, SLOT( tryUnload() ) );
100 unloadTimer->start( 5000, FALSE );
101#endif
102}
103
104void QLibraryPrivate::killTimer()
105{
106#ifndef QT_LITE_COMPONENT
107 delete unloadTimer;
108 unloadTimer = 0;
109#endif
110}
111
112/*!
113 \class QLibrary qlibrary.h
114
115 \brief The QLibrary class provides a wrapper for handling shared libraries.
116
117 This class is temporarily copied from Qt 3.0.
118*/
119
120/*!
121 \enum QLibrary::Policy
122
123 This enum type defines the various policies a QLibrary can have with respect to
124 loading and unloading the shared library.
125
126 The \e policy can be:
127
128 \value Delayed The library get's loaded as soon as needed and unloaded in the destructor
129 \value Immediately The library is loaded immediately and unloaded in the destructor
130 \value Manual Like delayed, and library has to be unloaded manually
131*/
132
133/*!
134 Creates a QLibrary object for the shared library \a filename.
135 The library get's loaded if \a pol is Immediately.
136
137 Note that \a filename does not need to include the (platform specific)
138 file extension, so calling
139
140 \code
141 QLibrary lib( "mylib" );
142 \endcode
143
144 would be equivalent to
145
146 \code
147 QLibrary lib( "mylib.dll" );
148 \endcode
149
150 on Windows. But \e "mylib.dll" will obviously not work on other platforms.
151
152 \sa setPolicy(), unload()
153*/
154QLibrary::QLibrary( const QString& filename, Policy pol )
155 : libfile( filename ), libPol( pol ), entry( 0 )
156{
157 d = new QLibraryPrivate( this );
158 if ( pol == Immediately )
159 load();
160}
161
162/*!
163 Deletes the QLibrary object.
164 The library will be unloaded if the policy is not Manual.
165
166 \sa unload(), setPolicy()
167*/
168QLibrary::~QLibrary()
169{
170 if ( libPol == Manual || !unload() ) {
171 if ( entry ) {
172 entry->release();
173 entry = 0;
174 }
175 }
176 delete d;
177}
178
179void QLibrary::createInstanceInternal()
180{
181 if ( libfile.isEmpty() )
182 return;
183
184 if ( !d->pHnd ) {
185 ASSERT( entry == 0 );
186 load();
187 }
188
189 if ( d->pHnd && !entry ) {
190#if defined(QT_DEBUG_COMPONENT) && QT_DEBUG_COMPONENT == 2
191 qWarning( "%s has been loaded.", library().latin1() );
192#endif
193 typedef QUnknownInterface* (*UCMInstanceProc)();
194 UCMInstanceProc ucmInstanceProc;
195 ucmInstanceProc = (UCMInstanceProc) resolve( "ucm_instantiate" );
196 entry = ucmInstanceProc ? ucmInstanceProc() : 0;
197 if ( entry ) {
198 entry->queryInterface( IID_QLibrary, (QUnknownInterface**)&d->libIface);
199 if ( d->libIface ) {
200 if ( !d->libIface->init() ) {
201#if defined(QT_DEBUG_COMPONENT)
202 qWarning( "%s: QLibraryInterface::init() failed.", library().latin1() );
203#endif
204 unload();
205 return;
206 }
207
208 d->killTimer();
209 if ( libPol != Manual )
210 d->startTimer();
211 }
212 } else {
213#if defined(QT_DEBUG_COMPONENT)
214 qWarning( "%s: No interface implemented.", library().latin1() );
215#endif
216 unload();
217 }
218 }
219}
220
221/*!
222 Returns the address of the exported symbol \a symb. The library gets
223 loaded if necessary. The function returns NULL if the symbol could
224 not be resolved, or if loading the library failed.
225
226 \code
227 typedef int (*addProc)( int, int );
228
229 addProc add = (addProc) library->resolve( "add" );
230 if ( add )
231 return add( 5, 8 );
232 else
233 return 5 + 8;
234 \endcode
235
236 \sa queryInterface()
237*/
238void *QLibrary::resolve( const char* symb )
239{
240 if ( !d->pHnd )
241 load();
242 if ( !d->pHnd )
243 return 0;
244
245 void *address = d->resolveSymbol( symb );
246 if ( !address ) {
247#if defined(QT_DEBUG_COMPONENT)
248 // resolveSymbol() might give a warning; so let that warning look so fatal
249 qWarning( QString("Trying to resolve symbol \"_%1\" instead").arg( symb ) );
250#endif
251 address = d->resolveSymbol( QString( "_" ) + symb );
252 }
253 return address;
254}
255
256/*!
257 \overload
258
259 Loads the library \a filename and returns the address of the exported symbol \a symb.
260 Note that like for the constructor, \a filename does not need to include the (platform specific)
261 file extension. The library staying loaded until the process exits.
262
263 The function returns a null pointer if the symbol could not be resolved or if loading
264 the library failed.
265*/
266void *QLibrary::resolve( const QString &filename, const char *symb )
267{
268 QLibrary lib( filename, Manual );
269 return lib.resolve( symb );
270}
271
272/*!
273 Returns whether the library is loaded.
274
275 \sa unload()
276*/
277bool QLibrary::isLoaded() const
278{
279 return d->pHnd != 0;
280}
281
282/*!
283 Loads the library.
284*/
285bool QLibrary::load()
286{
287 return d->loadLibrary();
288}
289
290/*!
291 Releases the component and unloads the library when successful.
292 Returns TRUE if the library could be unloaded, otherwise FALSE.
293 If the component implements the QLibraryInterface, the cleanup()
294 function of this interface will be called. The unloading will be
295 cancelled if the subsequent call to canUnload() returns FALSE.
296
297 This function gets called automatically in the destructor if
298 the policy is not Manual.
299
300 \warning
301 If \a force is set to TRUE, the library gets unloaded at any cost,
302 which is in most cases a segmentation fault, so you should know what
303 you're doing!
304
305 \sa queryInterface(), resolve()
306*/
307bool QLibrary::unload( bool force )
308{
309 if ( !d->pHnd )
310 return TRUE;
311
312 if ( entry ) {
313 if ( d->libIface ) {
314 d->libIface->cleanup();
315
316 bool can = d->libIface->canUnload();
317 can = ( d->libIface->release() <= 1 ) && can;
318 // the "entry" member must be the last reference to the component
319 if ( can || force ) {
320 d->libIface = 0;
321 } else {
322#if defined(QT_DEBUG_COMPONENT)
323 qWarning( "%s prevents unloading!", library().latin1() );
324#endif
325 d->libIface->addRef();
326 return FALSE;
327 }
328 }
329
330 if ( entry->release() ) {
331#if defined(QT_DEBUG_COMPONENT)
332 qWarning( "%s is still in use!", library().latin1() );
333#endif
334 if ( force ) {
335 delete entry;
336 } else {
337 entry->addRef();
338 return FALSE;
339 }
340 }
341 d->killTimer();
342
343 entry = 0;
344 }
345
346// ### this is a hack to solve problems with plugin unloading und KAI C++
347// (other compilers may have the same problem)
348#if !defined(QT_NO_LIBRARY_UNLOAD)
349 if ( !d->freeLibrary() ) {
350#if defined(QT_DEBUG_COMPONENT)
351 qWarning( "%s could not be unloaded.", library().latin1() );
352#endif
353 return FALSE;
354#else
355 return TRUE;
356#endif
357#if !defined(QT_NO_LIBRARY_UNLOAD)
358 }
359
360#if defined(QT_DEBUG_COMPONENT) && QT_DEBUG_COMPONENT == 2
361 qWarning( "%s has been unloaded.", library().latin1() );
362#endif
363
364 d->pHnd = 0;
365 return TRUE;
366#endif
367}
368
369/*!
370 Sets the current policy to \a pol.
371 The library is loaded if \a pol is set to Immediately.
372*/
373void QLibrary::setPolicy( Policy pol )
374{
375 libPol = pol;
376
377 if ( libPol == Immediately && !d->pHnd )
378 load();
379}
380
381/*!
382 Returns the current policy.
383
384 \sa setPolicy()
385*/
386QLibrary::Policy QLibrary::policy() const
387{
388 return libPol;
389}
390
391/*!
392 Returns the filename of the shared library this QLibrary object handles,
393 including the platform specific file extension.
394
395 \code
396 QLibrary lib( "mylib" );
397 QString str = lib.library();
398 \endcode
399
400 will set \e str to "mylib.dll" on Windows, and "libmylib.so" on Linux.
401*/
402QString QLibrary::library() const
403{
404 if ( libfile.isEmpty() )
405 return libfile;
406
407 QString filename = libfile;
408#if defined(Q_WS_WIN)
409 if ( filename.find( ".dll" ) == -1 )
410 filename += ".dll";
411#elif defined(Q_OS_MACX)
412 if ( filename.find( ".dylib" ) == -1 )
413 filename += ".dylib";
414#else
415 if ( filename.find( ".so" ) == -1 )
416 filename = QString( "lib%1.so" ).arg( filename );
417#endif
418
419 return filename;
420}
421
422/*!
423 Forwards the query to the component and returns the result. \a request and \a iface
424 are propagated to the component's queryInterface implementation.
425
426 The library gets loaded if necessary.
427*/
428QRESULT QLibrary::queryInterface( const QUuid& request, QUnknownInterface** iface )
429{
430 if ( !entry ) {
431 createInstanceInternal();
432 }
433
434 return entry ? entry->queryInterface( request, iface ) : QE_NOINTERFACE;
435}
436
437#endif // QT_NO_COMPONENT