summaryrefslogtreecommitdiff
path: root/qmake/tools/qcomponentfactory.cpp
Unidiff
Diffstat (limited to 'qmake/tools/qcomponentfactory.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--qmake/tools/qcomponentfactory.cpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/qmake/tools/qcomponentfactory.cpp b/qmake/tools/qcomponentfactory.cpp
new file mode 100644
index 0000000..8ea81a8
--- a/dev/null
+++ b/qmake/tools/qcomponentfactory.cpp
@@ -0,0 +1,352 @@
1/****************************************************************************
2** $Id$
3**
4** Implementation of the QComponentFactory class
5**
6** Created : 990101
7**
8** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.
9**
10** This file is part of the tools module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qcomponentfactory_p.h"
39
40#ifndef QT_NO_COMPONENT
41#include "qsettings.h"
42#include <private/qcomlibrary_p.h>
43#include "qdir.h"
44#include "qapplication.h"
45
46/*!
47 \class QComponentFactory qcomponentfactory.h
48 \brief The QComponentFactory class provides static functions to create and register components.
49
50 \internal
51
52 The static convenience functions can be used both by applications to instantiate components,
53 and by component servers to register components.
54
55 The createInstance() function provides a pointer to an interface implemented in a specific
56 component if the component requested has been installed properly and implements the interface.
57
58 Use registerServer() to load a component server and register its components, and unregisterServer()
59 to unregister the components. The component exported by the component server has to implement the
60 QComponentRegistrationInterface.
61
62 The static functions registerComponent() and unregisterComponent() register and unregister a single
63 component in the system component registry, and should be used when implementing the
64 \link QComponentRegistrationInterface::registerComponents() registerCompontents() \endlink and
65 \link QComponentRegistrationInterface::unregisterComponents() unregisterCompontents() \endlink functions
66 in the QComponentRegistrationInterface.
67
68 A component is registered using a UUID, but can additionally be registered with a name, version and
69 description. A component registered with a name and a version can be instantiated by client applications
70 using the name and specific version number, or the highest available version number for that component by
71 just using the name. A component that is registered calling
72
73 \code
74 QComponentFactory::registerComponent( QUuid(...), filename, "MyProgram.Component", 1 );
75 \endcode
76
77 can be instantiated calling either:
78
79 \code
80 QComponentFactory::createInstance( QUuid(...), IID_XYZ, (QUnknownInterface**)&iface );
81 \endcode
82 or
83 \code
84 QComponentFactory::createInstance( "MyProgram.Component", IID_XYZ, (QUnknownInterface**)&iface );
85 \endcode
86 or
87 \code
88 QComponentFactory::createInstance( "MyProgram.Component.1", IID_XYZ, (QUnknownInterface**)&iface );
89 \endcode
90
91 The first and the last way will always instantiate exactly the component registered above, while
92 the second call might also return a later version of the same component. This allows smoother upgrading
93 of components, and is easier to use in application source code, but should only be used when new versions
94 of the component are guaranteed to work with the application.
95
96 The component name can be anything, but should be unique on the system the component is being
97 installed on. A common naming convention for components is \e application.component.
98
99 \sa QComponentRegistrationInterface QComponentFactoryInterface
100*/
101
102
103static QPtrList<QComLibrary> *libraries = 0;
104
105static void cleanup()
106{
107 delete libraries;
108 libraries = 0;
109}
110
111static QPtrList<QComLibrary> *liblist()
112{
113 if ( !libraries ) {
114 libraries = new QPtrList<QComLibrary>();
115 libraries->setAutoDelete( TRUE );
116 qAddPostRoutine( cleanup );
117 }
118 return libraries;
119}
120
121/*!
122 Searches for the component identifier \a cid in the system component registry,
123 loads the corresponding component server and queries for the interface \a iid.
124 \a iface is set to the resulting interface pointer. \a cid can either be the
125 UUID or the name of the component.
126
127 The parameter \a outer is a pointer to the outer interface used
128 for containment and aggregation and is propagated to the \link
129 QComponentFactoryInterface::createInstance() createInstance() \endlink
130 implementation of the QComponentFactoryInterface in the component server if
131 provided.
132
133 The function returns QS_OK if the interface was successfully instantiated, QE_NOINTERFACE if
134 the component does not provide an interface \a iid, or QE_NOCOMPONENT if there was
135 an error loading the component.
136
137 Example:
138 \code
139 QInterfacePtr<MyInterface> iface;
140 if ( QComponentFactory::createInstance( IID_MyInterface, CID_MyComponent, (QUnknownInterface**)&iface ) == QS_OK )
141 iface->doSomething();
142 ...
143 }
144 \endcode
145*/
146QRESULT QComponentFactory::createInstance( const QString &cid, const QUuid &iid, QUnknownInterface** iface, QUnknownInterface *outer )
147{
148 QSettings settings;
149 settings.insertSearchPath( QSettings::Windows, "/Classes" );
150 bool ok = FALSE;
151 QString cidStr = cid;
152 QRESULT res = QE_NOCOMPONENT;
153
154 QUuid uuid( cidStr ); // try to parse, and resolve CLSID if necessary
155 if ( uuid.isNull() ) {
156 uuid = settings.readEntry( "/" + cid + "/CLSID/Default", QString::null, &ok );
157 cidStr = uuid.toString().upper();
158 }
159
160 if ( cidStr.isEmpty() )
161 return res;
162
163 QString file = settings.readEntry( "/CLSID/" + cidStr + "/InprocServer32/Default", QString::null, &ok );
164 if ( !ok )
165 return res;
166
167 QComLibrary *library = new QComLibrary( file );
168 library->setAutoUnload( FALSE );
169
170 QComponentFactoryInterface *cfIface =0;
171 library->queryInterface( IID_QComponentFactory, (QUnknownInterface**)&cfIface );
172
173 if ( cfIface ) {
174 res = cfIface->createInstance( uuid, iid, iface, outer );
175 cfIface->release();
176 } else {
177 res = library->queryInterface( iid, iface );
178 }
179 QLibraryInterface *libiface = 0;
180 if ( library->queryInterface( IID_QLibrary, (QUnknownInterface**)&libiface ) != QS_OK || !qApp ) {
181 delete library; // only deletes the object, thanks to QLibrary::Manual
182 } else {
183 libiface->release();
184 library->setAutoUnload( TRUE );
185 liblist()->prepend( library );
186 }
187 return res;
188}
189
190/*!
191 Loads the shared library \a filename and queries for a
192 QComponentRegistrationInterface. If the library implements this interface,
193 the \link QComponentRegistrationInterface::registerComponents()
194 registerComponents() \endlink function is called.
195
196 Returns TRUE if the interface is found and successfully called,
197 otherwise returns FALSE.
198*/
199QRESULT QComponentFactory::registerServer( const QString &filename )
200{
201 QComLibrary lib( filename );
202 lib.load();
203 QComponentRegistrationInterface *iface = 0;
204 QRESULT res = lib.queryInterface( IID_QComponentRegistration, (QUnknownInterface**)&iface );
205 if ( res != QS_OK )
206 return res;
207 QDir dir( filename );
208 bool ok = iface->registerComponents( dir.absPath() );
209 iface->release();
210 return ok ? QS_OK : QS_FALSE;
211}
212
213/*!
214 Loads the shared library \a filename and queries for a
215 QComponentRegistrationInterface. If the library implements this interface,
216 the \link QComponentRegistrationInterface::unregisterComponents()
217 unregisterComponents() \endlink function is called.
218
219 Returns TRUE if the interface is found and successfully unregistered,
220 otherwise returns FALSE.
221*/
222QRESULT QComponentFactory::unregisterServer( const QString &filename )
223{
224 QComLibrary lib( filename );
225 lib.load();
226 QComponentRegistrationInterface *iface = 0;
227 QRESULT res = lib.queryInterface( IID_QComponentRegistration, (QUnknownInterface**)&iface );
228 if ( res != QS_OK )
229 return res;
230 bool ok = iface->unregisterComponents();
231 iface->release();
232 return ok ? QS_OK : QS_FALSE;
233}
234
235/*!
236 Registers the component with id \a cid in the system component registry and
237 returns TRUE if the component was registerd successfully, otherwise returns
238 FALSE. The component is provided by the component server at \a filepath and
239 registered with an optional \a name, \a version and \a description.
240
241 This function does nothing and returns FALSE if a component with an identical
242 \a cid does already exist on the system.
243
244 A component that has been registered with a \a name can be created using both the
245 \a cid and the \a name value using createInstance().
246
247 Call this function for each component in an implementation of
248 \link QComponentRegistrationInterface::registerComponents() registerComponents() \endlink.
249
250 \sa unregisterComponent(), registerServer(), createInstance()
251*/
252bool QComponentFactory::registerComponent( const QUuid &cid, const QString &filepath, const QString &name, int version, const QString &description )
253{
254 bool ok = FALSE;
255 QSettings settings;
256 settings.insertSearchPath( QSettings::Windows, "/Classes" );
257
258 QString cidStr = cid.toString().upper();
259 settings.readEntry( "/CLSID/" + cidStr + "/InprocServer32/Default", QString::null, &ok );
260 if ( ok ) // don't overwrite existing component
261 return FALSE;
262
263 ok = settings.writeEntry( "/CLSID/" + cidStr + "/InprocServer32/Default", filepath );
264 if ( ok && !!description )
265 settings.writeEntry( "/CLSID/" + cidStr + "/Default", description );
266
267 // register the human readable part
268 if ( ok && !!name ) {
269 QString vName = version ? name + "." + QString::number( version ) : name;
270 settings.writeEntry( "/CLSID/" + cidStr + "/ProgID/Default", vName );
271 ok = settings.writeEntry( "/" + vName + "/CLSID/Default", cidStr );
272 if ( ok && !!description )
273 settings.writeEntry( "/" + vName + "/Default", description );
274
275 if ( ok && version ) {
276 settings.writeEntry( "/CLSID/" + cidStr + "/VersionIndependentProgID/Default", name );
277 QString curVer = settings.readEntry( "/" + name + "/CurVer/Default" );
278 if ( !curVer || curVer < vName ) { // no previous, or a lesser version installed
279 settings.writeEntry( "/" + name + "/CurVer/Default", vName );
280 ok = settings.writeEntry( "/" + name + "/CLSID/Default", cidStr );
281 if ( ok && !!description )
282 settings.writeEntry( "/" + name + "/Default", description );
283 }
284 }
285 }
286
287 return ok;
288}
289
290/*!
291 Unregisters the component with id \a cid from the system component registry and returns
292 TRUE if the component was unregistered successfully, otherwise returns FALSE.
293
294 Call this function for each component in an implementation of
295 \link QComponentRegistrationInterface::unregisterComponents() unregisterComponents() \endlink.
296
297 \sa registerComponent(), unregisterServer()
298*/
299bool QComponentFactory::unregisterComponent( const QUuid &cid )
300{
301 QSettings settings;
302 bool ok = FALSE;
303 settings.insertSearchPath( QSettings::Windows, "/Classes" );
304
305 QString cidStr = cid.toString().upper();
306 if ( cidStr.isEmpty() )
307 return FALSE;
308
309 // unregister the human readable part
310 QString vName = settings.readEntry( "/CLSID/" + cidStr + "/ProgID/Default", QString::null, &ok );
311 if ( ok ) {
312 QString name = settings.readEntry( "/CLSID/" + cidStr + "/VersionIndependentProgID/Default", QString::null );
313 if ( !!name && settings.readEntry( "/" + name + "/CurVer/Default" ) == vName ) {
314 // unregistering the current version -> change CurVer to previous version
315 QString version = vName.right( vName.length() - name.length() - 1 );
316 QString newVerName;
317 QString newCidStr;
318 if ( version.find( '.' ) == -1 ) {
319 int ver = version.toInt();
320 // see if a lesser version is installed, and make that the CurVer
321 while ( ver-- ) {
322 newVerName = name + "." + QString::number( ver );
323 newCidStr = settings.readEntry( "/" + newVerName + "/CLSID/Default" );
324 if ( !!newCidStr )
325 break;
326 }
327 } else {
328 // oh well...
329 }
330 if ( !!newCidStr ) {
331 settings.writeEntry( "/" + name + "/CurVer/Default", newVerName );
332 settings.writeEntry( "/" + name + "/CLSID/Default", newCidStr );
333 } else {
334 settings.removeEntry( "/" + name + "/CurVer/Default" );
335 settings.removeEntry( "/" + name + "/CLSID/Default" );
336 settings.removeEntry( "/" + name + "/Default" );
337 }
338 }
339
340 settings.removeEntry( "/" + vName + "/CLSID/Default" );
341 settings.removeEntry( "/" + vName + "/Default" );
342 }
343
344 settings.removeEntry( "/CLSID/" + cidStr + "/VersionIndependentProgID/Default" );
345 settings.removeEntry( "/CLSID/" + cidStr + "/ProgID/Default" );
346 settings.removeEntry( "/CLSID/" + cidStr + "/InprocServer32/Default" );
347 ok = settings.removeEntry( "/CLSID/" + cidStr + "/Default" );
348
349 return ok;
350}
351
352#endif // QT_NO_COMPONENT