1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtDBus module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "qdbusconnection.h"
42 #include "qdbusconnection_p.h"
43 
44 #include <qdebug.h>
45 #include <qcoreapplication.h>
46 #include <qstringlist.h>
47 #include <qvector.h>
48 #include <qtimer.h>
49 #include <qthread.h>
50 #include <QtCore/private/qlocking_p.h>
51 
52 #include "qdbusconnectioninterface.h"
53 #include "qdbuserror.h"
54 #include "qdbusmessage.h"
55 #include "qdbusmessage_p.h"
56 #include "qdbusinterface_p.h"
57 #include "qdbusutil_p.h"
58 #include "qdbusconnectionmanager_p.h"
59 #include "qdbuspendingcall_p.h"
60 
61 #include "qdbusthreaddebug_p.h"
62 
63 #include <algorithm>
64 
65 #ifdef interface
66 #undef interface
67 #endif
68 
69 #ifndef QT_NO_DBUS
70 
71 QT_BEGIN_NAMESPACE
72 
73 #ifdef Q_OS_WIN
74 static void preventDllUnload();
75 #endif
76 
77 Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
78 
79 struct QDBusConnectionManager::ConnectionRequestData
80 {
81     enum RequestType {
82         ConnectToStandardBus,
83         ConnectToBusByAddress,
84         ConnectToPeerByAddress
85     } type;
86 
87     union {
88         QDBusConnection::BusType busType;
89         const QString *busAddress;
90     };
91     const QString *name;
92 
93     QDBusConnectionPrivate *result;
94 
95     bool suspendedDelivery;
96 };
97 
busConnection(QDBusConnection::BusType type)98 QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
99 {
100     Q_STATIC_ASSERT(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
101     Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
102 
103     if (!qdbus_loadLibDBus())
104         return nullptr;
105 
106     // we'll start in suspended delivery mode if we're in the main thread
107     // (the event loop will resume delivery)
108     bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
109 
110     const auto locker = qt_scoped_lock(defaultBusMutex);
111     if (defaultBuses[type])
112         return defaultBuses[type];
113 
114     QString name = QStringLiteral("qt_default_session_bus");
115     if (type == QDBusConnection::SystemBus)
116         name = QStringLiteral("qt_default_system_bus");
117     return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
118 }
119 
connection(const QString & name) const120 QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
121 {
122     return connectionHash.value(name, 0);
123 }
124 
removeConnection(const QString & name)125 void QDBusConnectionManager::removeConnection(const QString &name)
126 {
127     QDBusConnectionPrivate *d = nullptr;
128     d = connectionHash.take(name);
129     if (d && !d->ref.deref())
130         d->deleteLater();
131 
132     // Static objects may be keeping the connection open.
133     // However, it is harmless to have outstanding references to a connection that is
134     // closing as long as those references will be soon dropped without being used.
135 
136     // ### Output a warning if connections are being used after they have been removed.
137 }
138 
QDBusConnectionManager()139 QDBusConnectionManager::QDBusConnectionManager()
140 {
141     connect(this, &QDBusConnectionManager::connectionRequested,
142             this, &QDBusConnectionManager::executeConnectionRequest, Qt::BlockingQueuedConnection);
143     connect(this, &QDBusConnectionManager::serverRequested,
144             this, &QDBusConnectionManager::createServer, Qt::BlockingQueuedConnection);
145     moveToThread(this);         // ugly, don't do this in other projects
146 
147 #ifdef Q_OS_WIN
148     // prevent the library from being unloaded on Windows. See comments in the function.
149     preventDllUnload();
150 #endif
151     defaultBuses[0] = defaultBuses[1] = nullptr;
152     start();
153 }
154 
~QDBusConnectionManager()155 QDBusConnectionManager::~QDBusConnectionManager()
156 {
157     quit();
158     wait();
159 }
160 
instance()161 QDBusConnectionManager* QDBusConnectionManager::instance()
162 {
163     return _q_manager();
164 }
165 
166 Q_DBUS_EXPORT void qDBusBindToApplication();
qDBusBindToApplication()167 void qDBusBindToApplication()
168 {
169 }
170 
setConnection(const QString & name,QDBusConnectionPrivate * c)171 void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
172 {
173     connectionHash[name] = c;
174     c->name = name;
175 }
176 
run()177 void QDBusConnectionManager::run()
178 {
179     exec();
180 
181     // cleanup:
182     const auto locker = qt_scoped_lock(mutex);
183     for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
184          it != connectionHash.constEnd(); ++it) {
185         QDBusConnectionPrivate *d = it.value();
186         if (!d->ref.deref()) {
187             delete d;
188         } else {
189             d->closeConnection();
190             d->moveToThread(nullptr);     // allow it to be deleted in another thread
191         }
192     }
193     connectionHash.clear();
194 
195     // allow deletion from any thread without warning
196     moveToThread(nullptr);
197 }
198 
connectToBus(QDBusConnection::BusType type,const QString & name,bool suspendedDelivery)199 QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
200                                                              bool suspendedDelivery)
201 {
202     ConnectionRequestData data;
203     data.type = ConnectionRequestData::ConnectToStandardBus;
204     data.busType = type;
205     data.name = &name;
206     data.suspendedDelivery = suspendedDelivery;
207 
208     emit connectionRequested(&data);
209     if (suspendedDelivery && data.result->connection) {
210         data.result->ref.ref();
211         QDBusConnectionDispatchEnabler *o = new QDBusConnectionDispatchEnabler(data.result);
212         QTimer::singleShot(0, o, SLOT(execute()));
213         o->moveToThread(qApp->thread());    // qApp was checked in the caller
214     }
215     return data.result;
216 }
217 
connectToBus(const QString & address,const QString & name)218 QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
219 {
220     ConnectionRequestData data;
221     data.type = ConnectionRequestData::ConnectToBusByAddress;
222     data.busAddress = &address;
223     data.name = &name;
224     data.suspendedDelivery = false;
225 
226     emit connectionRequested(&data);
227     return data.result;
228 }
229 
connectToPeer(const QString & address,const QString & name)230 QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name)
231 {
232     ConnectionRequestData data;
233     data.type = ConnectionRequestData::ConnectToPeerByAddress;
234     data.busAddress = &address;
235     data.name = &name;
236     data.suspendedDelivery = false;
237 
238     emit connectionRequested(&data);
239     return data.result;
240 }
241 
executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData * data)242 void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data)
243 {
244     const auto locker = qt_scoped_lock(mutex);
245     const QString &name = *data->name;
246     QDBusConnectionPrivate *&d = data->result;
247 
248     // check if the connection exists by name
249     d = connection(name);
250     if (d || name.isEmpty())
251         return;
252 
253     d = new QDBusConnectionPrivate;
254     DBusConnection *c = nullptr;
255     QDBusErrorInternal error;
256     switch (data->type) {
257     case ConnectionRequestData::ConnectToStandardBus:
258         switch (data->busType) {
259         case QDBusConnection::SystemBus:
260             c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
261             break;
262         case QDBusConnection::SessionBus:
263             c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
264             break;
265         case QDBusConnection::ActivationBus:
266             c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
267             break;
268         }
269         break;
270 
271     case ConnectionRequestData::ConnectToBusByAddress:
272     case ConnectionRequestData::ConnectToPeerByAddress:
273         c = q_dbus_connection_open_private(data->busAddress->toUtf8().constData(), error);
274         if (c && data->type == ConnectionRequestData::ConnectToBusByAddress) {
275             // register on the bus
276             if (!q_dbus_bus_register(c, error)) {
277                 q_dbus_connection_unref(c);
278                 c = nullptr;
279             }
280         }
281         break;
282     }
283 
284     setConnection(name, d);
285     if (data->type == ConnectionRequestData::ConnectToPeerByAddress) {
286         d->setPeer(c, error);
287     } else {
288         // create the bus service
289         // will lock in QDBusConnectionPrivate::connectRelay()
290         d->setConnection(c, error);
291         d->createBusService();
292         if (c && data->suspendedDelivery)
293             d->setDispatchEnabled(false);
294     }
295 }
296 
createServer(const QString & address,void * server)297 void QDBusConnectionManager::createServer(const QString &address, void *server)
298 {
299     QDBusErrorInternal error;
300     QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
301     d->setServer(static_cast<QDBusServer *>(server),
302                  q_dbus_server_listen(address.toUtf8().constData(), error), error);
303 }
304 
305 /*!
306     \class QDBusConnection
307     \inmodule QtDBus
308     \since 4.2
309 
310     \brief The QDBusConnection class represents a connection to the D-Bus bus daemon.
311 
312     This class is the initial point in a D-Bus session. Using it, you
313     can get access to remote objects, interfaces; connect remote
314     signals to your object's slots; register objects, etc.
315 
316     D-Bus connections are created using the connectToBus() function,
317     which opens a connection to the server daemon and does the initial
318     handshaking, associating that connection with a name. Further
319     attempts to connect using the same name will return the same
320     connection.
321 
322     The connection is then torn down using the disconnectFromBus()
323     function.
324 
325     Once disconnected, calling connectToBus() will not reestablish a
326     connection, you must create a new QDBusConnection instance.
327 
328     As a convenience for the two most common connection types, the
329     sessionBus() and systemBus() functions return open connections to
330     the session server daemon and the system server daemon,
331     respectively. Those connections are opened when first used and are
332     closed when the QCoreApplication destructor is run.
333 
334     D-Bus also supports peer-to-peer connections, without the need for
335     a bus server daemon. Using this facility, two applications can
336     talk to each other and exchange messages. This can be achieved by
337     passing an address to connectToBus() function, which was opened by
338     another D-Bus application using QDBusServer.
339 */
340 
341 /*!
342     \enum QDBusConnection::BusType
343     Specifies the type of the bus connection. The valid bus types are:
344 
345     \value SessionBus           the session bus, associated with the running desktop session
346     \value SystemBus            the system bus, used to communicate with system-wide processes
347     \value ActivationBus        the activation bus, the "alias" for the bus that started the
348                                 service
349 
350     On the Session Bus, one can find other applications by the same user that are sharing the same
351     desktop session (hence the name). On the System Bus, however, processes shared for the whole
352     system are usually found.
353 */
354 
355 /*!
356     \enum QDBusConnection::RegisterOption
357     Specifies the options for registering objects with the connection. The possible values are:
358 
359     \value ExportAdaptors                       export the contents of adaptors found in this object
360 
361     \value ExportScriptableSlots                export this object's scriptable slots
362     \value ExportScriptableSignals              export this object's scriptable signals
363     \value ExportScriptableProperties           export this object's scriptable properties
364     \value ExportScriptableInvokables           export this object's scriptable invokables
365     \value ExportScriptableContents             shorthand form for ExportScriptableSlots |
366                                                 ExportScriptableSignals |
367                                                 ExportScriptableProperties
368 
369     \value ExportNonScriptableSlots             export this object's non-scriptable slots
370     \value ExportNonScriptableSignals           export this object's non-scriptable signals
371     \value ExportNonScriptableProperties        export this object's non-scriptable properties
372     \value ExportNonScriptableInvokables        export this object's non-scriptable invokables
373     \value ExportNonScriptableContents          shorthand form for ExportNonScriptableSlots |
374                                                 ExportNonScriptableSignals |
375                                                 ExportNonScriptableProperties
376 
377     \value ExportAllSlots                       export all of this object's slots
378     \value ExportAllSignals                     export all of this object's signals
379     \value ExportAllProperties                  export all of this object's properties
380     \value ExportAllInvokables                  export all of this object's invokables
381     \value ExportAllContents                    export all of this object's contents
382     \value ExportChildObjects                   export this object's child objects
383 
384     \sa registerObject(), QDBusAbstractAdaptor, {usingadaptors.html}{Using adaptors}
385 */
386 
387 /*!
388     \internal
389     \since 4.8
390     \enum QDBusConnection::VirtualObjectRegisterOption
391     Specifies the options for registering virtual objects with the connection. The possible values are:
392 
393     \value SingleNode                           register a virtual object to handle one path only
394     \value SubPath                              register a virtual object so that it handles all sub paths
395 
396     \sa registerVirtualObject(), QDBusVirtualObject
397 */
398 
399 /*!
400     \enum QDBusConnection::UnregisterMode
401     The mode for unregistering an object path:
402 
403     \value UnregisterNode       unregister this node only: do not unregister child objects
404     \value UnregisterTree       unregister this node and all its sub-tree
405 
406     Note, however, if this object was registered with the ExportChildObjects option, UnregisterNode
407     will unregister the child objects too.
408 */
409 
410 /*!
411     \since 4.8
412     \enum QDBusConnection::ConnectionCapability
413 
414     This enum describes the available capabilities for a D-Bus connection.
415 
416     \value UnixFileDescriptorPassing        enables passing of Unix file descriptors to other processes
417                                             (see QDBusUnixFileDescriptor)
418 
419     \sa connectionCapabilities()
420 */
421 
422 /*!
423     Creates a QDBusConnection object attached to the connection with name \a name.
424 
425     This does not open the connection. You have to call connectToBus() to open it.
426 */
QDBusConnection(const QString & name)427 QDBusConnection::QDBusConnection(const QString &name)
428 {
429     if (name.isEmpty() || _q_manager.isDestroyed()) {
430         d = nullptr;
431     } else {
432         const auto locker = qt_scoped_lock(_q_manager()->mutex);
433         d = _q_manager()->connection(name);
434         if (d)
435             d->ref.ref();
436     }
437 }
438 
439 /*!
440     Creates a copy of the \a other connection.
441 */
QDBusConnection(const QDBusConnection & other)442 QDBusConnection::QDBusConnection(const QDBusConnection &other)
443 {
444     d = other.d;
445     if (d)
446         d->ref.ref();
447 }
448 
449 /*!
450   \internal
451    Creates a connection object with the given \a dd as private object.
452 */
QDBusConnection(QDBusConnectionPrivate * dd)453 QDBusConnection::QDBusConnection(QDBusConnectionPrivate *dd)
454 {
455     d = dd;
456     if (d)
457         d->ref.ref();
458 }
459 
460 /*!
461     Disposes of this object. This does not close the connection: you
462     have to call disconnectFromBus() to do that.
463 */
~QDBusConnection()464 QDBusConnection::~QDBusConnection()
465 {
466     if (d && !d->ref.deref())
467         d->deleteLater();
468 }
469 
470 /*!
471     Creates a copy of the connection \a other in this object. Note
472     that the connection this object referenced before the copy, is not
473     spontaneously disconnected.
474 
475     \sa disconnectFromBus()
476 */
operator =(const QDBusConnection & other)477 QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
478 {
479     if (other.d)
480         other.d->ref.ref();
481     if (d && !d->ref.deref())
482         d->deleteLater();
483     d = other.d;
484     return *this;
485 }
486 
487 /*!
488     Opens a connection of type \a type to one of the known busses and
489     associate with it the connection name \a name. Returns a
490     QDBusConnection object associated with that connection.
491 */
connectToBus(BusType type,const QString & name)492 QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
493 {
494     if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
495         QDBusConnectionPrivate *d = nullptr;
496         return QDBusConnection(d);
497     }
498     return QDBusConnection(_q_manager()->connectToBus(type, name, false));
499 }
500 
501 /*!
502     Opens a connection to a private bus on address \a address and associate with it the
503     connection name \a name. Returns a QDBusConnection object associated with that connection.
504 */
connectToBus(const QString & address,const QString & name)505 QDBusConnection QDBusConnection::connectToBus(const QString &address,
506                                               const QString &name)
507 {
508     if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
509         QDBusConnectionPrivate *d = nullptr;
510         return QDBusConnection(d);
511     }
512     return QDBusConnection(_q_manager()->connectToBus(address, name));
513 }
514 /*!
515     \since 4.8
516 
517     Opens a peer-to-peer connection on address \a address and associate with it the
518     connection name \a name. Returns a QDBusConnection object associated with that connection.
519 */
connectToPeer(const QString & address,const QString & name)520 QDBusConnection QDBusConnection::connectToPeer(const QString &address,
521                                                const QString &name)
522 {
523     if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
524         QDBusConnectionPrivate *d = nullptr;
525         return QDBusConnection(d);
526     }
527     return QDBusConnection(_q_manager()->connectToPeer(address, name));
528 }
529 
530 /*!
531     Closes the bus connection of name \a name.
532 
533     Note that if there are still QDBusConnection objects associated
534     with the same connection, the connection will not be closed until
535     all references are dropped. However, no further references can be
536     created using the QDBusConnection constructor.
537 */
disconnectFromBus(const QString & name)538 void QDBusConnection::disconnectFromBus(const QString &name)
539 {
540     if (_q_manager()) {
541         const auto locker = qt_scoped_lock(_q_manager()->mutex);
542         QDBusConnectionPrivate *d = _q_manager()->connection(name);
543         if (d && d->mode != QDBusConnectionPrivate::ClientMode)
544             return;
545         _q_manager()->removeConnection(name);
546     }
547 }
548 
549 /*!
550     \since 4.8
551 
552     Closes the peer connection of name \a name.
553 
554     Note that if there are still QDBusConnection objects associated
555     with the same connection, the connection will not be closed until
556     all references are dropped. However, no further references can be
557     created using the QDBusConnection constructor.
558 */
disconnectFromPeer(const QString & name)559 void QDBusConnection::disconnectFromPeer(const QString &name)
560 {
561     if (_q_manager()) {
562         const auto locker = qt_scoped_lock(_q_manager()->mutex);
563         QDBusConnectionPrivate *d = _q_manager()->connection(name);
564         if (d && d->mode != QDBusConnectionPrivate::PeerMode)
565             return;
566         _q_manager()->removeConnection(name);
567     }
568 }
569 
570 /*!
571     Sends the \a message over this connection, without waiting for a
572     reply. This is suitable for errors, signals, and return values as
573     well as calls whose return values are not necessary.
574 
575     Returns \c true if the message was queued successfully, false otherwise.
576 */
send(const QDBusMessage & message) const577 bool QDBusConnection::send(const QDBusMessage &message) const
578 {
579     if (!d || !d->connection) {
580         QDBusError err = QDBusError(QDBusError::Disconnected,
581                                     QDBusUtil::disconnectedErrorMessage());
582         if (d)
583             d->lastError = err;
584         return false;
585     }
586     return d->send(message);
587 }
588 
589 /*!
590     Sends the \a message over this connection and returns immediately.
591     When the reply is received, the method \a returnMethod is called in
592     the \a receiver object. If an error occurs, the method \a errorMethod
593     will be called instead.
594 
595     If no reply is received within \a timeout milliseconds, an automatic
596     error will be delivered indicating the expiration of the call.
597     The default \a timeout is -1, which will be replaced with an
598     implementation-defined value that is suitable for inter-process
599     communications (generally, 25 seconds).
600 
601     This function is suitable for method calls only. It is guaranteed
602     that the slot will be called exactly once with the reply, as long
603     as the parameter types match and no error occurs.
604 
605     Returns \c true if the message was sent, or false if the message could
606     not be sent.
607 */
callWithCallback(const QDBusMessage & message,QObject * receiver,const char * returnMethod,const char * errorMethod,int timeout) const608 bool QDBusConnection::callWithCallback(const QDBusMessage &message, QObject *receiver,
609                                        const char *returnMethod, const char *errorMethod,
610                                        int timeout) const
611 {
612     if (!d || !d->connection) {
613         QDBusError err = QDBusError(QDBusError::Disconnected,
614                                     QDBusUtil::disconnectedErrorMessage());
615         if (d)
616             d->lastError = err;
617         return false;
618     }
619     return d->sendWithReplyAsync(message, receiver, returnMethod, errorMethod, timeout) != nullptr;
620 }
621 
622 /*!
623     \overload
624     \deprecated
625     Sends the \a message over this connection and returns immediately.
626     When the reply is received, the method \a returnMethod is called in
627     the \a receiver object.
628 
629     This function is suitable for method calls only. It is guaranteed
630     that the slot will be called exactly once with the reply, as long
631     as the parameter types match and no error occurs.
632 
633     This function is dangerous because it cannot report errors, including
634     the expiration of the timeout.
635 
636     Returns \c true if the message was sent, or false if the message could
637     not be sent.
638 */
callWithCallback(const QDBusMessage & message,QObject * receiver,const char * returnMethod,int timeout) const639 bool QDBusConnection::callWithCallback(const QDBusMessage &message, QObject *receiver,
640                                        const char *returnMethod, int timeout) const
641 {
642     return callWithCallback(message, receiver, returnMethod, nullptr, timeout);
643 }
644 
645 /*!
646     Sends the \a message over this connection and blocks, waiting for
647     a reply, for at most \a timeout milliseconds. This function is
648     suitable for method calls only. It returns the reply message as
649     its return value, which will be either of type
650     QDBusMessage::ReplyMessage or QDBusMessage::ErrorMessage.
651 
652     If no reply is received within \a timeout milliseconds, an automatic
653     error will be delivered indicating the expiration of the call.
654     The default \a timeout is -1, which will be replaced with an
655     implementation-defined value that is suitable for inter-process
656     communications (generally, 25 seconds).
657 
658     See the QDBusInterface::call() function for a more friendly way
659     of placing calls.
660 
661     \warning If \a mode is QDBus::BlockWithGui, this function will
662              reenter the Qt event loop in order to wait for the
663              reply. During the wait, it may deliver signals and other
664              method calls to your application. Therefore, it must be
665              prepared to handle a reentrancy whenever a call is
666              placed with call().
667 */
call(const QDBusMessage & message,QDBus::CallMode mode,int timeout) const668 QDBusMessage QDBusConnection::call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const
669 {
670     if (!d || !d->connection) {
671         QDBusError err = QDBusError(QDBusError::Disconnected,
672                                     QDBusUtil::disconnectedErrorMessage());
673         if (d)
674             d->lastError = err;
675 
676         return QDBusMessage::createError(err);
677     }
678 
679     if (mode != QDBus::NoBlock)
680         return d->sendWithReply(message, mode, timeout);
681 
682     d->send(message);
683     QDBusMessage retval;
684     retval << QVariant(); // add one argument (to avoid .at(0) problems)
685     return retval;
686 }
687 
688 /*!
689     \since 4.5
690     Sends the \a message over this connection and returns
691     immediately. This function is suitable for method calls only. It
692     returns an object of type QDBusPendingCall which can be used to
693     track the status of the reply.
694 
695     If no reply is received within \a timeout milliseconds, an automatic
696     error will be delivered indicating the expiration of the call. The
697     default \a timeout is -1, which will be replaced with an
698     implementation-defined value that is suitable for inter-process
699     communications (generally, 25 seconds). This timeout is also the
700     upper limit for waiting in QDBusPendingCall::waitForFinished().
701 
702     See the QDBusInterface::asyncCall() function for a more friendly way
703     of placing calls.
704 */
asyncCall(const QDBusMessage & message,int timeout) const705 QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int timeout) const
706 {
707     if (!d || !d->connection) {
708         return QDBusPendingCall(nullptr); // null pointer -> disconnected
709     }
710 
711     QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, nullptr, nullptr, nullptr, timeout);
712     return QDBusPendingCall(priv);
713 }
714 
715 /*!
716     Connects the signal specified by the \a service, \a path, \a interface and \a name parameters to
717     the slot \a slot in object \a receiver. The arguments \a service and \a path can be empty,
718     denoting a connection to any signal of the (\a interface, \a name) pair, from any remote
719     application.
720 
721     Returns \c true if the connection was successful.
722 
723     \warning The signal will only be delivered to the slot if the parameters match. This verification
724              can be done only when the signal is received, not at connection time.
725 */
connect(const QString & service,const QString & path,const QString & interface,const QString & name,QObject * receiver,const char * slot)726 bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
727                               const QString &name, QObject *receiver, const char *slot)
728 {
729     return connect(service, path, interface, name, QStringList(), QString(), receiver, slot);
730 }
731 
732 /*!
733     \overload
734 
735     Connects the signal to the slot \a slot in object \a
736     receiver. Unlike the previous connect() overload, this function
737     allows one to specify the parameter signature to be connected
738     using the \a signature variable. The function will then verify
739     that this signature can be delivered to the slot specified by \a
740     slot and return false otherwise.
741 
742     Returns \c true if the connection was successful.
743 
744     \note This function verifies that the signal signature matches the
745           slot's parameters, but it does not verify that the actual
746           signal exists with the given signature in the remote
747           service.
748 */
connect(const QString & service,const QString & path,const QString & interface,const QString & name,const QString & signature,QObject * receiver,const char * slot)749 bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
750                               const QString &name, const QString &signature,
751                               QObject *receiver, const char *slot)
752 {
753     return connect(service, path, interface, name, QStringList(), signature, receiver, slot);
754 }
755 
756 /*!
757     \overload
758     \since 4.6
759 
760     Connects the signal to the slot \a slot in object \a
761     receiver. Unlike the previous connect() overload, this function
762     allows one to specify the parameter signature to be connected
763     using the \a signature variable. The function will then verify
764     that this signature can be delivered to the slot specified by \a
765     slot and return false otherwise.
766 
767     The \a argumentMatch parameter lists the string parameters to be matched,
768     in sequential order. Note that, to match an empty string, you need to
769     pass a QString that is empty but not null (i.e., QString("")). A null
770     QString skips matching at that position.
771 
772     Returns \c true if the connection was successful.
773 
774     \note This function verifies that the signal signature matches the
775           slot's parameters, but it does not verify that the actual
776           signal exists with the given signature in the remote
777           service.
778 */
connect(const QString & service,const QString & path,const QString & interface,const QString & name,const QStringList & argumentMatch,const QString & signature,QObject * receiver,const char * slot)779 bool QDBusConnection::connect(const QString &service, const QString &path, const QString& interface,
780                               const QString &name, const QStringList &argumentMatch, const QString &signature,
781                               QObject *receiver, const char *slot)
782 {
783 
784     if (!receiver || !slot || !d || !d->connection)
785         return false;
786     if (interface.isEmpty() && name.isEmpty())
787         return false;
788     if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface)) {
789 #ifndef QT_NO_DEBUG
790         qWarning("QDBusConnection::connect: interface name '%s' is not valid", interface.toLatin1().constData());
791 #endif
792         return false;
793     }
794     if (!service.isEmpty() && !QDBusUtil::isValidBusName(service)) {
795 #ifndef QT_NO_DEBUG
796         qWarning("QDBusConnection::connect: service name '%s' is not valid", service.toLatin1().constData());
797 #endif
798         return false;
799     }
800     if (!path.isEmpty() && !QDBusUtil::isValidObjectPath(path)) {
801 #ifndef QT_NO_DEBUG
802         qWarning("QDBusConnection::connect: object path '%s' is not valid", path.toLatin1().constData());
803 #endif
804         return false;
805     }
806 
807     return d->connectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot);
808 }
809 
810 /*!
811     Disconnects the signal specified by the \a service, \a path, \a interface
812     and \a name parameters from the slot \a slot in object \a receiver. The
813     arguments must be the same as passed to the connect() function.
814 
815     Returns \c true if the disconnection was successful.
816 */
disconnect(const QString & service,const QString & path,const QString & interface,const QString & name,QObject * receiver,const char * slot)817 bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString &interface,
818                                  const QString &name, QObject *receiver, const char *slot)
819 {
820     return disconnect(service, path, interface, name, QStringList(), QString(), receiver, slot);
821 }
822 
823 /*!
824     \overload
825 
826     Disconnects the signal specified by the \a service, \a path, \a
827     interface, \a name, and \a signature parameters from the slot \a slot in
828     object \a receiver. The arguments must be the same as passed to the
829     connect() function.
830 
831     Returns \c true if the disconnection was successful.
832 */
disconnect(const QString & service,const QString & path,const QString & interface,const QString & name,const QString & signature,QObject * receiver,const char * slot)833 bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString& interface,
834                                  const QString &name, const QString &signature,
835                                  QObject *receiver, const char *slot)
836 {
837     return disconnect(service, path, interface, name, QStringList(), signature, receiver, slot);
838 }
839 
840 /*!
841     \overload
842     \since 4.6
843 
844     Disconnects the signal specified by the \a service, \a path, \a
845     interface, \a name, \a argumentMatch, and \a signature parameters from
846     the slot \a slot in object \a receiver. The arguments must be the same as
847     passed to the connect() function.
848 
849     Returns \c true if the disconnection was successful.
850 */
disconnect(const QString & service,const QString & path,const QString & interface,const QString & name,const QStringList & argumentMatch,const QString & signature,QObject * receiver,const char * slot)851 bool QDBusConnection::disconnect(const QString &service, const QString &path, const QString& interface,
852                                  const QString &name, const QStringList &argumentMatch, const QString &signature,
853                                  QObject *receiver, const char *slot)
854 {
855     if (!receiver || !slot || !d || !d->connection)
856         return false;
857     if (!interface.isEmpty() && !QDBusUtil::isValidInterfaceName(interface))
858         return false;
859     if (interface.isEmpty() && name.isEmpty())
860         return false;
861 
862     return d->disconnectSignal(service, path, interface, name, argumentMatch, signature, receiver, slot);
863 }
864 
865 /*!
866     Registers the object \a object at path \a path and returns \c true if
867     the registration was successful. The \a options parameter
868     specifies how much of the object \a object will be exposed through
869     D-Bus.
870 
871     This function does not replace existing objects: if there is already an object registered at
872     path \a path, this function will return false. Use unregisterObject() to unregister it first.
873 
874     The ExportChildObjects flag exports child objects on D-Bus based on the
875     path of the registered objects and the QObject::objectName of the child.
876     Therefore, it is important for the child object to have an object name.
877 
878     You cannot register an object as a child object of an object that
879     was registered with ExportChildObjects.
880 */
registerObject(const QString & path,QObject * object,RegisterOptions options)881 bool QDBusConnection::registerObject(const QString &path, QObject *object, RegisterOptions options)
882 {
883    return registerObject(path, QString(), object, options);
884 }
885 
886 /*!
887     \overload
888     \since 5.5
889 
890     Registers the object \a object at path \a path with interface name \a interface
891     and returns \c true if the registration was successful. The \a options parameter
892     specifies how much of the object \a object will be exposed through
893     D-Bus.
894 
895     This function does not replace existing objects: if there is already an object registered at
896     path \a path, this function will return false. Use unregisterObject() to unregister it first.
897 
898     The ExportChildObjects flag exports child objects on D-Bus based on the
899     path of the registered objects and the QObject::objectName of the child.
900     Therefore, it is important for the child object to have an object name.
901 
902     You cannot register an object as a child object of an object that
903     was registered with ExportChildObjects.
904 */
registerObject(const QString & path,const QString & interface,QObject * object,RegisterOptions options)905 bool QDBusConnection::registerObject(const QString &path, const QString &interface, QObject *object, RegisterOptions options)
906 {
907     Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registerObject",
908                "Invalid object path given");
909     if (!d || !d->connection || !object || !options || !QDBusUtil::isValidObjectPath(path))
910         return false;
911 
912     auto pathComponents = path.splitRef(QLatin1Char('/'));
913     if (pathComponents.constLast().isEmpty())
914         pathComponents.removeLast();
915     QDBusWriteLocker locker(RegisterObjectAction, d);
916 
917     // lower-bound search for where this object should enter in the tree
918     QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator node = &d->rootNode;
919     int i = 1;
920     while (node) {
921         if (pathComponents.count() == i) {
922             // this node exists
923             // consider it free if there's no object here and the user is not trying to
924             // replace the object sub-tree
925             if (node->obj)
926                 return false;
927 
928             if (options & QDBusConnectionPrivate::VirtualObject) {
929                 if (options & SubPath && !node->children.isEmpty())
930                     return false;
931             } else {
932                 if ((options & ExportChildObjects && !node->children.isEmpty()))
933                     return false;
934             }
935             // we can add the object here
936             node->obj = object;
937             node->flags = options;
938             node->interfaceName = interface;
939 
940             d->registerObject(node);
941             //qDebug("REGISTERED FOR %s", path.toLocal8Bit().constData());
942             return true;
943         }
944 
945         // if a virtual object occupies this path, return false
946         if (node->obj && (node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath)) {
947             //qDebug("Cannot register object at %s because QDBusVirtualObject handles all sub-paths.",
948             //       qPrintable(path));
949             return false;
950         }
951 
952         // find the position where we'd insert the node
953         QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it =
954             std::lower_bound(node->children.begin(), node->children.end(), pathComponents.at(i));
955         if (it != node->children.end() && it->name == pathComponents.at(i)) {
956             // match: this node exists
957             node = it;
958 
959             // are we allowed to go deeper?
960             if (node->flags & ExportChildObjects) {
961                 // we're not
962                 //qDebug("Cannot register object at %s because %s exports its own child objects",
963                 //       qPrintable(path), qPrintable(pathComponents.at(i)));
964                 return false;
965             }
966         } else {
967             // add entry
968             node = node->children.insert(it, pathComponents.at(i).toString());
969         }
970 
971         // iterate
972         ++i;
973     }
974 
975     Q_ASSERT_X(false, "QDBusConnection::registerObject", "The impossible happened");
976     return false;
977 }
978 
979 /*!
980     \internal
981     \since 4.8
982     Registers a QDBusTreeNode for a path. It can handle a path including all child paths, thus
983     handling multiple DBus nodes.
984 
985     To unregister a QDBusTreeNode use the unregisterObject() function with its path.
986 */
registerVirtualObject(const QString & path,QDBusVirtualObject * treeNode,VirtualObjectRegisterOption options)987 bool QDBusConnection::registerVirtualObject(const QString &path, QDBusVirtualObject *treeNode,
988                       VirtualObjectRegisterOption options)
989 {
990     int opts = options | QDBusConnectionPrivate::VirtualObject;
991     return registerObject(path, (QObject*) treeNode, (RegisterOptions) opts);
992 }
993 
994 /*!
995     Unregisters an object that was registered with the registerObject() at the object path given by
996     \a path and, if \a mode is QDBusConnection::UnregisterTree, all of its sub-objects too.
997 
998     Note that you cannot unregister objects that were not registered with registerObject().
999 */
unregisterObject(const QString & path,UnregisterMode mode)1000 void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode)
1001 {
1002     if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
1003         return;
1004 
1005     QDBusWriteLocker locker(UnregisterObjectAction, d);
1006     d->unregisterObject(path, mode);
1007 }
1008 
1009 /*!
1010     Return the object that was registered with the registerObject() at the object path given by
1011     \a path.
1012 */
objectRegisteredAt(const QString & path) const1013 QObject *QDBusConnection::objectRegisteredAt(const QString &path) const
1014 {
1015     Q_ASSERT_X(QDBusUtil::isValidObjectPath(path), "QDBusConnection::registeredObject",
1016                "Invalid object path given");
1017     if (!d || !d->connection || !QDBusUtil::isValidObjectPath(path))
1018         return nullptr;
1019 
1020     auto pathComponents = path.splitRef(QLatin1Char('/'));
1021     if (pathComponents.constLast().isEmpty())
1022         pathComponents.removeLast();
1023 
1024     // lower-bound search for where this object should enter in the tree
1025     QDBusReadLocker lock(ObjectRegisteredAtAction, d);
1026     const QDBusConnectionPrivate::ObjectTreeNode *node = &d->rootNode;
1027 
1028     int i = 1;
1029     while (node) {
1030         if (pathComponents.count() == i)
1031             return node->obj;
1032         if ((node->flags & QDBusConnectionPrivate::VirtualObject) && (node->flags & QDBusConnection::SubPath))
1033             return node->obj;
1034 
1035         QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
1036             std::lower_bound(node->children.constBegin(), node->children.constEnd(), pathComponents.at(i));
1037         if (it == node->children.constEnd() || it->name != pathComponents.at(i))
1038             break;              // node not found
1039 
1040         node = it;
1041         ++i;
1042     }
1043     return nullptr;
1044 }
1045 
1046 
1047 
1048 /*!
1049     Returns a QDBusConnectionInterface object that represents the
1050     D-Bus server interface on this connection.
1051 */
interface() const1052 QDBusConnectionInterface *QDBusConnection::interface() const
1053 {
1054     if (!d || d->mode != QDBusConnectionPrivate::ClientMode)
1055         return nullptr;
1056     return d->busService;
1057 }
1058 
1059 /*!
1060     \internal
1061     \since 4.8
1062 
1063     Returns the internal, implementation-defined pointer for this
1064     connection. Currently, this returns a DBusConnection* pointer,
1065     without changing the reference count. It is the responsibility of
1066     the caller to call dbus_connection_ref if it wants to store the
1067     pointer.
1068 */
internalPointer() const1069 void *QDBusConnection::internalPointer() const
1070 {
1071     return d ? d->connection : nullptr;
1072 }
1073 
1074 /*!
1075     Returns \c true if this QDBusConnection object is connected.
1076 */
isConnected() const1077 bool QDBusConnection::isConnected() const
1078 {
1079     return d && d->connection && q_dbus_connection_get_is_connected(d->connection);
1080 }
1081 
1082 /*!
1083     Returns the last error that happened in this connection.
1084 
1085     This function is provided for low-level code. If you're using
1086     QDBusInterface::call(), error codes are reported by its return
1087     value.
1088 
1089     \sa QDBusInterface, QDBusMessage
1090 */
lastError() const1091 QDBusError QDBusConnection::lastError() const
1092 {
1093     return d ? d->lastError : QDBusError(QDBusError::Disconnected, QDBusUtil::disconnectedErrorMessage());
1094 }
1095 
1096 /*!
1097     Returns the unique connection name for this connection, if this QDBusConnection object is
1098     connected, or an empty QString otherwise.
1099 
1100     A Unique Connection Name is a string in the form ":x.xxx" (where x
1101     are decimal digits) that is assigned by the D-Bus server daemon
1102     upon connection. It uniquely identifies this client in the bus.
1103 
1104     This function returns an empty QString for peer-to-peer connections.
1105 */
baseService() const1106 QString QDBusConnection::baseService() const
1107 {
1108     return d ? d->baseService : QString();
1109 }
1110 
1111 /*!
1112     \since 4.5
1113 
1114     Returns the connection name for this connection, as given as the
1115     name parameter to connectToBus().
1116 
1117     The connection name can be used to uniquely identify actual
1118     underlying connections to buses.  Copies made from a single
1119     connection will always implicitly share the underlying connection,
1120     and hence will have the same connection name.
1121 
1122     Inversely, two connections having different connection names will
1123     always either be connected to different buses, or have a different
1124     unique name (as returned by baseService()) on that bus.
1125 
1126     \sa connectToBus(), disconnectFromBus()
1127 */
name() const1128 QString QDBusConnection::name() const
1129 {
1130     return d ? d->name : QString();
1131 }
1132 
1133 /*!
1134     \since 4.8
1135 
1136     Returns the capabilities of this connection as negotiated with the bus
1137     server or peer. If this QDBusConnection is not connected, this function
1138     returns no capabilities.
1139 */
connectionCapabilities() const1140 QDBusConnection::ConnectionCapabilities QDBusConnection::connectionCapabilities() const
1141 {
1142     return d ? d->connectionCapabilities() : ConnectionCapabilities();
1143 }
1144 
1145 /*!
1146     Attempts to register the \a serviceName on the D-Bus server and
1147     returns \c true if the registration succeeded. The registration will
1148     fail if the name is already registered by another application.
1149 
1150     \sa unregisterService(), QDBusConnectionInterface::registerService()
1151 */
registerService(const QString & serviceName)1152 bool QDBusConnection::registerService(const QString &serviceName)
1153 {
1154     if (interface() && interface()->registerService(serviceName)) {
1155         if (d) d->registerService(serviceName);
1156         return true;
1157     }
1158     return false;
1159 }
1160 
1161 /*!
1162     Unregisters the service \a serviceName that was previously
1163     registered with registerService() and returns \c true if it
1164     succeeded.
1165 
1166     \sa registerService(), QDBusConnectionInterface::unregisterService()
1167 */
unregisterService(const QString & serviceName)1168 bool QDBusConnection::unregisterService(const QString &serviceName)
1169 {
1170     if (interface()->unregisterService(serviceName)) {
1171         if (d) d->unregisterService(serviceName);
1172         return true;
1173     }
1174     return false;
1175 }
1176 
1177 /*!
1178     \fn QDBusConnection QDBusConnection::sessionBus()
1179 
1180     Returns a QDBusConnection object opened with the session bus. The object
1181     reference returned by this function is valid until the application terminates,
1182     at which point the connection will be closed and the object deleted.
1183 */
sessionBus()1184 QDBusConnection QDBusConnection::sessionBus()
1185 {
1186     if (_q_manager.isDestroyed())
1187         return QDBusConnection(nullptr);
1188     return QDBusConnection(_q_manager()->busConnection(SessionBus));
1189 }
1190 
1191 /*!
1192     \fn QDBusConnection QDBusConnection::systemBus()
1193 
1194     Returns a QDBusConnection object opened with the system bus. The object reference returned
1195     by this function is valid until the QCoreApplication's destructor is run, when the
1196     connection will be closed and the object, deleted.
1197 */
systemBus()1198 QDBusConnection QDBusConnection::systemBus()
1199 {
1200     if (_q_manager.isDestroyed())
1201         return QDBusConnection(nullptr);
1202     return QDBusConnection(_q_manager()->busConnection(SystemBus));
1203 }
1204 
1205 #if QT_DEPRECATED_SINCE(5,5)
1206 /*!
1207   \deprecated
1208 
1209   Always returns a disconnected, invalid QDBusConnection object. For the old
1210   functionality of determining the sender connection, please use QDBusContext.
1211 
1212   \sa QDBusContext
1213 */
sender()1214 QDBusConnection QDBusConnection::sender()
1215 {
1216     return QDBusConnection(QString());
1217 }
1218 #endif
1219 
1220 /*!
1221   \internal
1222 */
createBusService()1223 void QDBusConnectionPrivate::createBusService()
1224 {
1225     Q_ASSERT(mode == ClientMode);
1226     QDBusConnection connection(this);
1227     busService = new QDBusConnectionInterface(connection, this);
1228     ref.deref(); // busService has increased the refcounting to us
1229                  // avoid cyclic refcounting
1230 
1231     QObject::connect(this, &QDBusConnectionPrivate::callWithCallbackFailed,
1232                      busService, emit &QDBusConnectionInterface::callWithCallbackFailed,
1233                      Qt::QueuedConnection);
1234 }
1235 
1236 /*!
1237     \since 4.8
1238     Returns the local machine ID as known to the D-Bus system. Each
1239     node or host that runs D-Bus has a unique identifier that can be
1240     used to distinguish it from other hosts if they are sharing
1241     resources like the filesystem.
1242 
1243     Note that the local machine ID is not guaranteed to be persistent
1244     across boots of the system, so this identifier should not be
1245     stored in persistent storage (like the filesystem). It is
1246     guaranteed to remain constant only during the lifetime of this
1247     boot session.
1248 */
localMachineId()1249 QByteArray QDBusConnection::localMachineId()
1250 {
1251     char *dbus_machine_id = q_dbus_get_local_machine_id();
1252     QByteArray result = dbus_machine_id;
1253     q_dbus_free(dbus_machine_id);
1254     return result;
1255 }
1256 
1257 /*!
1258     \namespace QDBus
1259     \inmodule QtDBus
1260 
1261     \brief The QDBus namespace contains miscellaneous identifiers used
1262     throughout the Qt D-Bus module.
1263 */
1264 
1265 /*!
1266     \enum QDBus::CallMode
1267 
1268     This enum describes the various ways of placing a function call. The valid modes are:
1269 
1270     \value NoBlock              Place the call but don't wait for the reply (the reply's contents
1271                                 will be discarded).
1272     \value Block                Don't use an event loop to wait for a reply, but instead block on
1273                                 network operations while waiting. This means the
1274                                 user-interface may not be updated until the function returns.
1275     \value BlockWithGui         Use the Qt event loop to wait for a reply. This means that the
1276                                 user-interface will stay responsive (processing input events),
1277                                 but it also means other events may happen, like signal delivery
1278                                 and other D-Bus method calls.
1279     \value AutoDetect           Automatically detect if the called function has a reply.
1280 
1281     When using BlockWithGui, applications must be prepared for reentrancy in any function.
1282 */
1283 
1284 /*!
1285     \fn void QDBusConnection::swap(QDBusConnection &other)
1286 
1287     Swaps this QDBusConnection instance with \a other.
1288 */
1289 
1290 QT_END_NAMESPACE
1291 
1292 #ifdef Q_OS_WIN
1293 #  include <qt_windows.h>
1294 
1295 QT_BEGIN_NAMESPACE
preventDllUnload()1296 static void preventDllUnload()
1297 {
1298     // Thread termination is really wacky on Windows. For some reason we don't
1299     // understand, exiting from the thread may try to unload the DLL. Since the
1300     // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
1301     // a deadlock: the main thread is waiting for the manager thread to exit,
1302     // but the manager thread is attempting to acquire a lock to unload the DLL.
1303     //
1304     // We work around the issue by preventing the unload from happening in the
1305     // first place.
1306     //
1307     // For this trick, see
1308     // https://blogs.msdn.microsoft.com/oldnewthing/20131105-00/?p=2733
1309 
1310     static HMODULE self;
1311     GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
1312                       GET_MODULE_HANDLE_EX_FLAG_PIN,
1313                       reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
1314                       &self);
1315 }
1316 QT_END_NAMESPACE
1317 #endif
1318 
1319 #endif // QT_NO_DBUS
1320