1 | /****************************************************************************
|
---|
2 | ** $Id: qcomlibrary.cpp 2 2005-11-16 15:49:26Z dmik $
|
---|
3 | **
|
---|
4 | ** Implementation of QComLibrary class
|
---|
5 | **
|
---|
6 | ** Copyright (C) 2001-2002 Trolltech AS. All rights reserved.
|
---|
7 | **
|
---|
8 | ** This file is part of the tools module of the Qt GUI Toolkit.
|
---|
9 | **
|
---|
10 | ** This file may be distributed under the terms of the Q Public License
|
---|
11 | ** as defined by Trolltech AS of Norway and appearing in the file
|
---|
12 | ** LICENSE.QPL included in the packaging of this file.
|
---|
13 | **
|
---|
14 | ** This file may be distributed and/or modified under the terms of the
|
---|
15 | ** GNU General Public License version 2 as published by the Free Software
|
---|
16 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
17 | ** packaging of this file.
|
---|
18 | **
|
---|
19 | ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
|
---|
20 | ** licenses may use this file in accordance with the Qt Commercial License
|
---|
21 | ** Agreement provided with the Software.
|
---|
22 | **
|
---|
23 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
---|
24 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
---|
25 | **
|
---|
26 | ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
|
---|
27 | ** information about Qt Commercial License Agreements.
|
---|
28 | ** See http://www.trolltech.com/qpl/ for QPL licensing information.
|
---|
29 | ** See http://www.trolltech.com/gpl/ for GPL licensing information.
|
---|
30 | **
|
---|
31 | ** Contact info@trolltech.com if any conditions of this licensing are
|
---|
32 | ** not clear to you.
|
---|
33 | **
|
---|
34 | **********************************************************************/
|
---|
35 |
|
---|
36 | #include "qcomlibrary_p.h"
|
---|
37 |
|
---|
38 | #ifndef QT_NO_COMPONENT
|
---|
39 | #include <qapplication.h>
|
---|
40 | #include <qsettings.h>
|
---|
41 | #include <qfileinfo.h>
|
---|
42 | #include <qdatetime.h>
|
---|
43 | #include <qcleanuphandler.h>
|
---|
44 | #ifndef NO_ERRNO_H
|
---|
45 | #include <errno.h>
|
---|
46 | #endif // NO_ERROR_H
|
---|
47 |
|
---|
48 | #ifdef QT_THREAD_SUPPORT
|
---|
49 | # include "qmutexpool_p.h"
|
---|
50 | #endif // QT_THREAD_SUPPORT
|
---|
51 |
|
---|
52 | #ifndef QT_DEBUG_COMPONENT
|
---|
53 | # if defined(QT_DEBUG)
|
---|
54 | # define QT_DEBUG_COMPONENT 1
|
---|
55 | # endif
|
---|
56 | #endif
|
---|
57 |
|
---|
58 |
|
---|
59 | QComLibrary::QComLibrary( const QString &filename )
|
---|
60 | : QLibrary( filename ), entry( 0 ), libiface( 0 ), qt_version( 0 )
|
---|
61 | {
|
---|
62 | }
|
---|
63 |
|
---|
64 | QComLibrary::~QComLibrary()
|
---|
65 | {
|
---|
66 | if ( autoUnload() )
|
---|
67 | unload();
|
---|
68 | if ( libiface )
|
---|
69 | libiface->release();
|
---|
70 | if ( entry )
|
---|
71 | entry->release();
|
---|
72 | }
|
---|
73 |
|
---|
74 | bool QComLibrary::unload()
|
---|
75 | {
|
---|
76 | int refs = entry ? entry->release() : 0;
|
---|
77 | entry = 0;
|
---|
78 | if (refs || !libiface)
|
---|
79 | return FALSE;
|
---|
80 |
|
---|
81 | libiface->cleanup();
|
---|
82 | if ( !libiface->canUnload() )
|
---|
83 | return FALSE;
|
---|
84 | libiface->release();
|
---|
85 | libiface = 0;
|
---|
86 |
|
---|
87 | return QLibrary::unload();
|
---|
88 | }
|
---|
89 |
|
---|
90 | static bool qt_verify( const QString& library, uint version, uint flags,
|
---|
91 | const QCString &key, bool warn )
|
---|
92 | {
|
---|
93 | uint our_flags = 1;
|
---|
94 | #if defined(QT_THREAD_SUPPORT)
|
---|
95 | our_flags |= 2;
|
---|
96 | #endif
|
---|
97 |
|
---|
98 | if ( (flags & 1) == 0 ) {
|
---|
99 | if ( warn )
|
---|
100 | qWarning( "Conflict in %s:\n"
|
---|
101 | " Plugin cannot be queried successfully!",
|
---|
102 | (const char*) QFile::encodeName(library) );
|
---|
103 | } else if ( ( version > QT_VERSION ) ||
|
---|
104 | ( ( QT_VERSION & 0xff0000 ) > ( version & 0xff0000 ) ) ) {
|
---|
105 | if ( warn )
|
---|
106 | qWarning( "Conflict in %s:\n"
|
---|
107 | " Plugin uses incompatible Qt library (%d.%d.%d)!",
|
---|
108 | (const char*) QFile::encodeName(library),
|
---|
109 | (version&0xff0000) >> 16, (version&0xff00) >> 8, version&0xff );
|
---|
110 | } else if ( (flags & 2) != (our_flags & 2) ) {
|
---|
111 | if ( warn )
|
---|
112 | qWarning( "Conflict in %s:\n"
|
---|
113 | " Plugin uses %s Qt library!",
|
---|
114 | (const char*) QFile::encodeName(library),
|
---|
115 | (flags & 2) ? "multi threaded" : "single threaded" );
|
---|
116 | } else if ( key != QT_BUILD_KEY ) {
|
---|
117 | if ( warn )
|
---|
118 | qWarning( "Conflict in %s:\n"
|
---|
119 | " Plugin uses incompatible Qt library!\n"
|
---|
120 | " expected build key \"%s\", got \"%s\".",
|
---|
121 | (const char*) QFile::encodeName(library),
|
---|
122 | QT_BUILD_KEY,
|
---|
123 | key.isEmpty() ? "<null>" : (const char *) key );
|
---|
124 | } else {
|
---|
125 | return TRUE;
|
---|
126 | }
|
---|
127 | return FALSE;
|
---|
128 | }
|
---|
129 |
|
---|
130 | struct qt_token_info
|
---|
131 | {
|
---|
132 | qt_token_info( const char *f, const ulong fc )
|
---|
133 | : fields( f ), field_count( fc ), results( fc ), lengths( fc )
|
---|
134 | {
|
---|
135 | results.fill( 0 );
|
---|
136 | lengths.fill( 0 );
|
---|
137 | }
|
---|
138 |
|
---|
139 | const char *fields;
|
---|
140 | const ulong field_count;
|
---|
141 |
|
---|
142 | QMemArray<const char *> results;
|
---|
143 | QMemArray<ulong> lengths;
|
---|
144 | };
|
---|
145 |
|
---|
146 | /*
|
---|
147 | return values:
|
---|
148 | 1 parse ok
|
---|
149 | 0 eos
|
---|
150 | -1 parse error
|
---|
151 | */
|
---|
152 | static int qt_tokenize( const char *s, ulong s_len, ulong *advance,
|
---|
153 | const qt_token_info &token_info )
|
---|
154 | {
|
---|
155 | ulong pos = 0, field = 0, fieldlen = 0;
|
---|
156 | char current;
|
---|
157 | int ret = -1;
|
---|
158 | *advance = 0;
|
---|
159 | for (;;) {
|
---|
160 | current = s[ pos ];
|
---|
161 |
|
---|
162 | // next char
|
---|
163 | ++pos;
|
---|
164 | ++fieldlen;
|
---|
165 | ++*advance;
|
---|
166 |
|
---|
167 | if ( ! current || pos == s_len + 1 ) {
|
---|
168 | // save result
|
---|
169 | token_info.results[ (int)field ] = s;
|
---|
170 | token_info.lengths[ (int)field ] = fieldlen - 1;
|
---|
171 |
|
---|
172 | // end of string
|
---|
173 | ret = 0;
|
---|
174 | break;
|
---|
175 | }
|
---|
176 |
|
---|
177 | if ( current == token_info.fields[ field ] ) {
|
---|
178 | // save result
|
---|
179 | token_info.results[ (int)field ] = s;
|
---|
180 | token_info.lengths[ (int)field ] = fieldlen - 1;
|
---|
181 |
|
---|
182 | // end of field
|
---|
183 | fieldlen = 0;
|
---|
184 | ++field;
|
---|
185 | if ( field == token_info.field_count - 1 ) {
|
---|
186 | // parse ok
|
---|
187 | ret = 1;
|
---|
188 | }
|
---|
189 | if ( field == token_info.field_count ) {
|
---|
190 | // done parsing
|
---|
191 | break;
|
---|
192 | }
|
---|
193 |
|
---|
194 | // reset string and its length
|
---|
195 | s = s + pos;
|
---|
196 | s_len -= pos;
|
---|
197 | pos = 0;
|
---|
198 | }
|
---|
199 | }
|
---|
200 |
|
---|
201 | return ret;
|
---|
202 | }
|
---|
203 |
|
---|
204 | /*
|
---|
205 | returns TRUE if the string s was correctly parsed, FALSE otherwise.
|
---|
206 | */
|
---|
207 | static bool qt_parse_pattern( const char *s, uint *version, uint *flags,
|
---|
208 | QCString *key )
|
---|
209 | {
|
---|
210 | bool ret = TRUE;
|
---|
211 |
|
---|
212 | qt_token_info pinfo("=\n", 2);
|
---|
213 | int parse;
|
---|
214 | ulong at = 0, advance, parselen = qstrlen( s );
|
---|
215 | do {
|
---|
216 | parse = qt_tokenize( s + at, parselen, &advance, pinfo );
|
---|
217 | if ( parse == -1 ) {
|
---|
218 | ret = FALSE;
|
---|
219 | break;
|
---|
220 | }
|
---|
221 |
|
---|
222 | at += advance;
|
---|
223 | parselen -= advance;
|
---|
224 |
|
---|
225 | if ( qstrncmp( "version", pinfo.results[ 0 ], pinfo.lengths[ 0 ] ) == 0 ) {
|
---|
226 | // parse version string
|
---|
227 | qt_token_info pinfo2("..-", 3);
|
---|
228 | if ( qt_tokenize( pinfo.results[ 1 ], pinfo.lengths[ 1 ],
|
---|
229 | &advance, pinfo2 ) != -1 ) {
|
---|
230 | QCString m( pinfo2.results[ 0 ], pinfo2.lengths[ 0 ] + 1 );
|
---|
231 | QCString n( pinfo2.results[ 1 ], pinfo2.lengths[ 1 ] + 1 );
|
---|
232 | QCString p( pinfo2.results[ 2 ], pinfo2.lengths[ 2 ] + 1 );
|
---|
233 | *version = (m.toUInt() << 16) | (n.toUInt() << 8) | p.toUInt();
|
---|
234 | } else {
|
---|
235 | ret = FALSE;
|
---|
236 | break;
|
---|
237 | }
|
---|
238 | } else if ( qstrncmp( "flags", pinfo.results[ 0 ], pinfo.lengths[ 0 ] ) == 0 ) {
|
---|
239 | // parse flags string
|
---|
240 | char ch;
|
---|
241 | *flags = 0;
|
---|
242 | ulong p = 0, c = 0, bit = 0;
|
---|
243 | while ( p < pinfo.lengths[ 1 ] ) {
|
---|
244 | ch = pinfo.results[ 1 ][ p ];
|
---|
245 | bit = pinfo.lengths[ 1 ] - p - 1;
|
---|
246 | c = 1 << bit;
|
---|
247 | if ( ch == '1' ) {
|
---|
248 | *flags |= c;
|
---|
249 | } else if ( ch != '0' ) {
|
---|
250 | ret = FALSE;
|
---|
251 | break;
|
---|
252 | }
|
---|
253 | ++p;
|
---|
254 | }
|
---|
255 | } else if ( qstrncmp( "buildkey", pinfo.results[ 0 ],
|
---|
256 | pinfo.lengths[ 0 ] ) == 0 ){
|
---|
257 | // save buildkey
|
---|
258 | *key = QCString( pinfo.results[ 1 ], pinfo.lengths[ 1 ] + 1 );
|
---|
259 | }
|
---|
260 | } while ( parse == 1 && parselen > 0 );
|
---|
261 |
|
---|
262 | return ret;
|
---|
263 | }
|
---|
264 |
|
---|
265 | #if defined(Q_OS_UNIX)
|
---|
266 |
|
---|
267 | #if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX)
|
---|
268 | # define USE_MMAP
|
---|
269 | # include <sys/types.h>
|
---|
270 | # include <sys/mman.h>
|
---|
271 | #endif // Q_OS_FREEBSD || Q_OS_LINUX
|
---|
272 |
|
---|
273 | static long qt_find_pattern( const char *s, ulong s_len,
|
---|
274 | const char *pattern, ulong p_len )
|
---|
275 | {
|
---|
276 | /*
|
---|
277 | this uses the same algorithm as QString::findRev...
|
---|
278 |
|
---|
279 | we search from the end of the file because on the supported
|
---|
280 | systems, the read-only data/text segments are placed at the end
|
---|
281 | of the file. HOWEVER, when building with debugging enabled, all
|
---|
282 | the debug symbols are placed AFTER the data/text segments.
|
---|
283 |
|
---|
284 | what does this mean? when building in release mode, the search
|
---|
285 | is fast because the data we are looking for is at the end of the
|
---|
286 | file... when building in debug mode, the search is slower
|
---|
287 | because we have to skip over all the debugging symbols first
|
---|
288 | */
|
---|
289 |
|
---|
290 | if ( ! s || ! pattern || p_len > s_len ) return -1;
|
---|
291 | ulong i, hs = 0, hp = 0, delta = s_len - p_len;
|
---|
292 |
|
---|
293 | for (i = 0; i < p_len; ++i ) {
|
---|
294 | hs += s[delta + i];
|
---|
295 | hp += pattern[i];
|
---|
296 | }
|
---|
297 | i = delta;
|
---|
298 | for (;;) {
|
---|
299 | if ( hs == hp && qstrncmp( s + i, pattern, p_len ) == 0 )
|
---|
300 | return i;
|
---|
301 | if ( i == 0 )
|
---|
302 | break;
|
---|
303 | --i;
|
---|
304 | hs -= s[i + p_len];
|
---|
305 | hs += s[i];
|
---|
306 | }
|
---|
307 |
|
---|
308 | return -1;
|
---|
309 | }
|
---|
310 |
|
---|
311 | /*
|
---|
312 | This opens the specified library, mmaps it into memory, and searches
|
---|
313 | for the QT_UCM_VERIFICATION_DATA. The advantage of this approach is that
|
---|
314 | we can get the verification data without have to actually load the library.
|
---|
315 | This lets us detect mismatches more safely.
|
---|
316 |
|
---|
317 | Returns FALSE if version/flags/key information is not present, or if the
|
---|
318 | information could not be read.
|
---|
319 | Returns TRUE if version/flags/key information is present and succesfully read.
|
---|
320 | */
|
---|
321 | static bool qt_unix_query( const QString &library, uint *version, uint *flags,
|
---|
322 | QCString *key )
|
---|
323 | {
|
---|
324 | QFile file( library );
|
---|
325 | if (! file.open( IO_ReadOnly ) ) {
|
---|
326 | qWarning( "%s: %s", (const char*) QFile::encodeName(library),
|
---|
327 | strerror( errno ) );
|
---|
328 | return FALSE;
|
---|
329 | }
|
---|
330 |
|
---|
331 | QByteArray data;
|
---|
332 | char *filedata = 0;
|
---|
333 | ulong fdlen = 0;
|
---|
334 |
|
---|
335 | #ifdef USE_MMAP
|
---|
336 | char *mapaddr = 0;
|
---|
337 | size_t maplen = file.size();
|
---|
338 | mapaddr = (char *) mmap( mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0 );
|
---|
339 | if ( mapaddr != MAP_FAILED ) {
|
---|
340 | // mmap succeeded
|
---|
341 | filedata = mapaddr;
|
---|
342 | fdlen = maplen;
|
---|
343 | } else {
|
---|
344 | // mmap failed
|
---|
345 | qWarning( "mmap: %s", strerror( errno ) );
|
---|
346 | #endif // USE_MMAP
|
---|
347 | // try reading the data into memory instead
|
---|
348 | data = file.readAll();
|
---|
349 | filedata = data.data();
|
---|
350 | fdlen = data.size();
|
---|
351 | #ifdef USE_MMAP
|
---|
352 | }
|
---|
353 | #endif // USE_MMAP
|
---|
354 |
|
---|
355 | // verify that the pattern is present in the plugin
|
---|
356 | const char *pattern = "pattern=QT_UCM_VERIFICATION_DATA";
|
---|
357 | const ulong plen = qstrlen( pattern );
|
---|
358 | long pos = qt_find_pattern( filedata, fdlen, pattern, plen );
|
---|
359 |
|
---|
360 | bool ret = FALSE;
|
---|
361 | if ( pos >= 0 ) {
|
---|
362 | ret = qt_parse_pattern( filedata + pos, version, flags, key );
|
---|
363 | }
|
---|
364 |
|
---|
365 | #ifdef USE_MMAP
|
---|
366 | if ( mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0 ) {
|
---|
367 | qWarning( "munmap: %s", strerror( errno ) );
|
---|
368 | }
|
---|
369 | #endif // USE_MMAP
|
---|
370 |
|
---|
371 | file.close();
|
---|
372 | return ret;
|
---|
373 | }
|
---|
374 |
|
---|
375 | #endif // Q_OS_UNIX
|
---|
376 |
|
---|
377 |
|
---|
378 | static QSettings *cache = 0;
|
---|
379 | static QSingleCleanupHandler<QSettings> cleanup_cache;
|
---|
380 |
|
---|
381 | void QComLibrary::createInstanceInternal()
|
---|
382 | {
|
---|
383 | if ( library().isEmpty() )
|
---|
384 | return;
|
---|
385 |
|
---|
386 | QFileInfo fileinfo( library() );
|
---|
387 | QString lastModified = fileinfo.lastModified().toString(Qt::ISODate);
|
---|
388 | QString regkey = QString("/Qt Plugins %1.%2/%3")
|
---|
389 | .arg( ( QT_VERSION & 0xff0000 ) >> 16 )
|
---|
390 | .arg( ( QT_VERSION & 0xff00 ) >> 8 )
|
---|
391 | .arg( library() );
|
---|
392 | QStringList reg;
|
---|
393 | uint flags = 0;
|
---|
394 | QCString key;
|
---|
395 | bool query_done = FALSE;
|
---|
396 | bool warn_mismatch = TRUE;
|
---|
397 |
|
---|
398 | #ifdef QT_THREAD_SUPPORT
|
---|
399 | QMutexLocker locker( qt_global_mutexpool ?
|
---|
400 | qt_global_mutexpool->get( &cache ) : 0 );
|
---|
401 | #endif // QT_THREAD_SUPPORT
|
---|
402 |
|
---|
403 | if ( ! cache ) {
|
---|
404 | cache = new QSettings;
|
---|
405 | cache->insertSearchPath( QSettings::Windows, "/Trolltech" );
|
---|
406 | cleanup_cache.set( &cache );
|
---|
407 | }
|
---|
408 |
|
---|
409 | reg = cache->readListEntry( regkey );
|
---|
410 | if ( reg.count() == 4 ) {
|
---|
411 | // check timestamp
|
---|
412 | if ( lastModified == reg[3] ) {
|
---|
413 | qt_version = reg[0].toUInt(0, 16);
|
---|
414 | flags = reg[1].toUInt(0, 16);
|
---|
415 | key = reg[2].latin1();
|
---|
416 |
|
---|
417 | query_done = TRUE;
|
---|
418 | warn_mismatch = FALSE;
|
---|
419 | }
|
---|
420 | }
|
---|
421 |
|
---|
422 | #if defined(Q_OS_UNIX)
|
---|
423 | if ( ! query_done ) {
|
---|
424 | // get the query information directly from the plugin without loading
|
---|
425 | if ( qt_unix_query( library(), &qt_version, &flags, &key ) ) {
|
---|
426 | // info read succesfully from library
|
---|
427 | query_done = TRUE;
|
---|
428 | }
|
---|
429 | }
|
---|
430 | #else // !Q_OS_UNIX
|
---|
431 | if ( ! query_done ) {
|
---|
432 | // get the query information by loading the plugin
|
---|
433 | if ( !isLoaded() ) {
|
---|
434 | Q_ASSERT( entry == 0 );
|
---|
435 | if ( !load() )
|
---|
436 | return;
|
---|
437 | }
|
---|
438 |
|
---|
439 | # ifdef Q_CC_BOR
|
---|
440 | typedef const char * __stdcall (*UCMQueryVerificationDataProc)();
|
---|
441 | # else
|
---|
442 | typedef const char * (*UCMQueryVerificationDataProc)();
|
---|
443 | # endif
|
---|
444 | UCMQueryVerificationDataProc ucmQueryVerificationdataProc;
|
---|
445 | ucmQueryVerificationdataProc =
|
---|
446 | (UCMQueryVerificationDataProc) resolve( "qt_ucm_query_verification_data" );
|
---|
447 |
|
---|
448 | if ( !ucmQueryVerificationdataProc ||
|
---|
449 | !qt_parse_pattern( ucmQueryVerificationdataProc(),
|
---|
450 | &qt_version, &flags, &key ) ) {
|
---|
451 | qt_version = flags = 0;
|
---|
452 | key = "unknown";
|
---|
453 | } else {
|
---|
454 | query_done = TRUE;
|
---|
455 | }
|
---|
456 | }
|
---|
457 | #endif // Q_OS_UNIX
|
---|
458 |
|
---|
459 | QStringList queried;
|
---|
460 | queried << QString::number( qt_version,16 )
|
---|
461 | << QString::number( flags, 16 )
|
---|
462 | << key
|
---|
463 | << lastModified;
|
---|
464 |
|
---|
465 | if ( queried != reg ) {
|
---|
466 | cache->writeEntry( regkey, queried );
|
---|
467 | // delete the cache, which forces the settings to be written
|
---|
468 | delete cache;
|
---|
469 | cache = 0;
|
---|
470 | }
|
---|
471 |
|
---|
472 | if ( ! query_done ) {
|
---|
473 | if ( warn_mismatch ) {
|
---|
474 | qWarning( "Conflict in %s:\n Plugin cannot be queried successfully!",
|
---|
475 | (const char*) QFile::encodeName( library() ) );
|
---|
476 | }
|
---|
477 | unload();
|
---|
478 | return;
|
---|
479 | }
|
---|
480 |
|
---|
481 | if ( ! qt_verify( library(), qt_version, flags, key, warn_mismatch ) ) {
|
---|
482 | unload();
|
---|
483 | return;
|
---|
484 | } else if ( !isLoaded() ) {
|
---|
485 | Q_ASSERT( entry == 0 );
|
---|
486 | if ( !load() )
|
---|
487 | return;
|
---|
488 | }
|
---|
489 |
|
---|
490 | #ifdef Q_CC_BOR
|
---|
491 | typedef QUnknownInterface* __stdcall (*UCMInstanceProc)();
|
---|
492 | #else
|
---|
493 | typedef QUnknownInterface* (*UCMInstanceProc)();
|
---|
494 | #endif
|
---|
495 | UCMInstanceProc ucmInstanceProc;
|
---|
496 | ucmInstanceProc = (UCMInstanceProc) resolve( "ucm_instantiate" );
|
---|
497 | #if defined(QT_DEBUG_COMPONENT)
|
---|
498 | if ( !ucmInstanceProc )
|
---|
499 | qWarning( "%s: Not a UCOM library.", (const char*) QFile::encodeName(library()) );
|
---|
500 | #endif
|
---|
501 | entry = ucmInstanceProc ? ucmInstanceProc() : 0;
|
---|
502 |
|
---|
503 | if ( entry ) {
|
---|
504 | if ( entry->queryInterface( IID_QLibrary, (QUnknownInterface**)&libiface ) == QS_OK ) {
|
---|
505 | if ( libiface && !libiface->init() ) {
|
---|
506 | libiface->release();
|
---|
507 | libiface = 0;
|
---|
508 | unload();
|
---|
509 | return;
|
---|
510 | }
|
---|
511 | }
|
---|
512 | } else {
|
---|
513 | #if defined(QT_DEBUG_COMPONENT)
|
---|
514 | qWarning( "%s: No exported component provided.", (const char*) QFile::encodeName(library()) );
|
---|
515 | #endif
|
---|
516 | unload();
|
---|
517 | }
|
---|
518 | }
|
---|
519 |
|
---|
520 | QRESULT QComLibrary::queryInterface( const QUuid& request, QUnknownInterface** iface )
|
---|
521 | {
|
---|
522 | if ( !entry )
|
---|
523 | createInstanceInternal();
|
---|
524 | return entry ? entry->queryInterface( request, iface ) : QE_NOCOMPONENT;
|
---|
525 | }
|
---|
526 |
|
---|
527 | uint QComLibrary::qtVersion()
|
---|
528 | {
|
---|
529 | if ( !entry )
|
---|
530 | createInstanceInternal();
|
---|
531 | return entry ? qt_version : 0;
|
---|
532 | }
|
---|
533 |
|
---|
534 |
|
---|
535 | #endif // QT_NO_COMPONENT
|
---|