source: trunk/src/corelib/plugin/qpluginloader.cpp@ 98

Last change on this file since 98 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 11.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qplatformdefs.h"
43
44#include "qplugin.h"
45#include "qpluginloader.h"
46#include <qfileinfo.h>
47#include "qlibrary_p.h"
48#include "qdebug.h"
49
50#ifndef QT_NO_LIBRARY
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \class QPluginLoader
56 \reentrant
57 \brief The QPluginLoader class loads a plugin at run-time.
58
59 \mainclass
60 \ingroup plugins
61
62 QPluginLoader provides access to a \l{How to Create Qt
63 Plugins}{Qt plugin}. A Qt plugin is stored in a shared library (a
64 DLL) and offers these benefits over shared libraries accessed
65 using QLibrary:
66
67 \list
68 \o QPluginLoader checks that a plugin is linked against the same
69 version of Qt as the application.
70 \o QPluginLoader provides direct access to a root component object
71 (instance()), instead of forcing you to resolve a C function manually.
72 \endlist
73
74 An instance of a QPluginLoader object operates on a single shared
75 library file, which we call a plugin. It provides access to the
76 functionality in the plugin in a platform-independent way. To
77 specify which plugin to load, either pass a file name in
78 the constructor or set it with setFileName().
79
80 The most important functions are load() to dynamically load the
81 plugin file, isLoaded() to check whether loading was successful,
82 and instance() to access the root component in the plugin. The
83 instance() function implicitly tries to load the plugin if it has
84 not been loaded yet. Multiple instances of QPluginLoader can be
85 used to access the same physical plugin.
86
87 Once loaded, plugins remain in memory until all instances of
88 QPluginLoader has been unloaded, or until the application
89 terminates. You can attempt to unload a plugin using unload(),
90 but if other instances of QPluginLoader are using the same
91 library, the call will fail, and unloading will only happen when
92 every instance has called unload(). Right before the unloading
93 happen, the root component will also be deleted.
94
95 In order to speed up loading and validation of plugins, some of
96 the information that is collected during loading is cached in
97 persistent memory (through QSettings). For instance, the result
98 of a load operation (e.g. succeeded or failed) is stored in the
99 cache, so that subsequent load operations don't try to load an
100 invalid plugin. However, if the "last modified" timestamp of
101 a plugin has changed, the plugin's cache entry is invalidated
102 and the plugin is reloaded regardless of the values in the cache
103 entry. The cache entry is then updated with the new result of the
104 load operation.
105
106 This also means that the timestamp must be updated each time the
107 plugin or any dependent resources (such as a shared library) is
108 updated, since the dependent resources might influence the result
109 of loading a plugin.
110
111 See \l{How to Create Qt Plugins} for more information about
112 how to make your application extensible through plugins.
113
114 Note that the QPluginLoader cannot be used if your application is
115 statically linked against Qt. In this case, you will also have to
116 link to plugins statically. You can use QLibrary if you need to
117 load dynamic libraries in a statically linked application.
118
119 \sa QLibrary, {Plug & Paint Example}
120*/
121
122/*!
123 Constructs a plugin loader with the given \a parent.
124*/
125QPluginLoader::QPluginLoader(QObject *parent)
126 : QObject(parent), d(0), did_load(false)
127{
128}
129
130/*!
131 Constructs a plugin loader with the given \a parent that will
132 load the plugin specified by \a fileName.
133
134 To be loadable, the file's suffix must be a valid suffix for a
135 loadable library in accordance with the platform, e.g. \c .so on
136 Unix, - \c .dylib on Mac OS X, and \c .dll on Windows. The suffix
137 can be verified with QLibrary::isLibrary().
138
139 \sa setFileName()
140*/
141QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent)
142 : QObject(parent), d(0), did_load(false)
143{
144 setFileName(fileName);
145}
146
147/*!
148 Destroys the QPluginLoader object.
149
150 Unless unload() was called explicitly, the plugin stays in memory
151 until the application terminates.
152
153 \sa isLoaded(), unload()
154*/
155QPluginLoader::~QPluginLoader()
156{
157 if (d)
158 d->release();
159}
160
161/*!
162 Returns the root component object of the plugin. The plugin is
163 loaded if necessary. The function returns 0 if the plugin could
164 not be loaded or if the root component object could not be
165 instantiated.
166
167 If the root component object was destroyed, calling this function
168 creates a new instance.
169
170 The root component, returned by this function, is not deleted when
171 the QPluginLoader is destroyed. If you want to ensure that the root
172 component is deleted, you should call unload() as soon you don't
173 need to access the core component anymore. When the library is
174 finally unloaded, the root component will automatically be deleted.
175
176 The component object is a QObject. Use qobject_cast() to access
177 interfaces you are interested in.
178
179 \sa load()
180*/
181QObject *QPluginLoader::instance()
182{
183 if (!load())
184 return 0;
185 if (d->instance)
186 return d->instance();
187 return 0;
188}
189
190/*!
191 Loads the plugin and returns true if the plugin was loaded
192 successfully; otherwise returns false. Since instance() always
193 calls this function before resolving any symbols it is not
194 necessary to call it explicitly. In some situations you might want
195 the plugin loaded in advance, in which case you would use this
196 function.
197
198 \sa unload()
199*/
200bool QPluginLoader::load()
201{
202 if (!d || d->fileName.isEmpty())
203 return false;
204 if (did_load)
205 return d->pHnd && d->instance;
206 if (!d->isPlugin())
207 return false;
208 did_load = true;
209 return d->loadPlugin();
210}
211
212
213/*!
214 Unloads the plugin and returns true if the plugin could be
215 unloaded; otherwise returns false.
216
217 This happens automatically on application termination, so you
218 shouldn't normally need to call this function.
219
220 If other instances of QPluginLoader are using the same plugin, the
221 call will fail, and unloading will only happen when every instance
222 has called unload().
223
224 Don't try to delete the root component. Instead rely on
225 that unload() will automatically delete it when needed.
226
227 \sa instance(), load()
228*/
229bool QPluginLoader::unload()
230{
231 if (did_load) {
232 did_load = false;
233 return d->unload();
234 }
235 if (d) // Ouch
236 d->errorString = tr("The plugin was not loaded.");
237 return false;
238}
239
240/*!
241 Returns true if the plugin is loaded; otherwise returns false.
242
243 \sa load()
244 */
245bool QPluginLoader::isLoaded() const
246{
247 return d && d->pHnd && d->instance;
248}
249
250/*!
251 \property QPluginLoader::fileName
252 \brief the file name of the plugin
253
254 To be loadable, the file's suffix must be a valid suffix for a
255 loadable library in accordance with the platform, e.g. \c .so on
256 Unix, \c .dylib on Mac OS X, and \c .dll on Windows. The suffix
257 can be verified with QLibrary::isLibrary().
258
259 If the file name does not exist, it will not be set. This property
260 will then contain an empty string.
261
262 By default, this property contains an empty string.
263
264 \sa load()
265*/
266void QPluginLoader::setFileName(const QString &fileName)
267{
268#if defined(QT_SHARED)
269 QLibrary::LoadHints lh;
270 if (d) {
271 lh = d->loadHints;
272 d->release();
273 d = 0;
274 did_load = false;
275 }
276 QString fn = QFileInfo(fileName).canonicalFilePath();
277 d = QLibraryPrivate::findOrCreate(fn);
278 d->loadHints = lh;
279 if (fn.isEmpty())
280 d->errorString = QLibrary::tr("The shared library was not found.");
281#else
282 if (qt_debug_component()) {
283 qWarning("Cannot load %s into a statically linked Qt library.",
284 (const char*)QFile::encodeName(fileName));
285 }
286 Q_UNUSED(fileName);
287#endif
288}
289
290QString QPluginLoader::fileName() const
291{
292 if (d)
293 return d->fileName;
294 return QString();
295}
296
297/*!
298 \since 4.2
299
300 Returns a text string with the description of the last error that occurred.
301*/
302QString QPluginLoader::errorString() const
303{
304 return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString;
305}
306
307typedef QList<QtPluginInstanceFunction> StaticInstanceFunctionList;
308Q_GLOBAL_STATIC(StaticInstanceFunctionList, staticInstanceFunctionList)
309
310/*! \since 4.4
311
312 \property QPluginLoader::loadHints
313 \brief Give the load() function some hints on how it should behave.
314
315 You can give hints on how the symbols in the plugin are
316 resolved. By default, none of the hints are set.
317
318 See the documentation of QLibrary::loadHints for a complete
319 description of how this property works.
320
321 \sa QLibrary::loadHints
322*/
323
324void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints)
325{
326 if (!d) {
327 d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
328 d->errorString.clear();
329 }
330 d->loadHints = loadHints;
331}
332
333QLibrary::LoadHints QPluginLoader::loadHints() const
334{
335 if (!d) {
336 QPluginLoader *that = const_cast<QPluginLoader *>(this);
337 that->d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
338 that->d->errorString.clear();
339 }
340 return d->loadHints;
341}
342
343/*!
344 \relates QPluginLoader
345 \since 4.4
346
347 Registers the given \a function with the plugin loader.
348*/
349void Q_CORE_EXPORT qRegisterStaticPluginInstanceFunction(QtPluginInstanceFunction function)
350{
351 staticInstanceFunctionList()->append(function);
352}
353
354/*!
355 Returns a list of static plugin instances (root components) held
356 by the plugin loader.
357*/
358QObjectList QPluginLoader::staticInstances()
359{
360 QObjectList instances;
361 StaticInstanceFunctionList *functions = staticInstanceFunctionList();
362 if (functions) {
363 for (int i = 0; i < functions->count(); ++i)
364 instances.append((*functions)[i]());
365 }
366 return instances;
367}
368
369QT_END_NAMESPACE
370
371#endif // QT_NO_LIBRARY
Note: See TracBrowser for help on using the repository browser.