https://techbase.kde.org/api.php?action=feedcontributions&user=Bluesnik&feedformat=atomKDE TechBase - User contributions [en]2024-03-29T00:28:52ZUser contributionsMediaWiki 1.40.2https://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=56701Development/Tutorials/D-Bus/Accessing Interfaces (de)2011-01-17T23:46:07Z<p>Bluesnik: /* D-Bus XML generierte Klassen benutzen */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es, das interne API von Anwendungen, für die Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B., dass der Name der Schnittstelle bekannt sein muss, das {{qt|QDBusReply}} Objekt muss, so wie oben durch ein Template mit <tt>int</tt>, korrekt gesetzt sein und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es mit {{qt|QDBusMessage}} ein Fortschritt ist, es ist noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== D-Bus XML generierte Klassen benutzen ==<br />
<br />
Am besten wäre es, wenn man lokale Objekte, die einen gegebenen Dienst repräsentieren, einfach erzeugen und gleich benutzen könnte. Ungefähr so wie:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Glücklicherweise ist dies genau das, was QT uns erlaubt. Die einzige Vorraussetzung ist eine XML Datei, die den D-Bus Dienst beschreibt. Solche Dateien werden im D-Bus prefix im {{path|interfaces}} Verzeichnis installiert.<br />
<br />
{{tip|Das D-Bus prefix findet man heraus, indem man den folgenden Befehl auf der Kommandozeile eingibt:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
Man kann seine XML Dateien auch aus C++ Header Dateien erzeugen. Dies wird im nächsten Tutorial [[../Creating_Interfaces|Creating D-Bus Interfaces]] erläutert.<br />
<br />
Mit dem Pfad zur XML Datei zur Hand, kann man dann so etwas wie den folgenden Code zu seiner {{path|CMakeLists.txt}} hinzufügen:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
Dies erzeugt zwei Dateien während des Build-Prozess, {{path|network_interface.h}} und {{path|network_interface.cpp}}, und fügt sie der kompilierten Anwendung hinzu. Man kann einfach <tt>#include "network_interface.h"</tt> angeben und die erzeugte Klasse, wie im oben gezeigten Beispiel, benutzen.<br />
<br />
Wenn man die erzeugte Header Datei betrachtet, sieht man genau, welche Methoden, Signale, so wie ihre Signaturen und Rückgabewerte dem Anbieter des Dienstes entsprechen.Benutzt man die Klasse direkt, wird der Compiler eine Typ-Prüfung auf Methodenaufrufe durchführen, was weniger Laufzeit Brüche übriglässt, die es aufzuspüren gilt.<br />
<br />
Da die erzeugte Klasse eine Unterklasse von {{qt|QDBusAbstractInterface}} ist,<br />
so wie auch {{qt|QDBusInterface}}, ist alles was {{qt|QDBusInterface}} bietet, ebenfalls verfügbar.<br />
<br />
Durch diese Kombination aus einfacher Benutzung und Kompilierzeit-Typprüfung, ist dies der allgemein zu bevorzugende Mechanismus, um auf den D-Bus zuzugreifen.<br />
<br />
{{tip|Wenn die verwendete CMake Installation PKGCONFIG_GETVAR nicht anbietet, kann man [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] zu seinemm Projekt hinzufügen.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=56699Development/Tutorials/D-Bus/Accessing Interfaces (de)2011-01-17T23:27:23Z<p>Bluesnik: /* D-Bus XML generierte Klassen benutzen */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es, das interne API von Anwendungen, für die Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B., dass der Name der Schnittstelle bekannt sein muss, das {{qt|QDBusReply}} Objekt muss, so wie oben durch ein Template mit <tt>int</tt>, korrekt gesetzt sein und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es mit {{qt|QDBusMessage}} ein Fortschritt ist, es ist noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== D-Bus XML generierte Klassen benutzen ==<br />
<br />
Am besten wäre es, wenn man lokale Objekte, die einen gegebenen Dienst repräsentieren, einfach erzeugen und gleich benutzen könnte. Ungefähr so wie:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Glücklicherweise ist dies genau das, was QT uns erlaubt. Die einzige Vorraussetzung ist eine XML Datei, die den D-Bus Dienst beschreibt. Solche Dateien werden im D-Bus prefix im {{path|interfaces}} Verzeichnis installiert.<br />
<br />
{{tip|Das D-Bus prefix findet man heraus, indem man den folgenden Befehl auf der Kommandozeile eingibt:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
Man kann seine XML Dateien auch aus C++ Header Dateien erzeugen. Dies wird im nächsten Tutorial [[../Creating_Interfaces|Creating D-Bus Interfaces]] erläutert.<br />
<br />
Mit dem Pfad zur XML Datei zur Hand, kann man dann so etwas wie den folgenden Code zu seiner {{path|CMakeLists.txt}} hinzufügen:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time<br />
Dies erzeugt zwei Dateien während des Build-Prozess, {{path|network_interface.h}} und {{path|network_interface.cpp}}, und fügt sie der kompilierten Anwendung hinzu. Man kann einfach <tt>#include "network_interface.h"</tt> angeben und die erzeugte Klasse, wie im oben gezeigten Beispiel, benutzen.<br />
<br />
Wenn man die erzeugte Header Datei betrachtet, sieht man genau, welche Methoden, Signale, so wie ihre Signaturen und Rückgabewerte dem Anbieter des Dienstes entsprechen.Benutzt man die Klasse direkt, wird der Compiler eine Typ-Prüfung -(Using the class directly will let the compiler do type checking)- on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=56698Development/Tutorials/D-Bus/Accessing Interfaces (de)2011-01-17T22:36:22Z<p>Bluesnik: /* Using Classes Generated From D-Bus XML */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es, das interne API von Anwendungen, für die Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B., dass der Name der Schnittstelle bekannt sein muss, das {{qt|QDBusReply}} Objekt muss, so wie oben durch ein Template mit <tt>int</tt>, korrekt gesetzt sein und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es mit {{qt|QDBusMessage}} ein Fortschritt ist, es ist noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== D-Bus XML generierte Klassen benutzen ==<br />
<br />
Am besten wäre es, wenn man lokale Objekte, die einen gegebenen Dienst repräsentieren, einfach erzeugen und gleich benutzen könnte. Ungefähr so wie:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Glücklicherweise ist dies genau das, was QT uns erlaubt. Die einzige Vorraussetzung ist eine XML Datei, die den D-Bus Dienst beschreibt. Solche Dateien werden im D-Bus prefix im {{path|interfaces}} Verzeichnis installiert.<br />
<br />
{{tip|Das D-Bus prefix findet man heraus, indem man den folgenden Befehl auf der Kommandozeile eingibt:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=56697Development/Tutorials/D-Bus/Accessing Interfaces (de)2011-01-17T22:09:32Z<p>Bluesnik: /* Ist dies der beste Weg? */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es, das interne API von Anwendungen, für die Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B., dass der Name der Schnittstelle bekannt sein muss, das {{qt|QDBusReply}} Objekt muss, so wie oben durch ein Template mit <tt>int</tt>, korrekt gesetzt sein und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es mit {{qt|QDBusMessage}} ein Fortschritt ist, es ist noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=56696Development/Tutorials/D-Bus/Accessing Interfaces (de)2011-01-17T21:54:17Z<p>Bluesnik: /* Zusammenfassung */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es, das interne API von Anwendungen, für die Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B. der Name der Schnittstelle muss bekkannt sein, das {{qt|QDBusReply}} Objekt muss, so wie oben durch ein Template mit <tt>int</tt>, korrekt gesetzt sein und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es mit {{qt|QDBusMessage}} ein Fortschritt ist, es ist noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53424Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-12T23:41:48Z<p>Bluesnik: /* Ist dies der beste Weg? */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B. der Name der Schnittstelle muss bekkannt sein, das {{qt|QDBusReply}} Objekt muss, so wie oben durch ein Template mit <tt>int</tt>, korrekt gesetzt sein und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es mit {{qt|QDBusMessage}} ein Fortschritt ist, es ist noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53423Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-12T23:39:09Z<p>Bluesnik: /* Ist Dies der beste Weg? */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die gebotene Bequemlichkeit ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B. der Name der Schnittstelle muss bekkannt sein, das {{qt|QDBusReply}} Objekt muss korrekt gesetzt sein, so wie oben durch ein Template mit <tt>int</tt> und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es ein Fortschritt über {{qt|QDBusMessage}} ist, ist es noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53422Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-12T23:36:57Z<p>Bluesnik: still in translation progress</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchrone Methodenaufrufe und Signale ===<br />
<br />
Bis zu diesem Punkt im Beispiel sind alle Aufrufe synchron und die Anwendung blockiert, bis eine Antwort empfangen wurde. Die letzten beiden Verwendungen von {{qt|QDBusInterface}} im Beispiel, zeigen die asynchrone Nutzung des D-Bus und in beiden Fällen ist es der Qt-Signal-und Slot-Mechanismus auf den man sich verlässt.<br />
<br />
In Zeile 29 wird ein <tt>callWithCallback</tt> benutzt und dabei ein regulärer QObject Slot angegeben, der aufgerufen wird, wenn die D-Bus Antwort zurückkommt. Auf diese Weise blockiert die Anwendung nicht, da <tt>callWithCallback</tt>, sofort nach Einstellen der Nachricht in die bus Warteschlange zum senden, wieder zurrückkehrt. Der <tt>interfaceList</tt> Slot wird dann später aufgerufen. Zu beachten ist, dass diese Methode ein <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> erfordert; da führt erstmal kein Weg drumherum.<br />
<br />
Abschließend wird in Zeile 33 und 34 der Slot mit einem D-Bus Signal verbunden. Die Verwendung von {{qt|QDBusInterface}} sieht genauso aus, wie das Verbinden zu einem regulärem lokalen Signal, in QT Programmen. Es wird einfach die Standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> Methode angewandt. Dies wird von {{qt|QDBusInterface}} bewerkstelligt, indem es Qt's meta object system benutzt um dynamisch die Signale, die die D-Bus Schnittstellen anbieten, hinzuzufügen. Ziemlich ausgefuchst!<br />
<br />
=== Ist ''Dies'' der beste Weg? ===<br />
<br />
Diese einfache Bedienung über {{qt|QDBusMessage}} hat allerdings ihren Preis. Da {{qt|QDBusInterface}} ein {{qt|QObject}} ist, schleppt es den entsprechenden Overhead mit. Es generiert bei seiner Erzeugung, auch eine Abfrage an das angeforderten D-Bus Objekt, um die Schnittstelle mit Dingen, wie den verfügbaren Signalen, zu initialisieren. Oft wird dieser zusätzliche Overhead, im größeren Zusammenhang, zu vernachlässigen sein und durch die Bequemlichkeit die sie bietet ausgeglichen.<br />
<br />
Es gibt allerdings noch ein paar Ärgernisse zu bewältigen. Wie z.B. der Name der Schnittstelle muss bekkannt sein, das {{qt|QDBusReply}} Objekt muss korrekt gesetzt sein, so wie oben durch ein Template mit <tt>int</tt> und nach wie vor bleibt das Debuggen von Schreibfehlern in Methodennamen und die Entscheidung etwas zur Laufzeit, oder zur Kompilierzeit zu tun. Auch wenn es ein Fortschritt über {{qt|QDBusMessage}} ist, ist es noch nicht perfekt.<br />
<br />
Und genau hier kommt mit <tt>qdbusxml2cpp</tt>, die Rettung.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53421Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-12T18:35:35Z<p>Bluesnik: Translation in Progress</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Zugriff auf D-Bus Schnittstellen|<br />
<br />
pre=[[../Introduction_(de)|Einführung]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<code cppqt n><br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchrone Aufrufe ===<br />
<br />
Zuallererst wird in Zeile 3 ein {{qt|QDBusInterface}} erzeugt, welches desselbe Objekt wie in den obigen QDBusMessage Beispielen anspricht.<br />
<br />
Dann werden mit einigen unterschiedlichen Techniken, verschiedene D-Bus Methoden aufgerufen. In Zeile 9 erfolgt ein einfacher Aufruf einer Methode namens <tt>ping</tt>, ohne weitere Argumente.<br />
In Zeile 10 wird die selbe Methode mit '''einem''' Parameter angesprochen.<br />
Zu beachten ist der Umstand, dass keine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> für die Argumentübergabe erzeugt werden muss.<br />
Man kann auf diese Weise bis zu 8 Argumente an eine D-Bus Methode übergeben.<br />
<br />
Wenn mehr als 8 Argumente benötigt werden, um einen Zustand auszudrücken, oder aus anderen Gründen eine <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> der bessere Ansatz ist, etwas zu bewerkstelligen, dann sollte man stattdessen eine <tt>callWithArgumentList</tt> Methode, wie in Zeile 12-14 zu sehen, einsetzen.<br />
<br />
=== Der Umgang mit Antworten ===<br />
<br />
In Zeile 16 wird die <tt>ping</tt> Methode erneut aufgerufen, aber diesmal der Rückgabewert in einer Objektvariablen vom Typ {{qt|QDBusReply}} festgehalten. Es folgt die Prüfung auf gültige Werte (dass z.B. keine Fehler (error) zurückgeliefert wurden und der Rückgabetyp ein <tt>int</tt> ist), und die anschließende Verwertung der Rückgabedaten in einem "Pop-Up"-Fenster (Zeile 23).<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53384Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-11T00:34:46Z<p>Bluesnik: /* Ist dies der beste Weg? */</p>
<hr />
<div>== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<!-- <code cppqt n> --><br />
<pre> <br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</pre><br />
<!-- </code> --><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist das der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchronous Calls ===<br />
<br />
The first thing we did was create a {{qt|QDBusInterface}} on line 3 that represents the same object we were accessing in the QDBusMessage examples above. <br />
<br />
We then called several D-Bus methods on that object using a few different techniques. On line 9 we make a simple call to a method called <tt>ping</tt> without any arguments. On line 10, we call the same method but with a parameter. Note that we didn't have to create a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> for the arguments. We can pass up to 8 arguments to a D-Bus method this way.<br />
<br />
If you need to pass more than 8 arguments or for some other reason a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> is simply a better approach for the circumstances, then you may use the <tt>callWithArgumentList</tt> method instead as seen on lines 12-14 above.<br />
<br />
=== Handling Replies ===<br />
<br />
On line 16 we call the <tt>ping</tt> method yet again, but this time save the reply in a {{qt|QDBusReply}} object. We check to make sure the reply was valid (e.g. no errors were returned and we did indeed get an <tt>int</tt> back) and then use the returned data to populate a message in an informational popup.<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53383Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-11T00:34:06Z<p>Bluesnik: /* Antworten erhalten */</p>
<hr />
<div>== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<!-- <code cppqt n> --><br />
<pre> <br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</pre><br />
<!-- </code> --><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> oder <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist dies der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchronous Calls ===<br />
<br />
The first thing we did was create a {{qt|QDBusInterface}} on line 3 that represents the same object we were accessing in the QDBusMessage examples above. <br />
<br />
We then called several D-Bus methods on that object using a few different techniques. On line 9 we make a simple call to a method called <tt>ping</tt> without any arguments. On line 10, we call the same method but with a parameter. Note that we didn't have to create a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> for the arguments. We can pass up to 8 arguments to a D-Bus method this way.<br />
<br />
If you need to pass more than 8 arguments or for some other reason a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> is simply a better approach for the circumstances, then you may use the <tt>callWithArgumentList</tt> method instead as seen on lines 12-14 above.<br />
<br />
=== Handling Replies ===<br />
<br />
On line 16 we call the <tt>ping</tt> method yet again, but this time save the reply in a {{qt|QDBusReply}} object. We check to make sure the reply was valid (e.g. no errors were returned and we did indeed get an <tt>int</tt> back) and then use the returned data to populate a message in an informational popup.<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53382Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-11T00:29:49Z<p>Bluesnik: /* QDBusMessage benutzen */</p>
<hr />
<div>== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
* Methodenaufruf (method call)<br />
* Signal (signal)<br />
* Antwort (reply)<br />
* Fehler (error)<br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<!-- <code cppqt n> --><br />
<pre> <br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</pre><br />
<!-- </code> --><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> or <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist dies der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchronous Calls ===<br />
<br />
The first thing we did was create a {{qt|QDBusInterface}} on line 3 that represents the same object we were accessing in the QDBusMessage examples above. <br />
<br />
We then called several D-Bus methods on that object using a few different techniques. On line 9 we make a simple call to a method called <tt>ping</tt> without any arguments. On line 10, we call the same method but with a parameter. Note that we didn't have to create a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> for the arguments. We can pass up to 8 arguments to a D-Bus method this way.<br />
<br />
If you need to pass more than 8 arguments or for some other reason a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> is simply a better approach for the circumstances, then you may use the <tt>callWithArgumentList</tt> method instead as seen on lines 12-14 above.<br />
<br />
=== Handling Replies ===<br />
<br />
On line 16 we call the <tt>ping</tt> method yet again, but this time save the reply in a {{qt|QDBusReply}} object. We check to make sure the reply was valid (e.g. no errors were returned and we did indeed get an <tt>int</tt> back) and then use the returned data to populate a message in an informational popup.<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces_(de)&diff=53381Development/Tutorials/D-Bus/Accessing Interfaces (de)2010-08-11T00:25:41Z<p>Bluesnik: Translation in Progress, Problems with code-tag</p>
<hr />
<div>== Zusammenfassung ==<br />
D-Bus ermöglicht es Anwendungen, ihr internes API, der Außenwelt zugänglich zu machen. Auf diese APIs kann zur Laufzeit über den D-Bus, unter Zuhilfenahme von Kommandozeilenprogrammen oder D-Bus Bibliotheken und Bindungen, zugegriffen werden. Dieses Tutorial befasst sich mit der letzteren Methode, mit praxisnahen Beispielen, die Sie in Ihren Anwendungen verwenden können.<br />
<br />
== QDBusMessage benutzen ==<br />
[http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] repräsentiert eine D-Bus Nachricht, die über einen bestimmten Bus gesendet oder empfangen wird. Jede Nachricht kann, abhängig von ihrem Einsatzzweck, von einem der folgenden Typen sein:<br />
<ul><br />
<li>Methode aufrufen</li><br />
<li>Signal</li><br />
<li>Antwort</li><br />
<li>Fehler </li><br />
</ul><br />
Ein Aufzählungstyp (enum), der diese 4 Typen beinhaltet, wird in [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] definiert. Auf einen Nachrichtentyp kann über die <tt courier> [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]::type() </tt> Methode zugegriffen werden.<br />
<br />
=== Der Aufruf einer D-Bus Methode ===<br />
Eine [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] kann direkt mit der statischen Methode [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage]<tt>::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> benutzt werden, um Methoden in D-Bus Diensten aufzurufen. Der Rückgabewert ist ein [http://doc.qt.nokia.com/latest/QDBusMessage.html QDBusMessage] Objekt, welches dann für den eigentlichen Aufruf benutzt wird.<br />
<br />
Der <tt>interface</tt> Parameter ist optional und nur erforderlich, wenn die Methode nicht eindeutig identifizierbar im, mit dem Pfad assoziierten, Objekt ist.Dies kann passieren, wenn das Objekt mehrere Schnittstellen implementiert, die Methoden, mit den gleichen Namen haben. In solchen (seltenen) Fällen, gibt es keine Garantie darüber, welche Methode tatsächlich aufgerufen wird, wenn man die gewünschte Schnittstelle nicht explizit definiert. Allerdings kann man in der Regel einfach eine leere Zeichenfolge (z.B. ""), als Argument für <tt>interface</tt> übergeben.<br />
<br />
Als Beispiel für den Zugriff auf einen Dienst der (fiktiven) <tt>ping</tt>-Methode für das {{path|/network}} object in der <tt>org.foo.bar</tt>, könnte man dies zu tun:<br />
<br />
<!-- <code cppqt n> --><br />
<pre> <br />
QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar", <br />
"/network", <br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</pre><br />
<!-- </code> --><br />
<br />
In Zeile 5 im obigen Beispiel haben wir die Nachrichten-Warteschlange für das Senden über den aktuelle Session-Bus. Der Rückgabewert vom Typ <tt>bool</tt> lässt uns wissen, ob das Einstellen in die Warteschlange erfolgreich war, oder nicht.<br />
<br />
Dies lässt noch zwei Fragen offen:<br />
* Wie werden die Parameter für einen Methodenaufruf korrekt gesetzt?<br />
* Wie kommt man an die Rückmeldung im Falle der D-Bus-Methoden, die einen Rückgabewert haben?<br />
<br />
=== Parameter setzen ===<br />
<br />
Argumente zusammen mit dem Aufruf der Methode zu senden, ist ganz einfach. Zunächst muss eine {{qt|QList}} of {{qt|QVariant}} objects erzeugt, und diese dann der D-Bus-Nachricht hinzugefügt werden. Wenn man also der <tt>ping</tt> Methode in der obigen Deklaration einen Hostnamen als Parameter übergibt, könnte man den Code folgenderweise abändern (beachte Zeile 5 bis 7):<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternativ bietet {{qt|QDBusMessage}} mit der "operator<<" Funktion eine bequeme Methode zum Anhängen von Parametern an eine Nachricht. Das obige Beispiel wird zu:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|Die Argumente müssen in der {{qt|QList}} in der gleichen Reihenfolge, wie von der aufgerufenen D-Bus Methode erwartet, erscheinen.}}<br />
<br />
=== Antworten erhalten ===<br />
<br />
Wenn man Informationen wieder von der D-Bus Methode zurückbekommen möchte, wendet man statt dessen die Methode <tt>{{qt|QDBusConnection}}::call</tt> an.<br />
Diese blockiert, bis eine Antwort oder ein Timeout eintritt. Wenn unsere <tt>ping</tt> Methode Informationen über den im Parameter übergebenen Host zurückgibt, könnten wir den Code folgendermaßen abändern, um an diese Informationen zu gelangen:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
Die <tt>response</tt> (Antwort) ist von einem der Typen: <tt>QDBusMessage::ReplyMessage</tt> or <tt>QDBusMessage::ErrorMessage</tt>, je nachdem ob es erfolgreich war oder nicht. Man kann die zurückgegebenen Werte durchsehen, indem man die Argumente mit der <tt>{{qt|QDBusMessage}}::arguments()</tt> Methode holt, die einen <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>. zurückgibt.<br />
<br />
=== Ist dies der beste Weg? ===<br />
<br />
QDBusMessage direkt auf diese Weise zu benutzen, um D-Bus Methoden aufzurufen, ist nicht der einfachste, beste, oder empfohlene Weg. Werfen wir einen Blick auf die weitaus bequemer zu handhabende Klasse {{qt|QDBusInterface}} um dann den Remote-Zugriff auf D-Bus Schnittstellen zu betrachten, als wären sie lokale Methoden, die automatisch aus XML heraus generierte Proxy-Klassen benutzen.<br />
<br />
== QDBusInterface anwenden ==<br />
<br />
{{qt|QDBusInterface}} bietet eine einfache und direkte Methode, um D-Bus Aufrufe und Verbindungen zu D-Bus Signalen herzustellen.<br />
<br />
Ein {{qt|QDBusInterface}} Objekt stellt eine gegebene D-Bus Schnittstelle dar. Der Konstruktor erwartet als Parameter (in dieser Reihenfolge) einen Dienst-Namen, einen Objekt-Pfad, eine optionale Schnittstelle und ebenfalls optional, welchen Bus (z.B. system oder session) es benutzen soll. Wenn kein Bus explizit angegeben ist, wird standardmäßig der Session-Bus benutzt. Wenn keine Schnittstelle angegeben ist, wird das zurückgegebene Objekt alle Schnittstellen auf dem Bus ansprechen.<br />
<br />
Es wird empfohlen, explizit eine Schnittstelle zu benennen, wenn man den Konstruktor von {{qt|QDBusInterface}} aufruft. Aufgrund der Interna des QtDBus, wird bei Leerlassen des Schnittstellen-Parameters eine Methode der Remote-Anwendung aufgerufen, die prüft, welche Methoden überhaupt verfügbar sind. Dies ist vermeidbarer Overhead. Andererseits kann QTDBus bei Übergabe eines Schnittstellennamens, das Ergebnis für weiteren Gebrauch zwischenspeichern.<br />
<br />
<br />
Da {{qt|QDBusInterface}} ein QObject ist, kann man ihm ein Elternobjekt übergeben. Dies erleichtert die Verwaltungsarbeit, die mit dem Erzeugen neuer {{qt|QDBusInterface}} Objekte einhergeht, indem man QT das Aufräumen überlässt, wenn das Elternobjekt zerstört wird.<br />
<br />
Hier ist ein Beispiel der Benutzung von {{qt|QDBusInterface}}, das wir Zeile für Zeile durchgehen werden:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchronous Calls ===<br />
<br />
The first thing we did was create a {{qt|QDBusInterface}} on line 3 that represents the same object we were accessing in the QDBusMessage examples above. <br />
<br />
We then called several D-Bus methods on that object using a few different techniques. On line 9 we make a simple call to a method called <tt>ping</tt> without any arguments. On line 10, we call the same method but with a parameter. Note that we didn't have to create a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> for the arguments. We can pass up to 8 arguments to a D-Bus method this way.<br />
<br />
If you need to pass more than 8 arguments or for some other reason a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> is simply a better approach for the circumstances, then you may use the <tt>callWithArgumentList</tt> method instead as seen on lines 12-14 above.<br />
<br />
=== Handling Replies ===<br />
<br />
On line 16 we call the <tt>ping</tt> method yet again, but this time save the reply in a {{qt|QDBusReply}} object. We check to make sure the reply was valid (e.g. no errors were returned and we did indeed get an <tt>int</tt> back) and then use the returned data to populate a message in an informational popup.<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=KDE_TechBase:Contributors&diff=53380KDE TechBase:Contributors2010-08-10T21:07:59Z<p>Bluesnik: /* German Team */</p>
<hr />
<div>Welcome to the contributors page.<br />
<br />
'''This site contains a list of ''active'' contributors. It should help to build teams which maintain KDE TechBase's content. If you have questions about KDE TechBase you can ask/email the corresponding person.'''<br />
<br />
Please add yourself to the list where appropriate. If you are inactive, please remove yourself again.<br />
<br />
== Administrators ==<br />
<br />
This is a list of KDE TechBase administrators.<br />
<br />
* [[User:Danimo|Danimo]], <danimo at kde dot org><br />
* [[User:Dhaumann|Dhaumann]], <dhaumann at kde dot org><br />
* [[User:Tstaerk|Tstaerk]], <thorsten at staerk dot de><br />
<br />
== Reviewers and Article Writers ==<br />
<br />
If you are continuously reviewing KDE TechBase changes or writing articles add yourself to the list.<br />
<br />
* [[User:Dhaumann|Dhaumann]], <dhaumann at kde dot org><br />
* [[User:Milliams|Milliams]]<br />
* [[User:JRT|James Tyrer]], <tyrerj at acm dot org> [[Getting_Started/Build/KDE4.x|author of KDE 4.x ]]<br />
* name, <email><br />
<br />
== Translation Teams ==<br />
<br />
KDE TechBase is [[Help:Wiki Translation|translated]] into many languages. If you translate pages please add yourself to the right translation team.<br />
<br />
=== Chinese(simplified) Team ===<br />
* [[User:Liangqi|Liangqi]], cavendish.qi at gmail dot com<br />
* [[User:HualiangM|HualiangM]], hualiang.miao at googlemail dot com<br />
* [[User:Yinfan.ustc|Yifan]], enthumelon at gmail dot com<br />
* name, <email><br />
<br />
=== Spanish Team ===<br />
* [[User:Martin J. Ponce|Martin J. Ponce]], mjp dot ttc at gmail dot com<br />
* [[User:edumardo| Eduardo Delgado Díaz (edumardo)]], aesalemolo at gmail dot com<br />
* name, <email><br />
<br />
=== German Team ===<br />
* [[User:DrSlowDecay|DrSlowDecay]], kde at metalhorde dot de<br />
* [[User:Rememberme|rememberme]] redict dot info at gmx dot net<br />
* [[User:sschloenvoigt|Steffen Schloenvoigt]], steffen at schloenvoigt dot de <br />
* [[User:Bluesnik|bluesnik]] nano at bluesnik dot de<br />
* name, <email><br />
<br />
=== Italian Team ===<br />
* [[User:Thunder Teaser|Thunder Teaser]], totokid at gmail dot com<br />
* [[User:Panda84|Panda84]], panda84 at inwind dot it<br />
* [[User:Fresbeeplayer|Fresbeeplayer]], fresbeeplayer at gmail dot com<br />
* name, <email><br />
<br />
=== Tamil Team ===<br />
* [[User:Shriramadhas|Shriramadhas]], shriramadhas at gmail dot com<br />
* name, <email><br />
<br />
=== ... Kerala Amrita ===<br />
* Name Arun v Pillai, <email>arun.avp134@gmail.com<br />
* Name Arun Jyothi S, <ninakkayiajs@gmil.com></div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces&diff=53378Development/Tutorials/D-Bus/Accessing Interfaces2010-08-10T20:29:25Z<p>Bluesnik: /* Calling a D-Bus Method */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Accessing D-Bus Interfaces|<br />
<br />
pre=[[../Introduction|Introduction]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Abstract ==<br />
<br />
D-Bus allows applications to expose their internal API to the outside world. These APIs can then be accessed at run-time via the D-Bus protocol using command line applications or D-Bus libraries and bindings themselves. This tutorial looks at the latter method with examples that you can use in your applications.<br />
<br />
== Using QDBusMessage ==<br />
<br />
{{qt|QDBusMessage}} represents a D-Bus messages that can be sent or has been received over a given bus. Each message is one of four types, depending on the purpose of the message:<br />
* method call<br />
* signal<br />
* reply<br />
* error<br />
An enumeration covering each of these possibilities is defined in {{qt|QDBusMessage}}. A message's type can be access via the <tt>{{qt|QDBusMessage}}::type()</tt> method.<br />
<br />
=== Calling a D-Bus Method ===<br />
<br />
A {{qt|QDBusMessage}} can be used directly to call methods in D-Bus services using the <tt>{{qt|QDBusMessage}}::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> static method. It returns a {{qt|QDBusMessage}} object that you can then use to make the call.<br />
<br />
The <tt>interface</tt> parameter is optional and only necessary if the method to be called is not unique in the object associated with the <tt>path</tt>. This can happen if the object implements multiple interfaces which have methods that are named the same. In such (rare) cases, if you do not explicitly define the interface to use there is not guarantee as to which method will actually get called. However, usually you can simply pass an empty string (e.g. <tt>""</tt>) as the argument for <tt>interface</tt>.<br />
<br />
By way of example, to access the (fictional) <tt>ping</tt> method on the {{path|/network}} object in the <tt>org.foo.bar</tt> service, one might do this:<br />
<br />
<!-- <pre> --><br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</code><br />
<!-- </pre> --><br />
<br />
In line 5 of the above example we queue the message for sending on the current session bus. We get a <tt>bool</tt> returned letting us know if the queueing was successful or not.<br />
<br />
This leaves us with two questions, however:<br />
* How can one set parameters for a method call?<br />
* How can one get a return message in the case of D-Bus methods that have a return value?<br />
<br />
=== Setting Parameters ===<br />
<br />
Sending arguments along with the method call is quite straight forward. First we need to create a {{qt|QList}} of {{qt|QVariant}} objects and then add those to our D-Bus message. So if the <tt>ping</tt> method in the above took a hostname as a parameter, we might alter the code in this way (note lines 5 through 7):<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternatively, {{qt|QDBusMessage}} provides a convenience method to appending parameters to the message, by way of its "operator<<" function. The above example becomes:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|The arguments must appear in the {{qt|QList}} in the same order they are expected by the D-Bus method being called.}}<br />
<br />
=== Getting Replies ===<br />
<br />
If we wish to actually receive information back from the D-Bus method, we use the <tt>{{qt|QDBusConnection}}::call</tt> method instead. It will block until there is a reply or the call times out. If our <tt>ping</tt> method returned information on the host we provided in the arguments above, we might alter our code to look like this:<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
The <tt>response</tt> will be either of type <tt>QDBusMessage::ReplyMessage</tt> or <tt>QDBusMessage::ErrorMessage</tt> depending on whether it was successful or not. We can look through the values returned by retrieving the arguments with the <tt>{{qt|QDBusMessage}}::arguments()</tt> method which returns a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>.<br />
<br />
=== Is This The Best Way? ===<br />
<br />
Using QDBusMessage directly in this way to invoke remote D-Bus methods is not the easiest, best or even recommend way of doing things. We will now look at the more convenient {{qt|QDBusInterface}} class and then look at accessing remote D-Bus interfaces as if they were local methods using proxy classes auto-generated from XML.<br />
<br />
== Using QDBusInterface ==<br />
<br />
{{qt|QDBusInterface}} provides a simple and direct method to make D-Bus calls and connect to D-Bus signals.<br />
<br />
A {{qt|QDBusInterface}} object represents a given D-Bus interface. The constructor accepts as parameters (in order) a service name, an object path, an optional interface and optionally which bus (e.g. system or session) to use. If no bus is explicitly defined, it defaults to the session bus. If no interface is given, the returned object will be used to call all interfaces on the bus.<br />
<br />
However, note that explicitly passing an interface name to the {{qt|QDBusInterface}} constructor is recommended. Due to the internals of QtDBus, if you pass an empty interface, you will always cause a round-trip to the remote application to verify which methods are available. On the other hand, if you pass a non-empty interface name, QtDBus may cache the result for further uses.<br />
<br />
As {{qt|QDBusInterface}} is a QObject, you can also pass it a parent object. This helps simplify the bookkeeping associated with creating new {{qt|QDBusInterface}} objects by letting Qt clean up for you when the parent object is deleted.<br />
<br />
Here is an example of {{qt|QDBusInterface}} usage which we will then step through line by line:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchronous Calls ===<br />
<br />
The first thing we did was create a {{qt|QDBusInterface}} on line 3 that represents the same object we were accessing in the QDBusMessage examples above. <br />
<br />
We then called several D-Bus methods on that object using a few different techniques. On line 9 we make a simple call to a method called <tt>ping</tt> without any arguments. On line 10, we call the same method but with a parameter. Note that we didn't have to create a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> for the arguments. We can pass up to 8 arguments to a D-Bus method this way.<br />
<br />
If you need to pass more than 8 arguments or for some other reason a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> is simply a better approach for the circumstances, then you may use the <tt>callWithArgumentList</tt> method instead as seen on lines 12-14 above.<br />
<br />
=== Handling Replies ===<br />
<br />
On line 16 we call the <tt>ping</tt> method yet again, but this time save the reply in a {{qt|QDBusReply}} object. We check to make sure the reply was valid (e.g. no errors were returned and we did indeed get an <tt>int</tt> back) and then use the returned data to populate a message in an informational popup.<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Accessing_Interfaces&diff=53375Development/Tutorials/D-Bus/Accessing Interfaces2010-08-10T20:22:53Z<p>Bluesnik: /* Calling a D-Bus Method */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials/D-Bus/Accessing_Interfaces}}<br />
<br />
{{TutorialBrowser|<br />
<br />
series=D-Bus|<br />
<br />
name=Accessing D-Bus Interfaces|<br />
<br />
pre=[[../Introduction|Introduction]]|<br />
<br />
next=[[../Creating Interfaces|Creating Interfaces]], [[../Intermediate_D-Bus|Intermediate D-Bus]]|<br />
<br />
}}<br />
<br />
== Abstract ==<br />
<br />
D-Bus allows applications to expose their internal API to the outside world. These APIs can then be accessed at run-time via the D-Bus protocol using command line applications or D-Bus libraries and bindings themselves. This tutorial looks at the latter method with examples that you can use in your applications.<br />
<br />
== Using QDBusMessage ==<br />
<br />
{{qt|QDBusMessage}} represents a D-Bus messages that can be sent or has been received over a given bus. Each message is one of four types, depending on the purpose of the message:<br />
* method call<br />
* signal<br />
* reply<br />
* error<br />
An enumeration covering each of these possibilities is defined in {{qt|QDBusMessage}}. A message's type can be access via the <tt>{{qt|QDBusMessage}}::type()</tt> method.<br />
<br />
=== Calling a D-Bus Method ===<br />
<br />
A {{qt|QDBusMessage}} can be used directly to call methods in D-Bus services using the <tt>{{qt|QDBusMessage}}::createMethodCall( const QString & service, const QString & path, const QString & interface, const QString & method )</tt> static method. It returns a {{qt|QDBusMessage}} object that you can then use to make the call.<br />
<br />
The <tt>interface</tt> parameter is optional and only necessary if the method to be called is not unique in the object associated with the <tt>path</tt>. This can happen if the object implements multiple interfaces which have methods that are named the same. In such (rare) cases, if you do not explicitly define the interface to use there is not guarantee as to which method will actually get called. However, usually you can simply pass an empty string (e.g. <tt>""</tt>) as the argument for <tt>interface</tt>.<br />
<br />
By way of example, to access the (fictional) <tt>ping</tt> method on the {{path|/network}} object in the <tt>org.foo.bar</tt> service, one might do this:<br />
<br />
<!-- <code cppqt n> --><br />
<pre>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
bool queued = QDBusConnection::sessionBus().send(m);<br />
</pre><br />
<!-- </code> --><br />
<br />
In line 5 of the above example we queue the message for sending on the current session bus. We get a <tt>bool</tt> returned letting us know if the queueing was successful or not.<br />
<br />
This leaves us with two questions, however:<br />
* How can one set parameters for a method call?<br />
* How can one get a return message in the case of D-Bus methods that have a return value?<br />
<br />
=== Setting Parameters ===<br />
<br />
Sending arguments along with the method call is quite straight forward. First we need to create a {{qt|QList}} of {{qt|QVariant}} objects and then add those to our D-Bus message. So if the <tt>ping</tt> method in the above took a hostname as a parameter, we might alter the code in this way (note lines 5 through 7):<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
m.setArguments(args);<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
Alternatively, {{qt|QDBusMessage}} provides a convenience method to appending parameters to the message, by way of its "operator<<" function. The above example becomes:<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
bool queued = QDBusConnection::sessionBus().send(m);</code><br />
<br />
{{note|The arguments must appear in the {{qt|QList}} in the same order they are expected by the D-Bus method being called.}}<br />
<br />
=== Getting Replies ===<br />
<br />
If we wish to actually receive information back from the D-Bus method, we use the <tt>{{qt|QDBusConnection}}::call</tt> method instead. It will block until there is a reply or the call times out. If our <tt>ping</tt> method returned information on the host we provided in the arguments above, we might alter our code to look like this:<br />
<br />
<br />
<code cppqt n>QDBusMessage m = QDBusMessage::createMethodCall("org.foo.bar",<br />
"/network",<br />
"",<br />
"ping");<br />
m << "kde.org";<br />
QDBusMessage response = QDBusConnection::sessionBus().call(m);</code><br />
<br />
The <tt>response</tt> will be either of type <tt>QDBusMessage::ReplyMessage</tt> or <tt>QDBusMessage::ErrorMessage</tt> depending on whether it was successful or not. We can look through the values returned by retrieving the arguments with the <tt>{{qt|QDBusMessage}}::arguments()</tt> method which returns a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>.<br />
<br />
=== Is This The Best Way? ===<br />
<br />
Using QDBusMessage directly in this way to invoke remote D-Bus methods is not the easiest, best or even recommend way of doing things. We will now look at the more convenient {{qt|QDBusInterface}} class and then look at accessing remote D-Bus interfaces as if they were local methods using proxy classes auto-generated from XML.<br />
<br />
== Using QDBusInterface ==<br />
<br />
{{qt|QDBusInterface}} provides a simple and direct method to make D-Bus calls and connect to D-Bus signals.<br />
<br />
A {{qt|QDBusInterface}} object represents a given D-Bus interface. The constructor accepts as parameters (in order) a service name, an object path, an optional interface and optionally which bus (e.g. system or session) to use. If no bus is explicitly defined, it defaults to the session bus. If no interface is given, the returned object will be used to call all interfaces on the bus.<br />
<br />
However, note that explicitly passing an interface name to the {{qt|QDBusInterface}} constructor is recommended. Due to the internals of QtDBus, if you pass an empty interface, you will always cause a round-trip to the remote application to verify which methods are available. On the other hand, if you pass a non-empty interface name, QtDBus may cache the result for further uses.<br />
<br />
As {{qt|QDBusInterface}} is a QObject, you can also pass it a parent object. This helps simplify the bookkeeping associated with creating new {{qt|QDBusInterface}} objects by letting Qt clean up for you when the parent object is deleted.<br />
<br />
Here is an example of {{qt|QDBusInterface}} usage which we will then step through line by line:<br />
<br />
<code cppqt n><br />
QString hostname("kde.org");<br />
QDBusConnection bus = QDBusConnection::sessionBus();<br />
QDBusInterface *interface = new QDBusInterface("org.foo.bar",<br />
"/network",<br />
"org.foo.bar.network", <br />
bus,<br />
this); <br />
<br />
interface->call("ping");<br />
interface->call("ping", hostname);<br />
<br />
QList<QVariant> args;<br />
args.append("kde.org");<br />
interface->callWithArgumentList("ping", args);<br />
<br />
QDBusReply<int> reply = interface->call("ping",<br />
hostname);<br />
if (reply.isValid())<br />
{<br />
KMessageBox::information(winId(), <br />
i18n("Ping to %1 took %2s")<br />
.arg(hostname)<br />
.arg(reply.value()),<br />
i18n("Pinging %1")<br />
.arg(hostname));<br />
}<br />
<br />
args.clear();<br />
interface->callWithCallback("listInterfaces", args,<br />
this,<br />
SLOT(interfaceList(QDBusMessage));<br />
<br />
connect(interface, SIGNAL(interfaceUp(QString)),<br />
this, SLOT(interfaceUp(QString)));<br />
</code><br />
<br />
=== Synchronous Calls ===<br />
<br />
The first thing we did was create a {{qt|QDBusInterface}} on line 3 that represents the same object we were accessing in the QDBusMessage examples above. <br />
<br />
We then called several D-Bus methods on that object using a few different techniques. On line 9 we make a simple call to a method called <tt>ping</tt> without any arguments. On line 10, we call the same method but with a parameter. Note that we didn't have to create a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> for the arguments. We can pass up to 8 arguments to a D-Bus method this way.<br />
<br />
If you need to pass more than 8 arguments or for some other reason a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt> is simply a better approach for the circumstances, then you may use the <tt>callWithArgumentList</tt> method instead as seen on lines 12-14 above.<br />
<br />
=== Handling Replies ===<br />
<br />
On line 16 we call the <tt>ping</tt> method yet again, but this time save the reply in a {{qt|QDBusReply}} object. We check to make sure the reply was valid (e.g. no errors were returned and we did indeed get an <tt>int</tt> back) and then use the returned data to populate a message in an informational popup.<br />
<br />
=== Asynchronous Method Calls and Signals ===<br />
<br />
Up to this point in the example all of the calls made were synchronous and the application would block until a reply was received. The last two uses of {{qt|QDBusInterface}} in the example show asynchronous usage of D-Bus, and in both cases we rely on Qt's signal and slot mechanism.<br />
<br />
On line 29 we use <tt>callWithCallback</tt> and provide a regular QObject slot to be called when the D-Bus reply returns. This way the application will not block as <tt>callWithCallback</tt> returns immediately after queueing the message to be sent on the bus. Later, the <tt>interfaceList</tt> slot would get called. Note that this method requires a <tt>{{qt|QList}}&lt;{{qt|QVariant}}&gt;</tt>; there is no shortcut for us this time.<br />
<br />
Finally, on line 33 we connect to a D-Bus signal. Using {{qt|QDBusInterface}} to do this looks exactly like connecting to a regular, local signal in our own application. We even use the standard <tt>{{qt|QObject}}::{{qt|connect}}</tt> method! This is accomplished by {{qt|QDBusInterface}} using Qt's meta object system to dynamically add the signals the D-Bus interface advertises. Very slick!<br />
<br />
=== Is ''This'' the Best Way? ===<br />
<br />
This ease of use over {{qt|QDBusMessage}} does come with some prices, however. First, since {{qt|QDBusInterface}} is a {{qt|QObject}} it carries the overhead that implies. It also will perform at least one round-trip to the requested D-Bus object on creation to set up the interface object with things such as the available signals. Often this additional overhead is negligible in the larger scheme of things and well made up for by the convenience it provides.<br />
<br />
There are still some annoyances we have to deal with, however, such as having to know the name of the interface, setting up the correct {{qt|QDBusReply}} object such as we did above by templating it with an <tt>int</tt> and having to debug method name typos and the like at runtime versus letting the compiler do it for us. So while it's an improvement over {{qt|QDBusMessage}}, it's still not perfect.<br />
<br />
And that's precisely where <tt>qdbusxml2cpp</tt> comes to our rescue.<br />
<br />
== Using Classes Generated From D-Bus XML ==<br />
<br />
What would be truly great is if we could simply instantiate a local object that represented a given service and start using it right away. Perhaps something like this:<br />
<br />
<code cppqt n><br />
org::foo::bar::network *interface = <br />
new org::foo::bar::network("org.foo.bar", "/network",<br />
QDBusConnection::sessionBus(),<br />
this);<br />
interface->ping("kde.org");<br />
</code><br />
<br />
Fortunately for us, this is precisely what Qt allows us to do. The only requirement is an XML file describing the D-Bus service. Such files are installed in the D-Bus prefix in the {{path|interfaces}} directory. <br />
<br />
{{tip|The D-Bus prefix can be found by issuing the following command in a terminal:<br><tt><nowiki>pkg-config dbus-1 --variable=prefix</nowiki></tt>}}<br />
<br />
We can also create our own XML files from the C++ header files and use those directly. This is covered in the next tutorial, [[../Creating_Interfaces|Creating D-Bus Interfaces]].<br />
<br />
With the path to the XML in hand, we then add something like this to our {{path|CMakeLists.txt}}:<br />
<br />
<code><br />
PKGCONFIG_GETVAR(dbus-1 prefix DBUS_PREFIX)<br />
set(network_xml ${DBUS_PREFIX}/interfaces/org.foo.bar.xml)<br />
qt4_add_dbus_interface(myapp_SRCS ${network_xml} network_interface )<br />
</code><br />
<br />
This will generate two files at build time, {{path|network_interface.h}} and {{path|network_interface.cpp}}, and add them to the compiled application. We can then simply <tt>#include "network_interface.h"</tt> and use the generated class as seen in the example above.<br />
<br />
Examining the generated header file, we can see exactly what methods, signals as well as their signatures and return values are according to the provider of the service. Using the class directly will let the compiler do type checking on method calls leaving fewer run-time breakages to track down.<br />
<br />
Due to the generated class being a subclass of {{qt|QDBusAbstractInterface}} just as {{qt|QDBusInterface}} is, anything we can do with {{qt|QDBusInterface}} is also available to us.<br />
<br />
Due to this combination of ease of use and compile-time checking, this is generally the preferred mechanism to use when accessing D-Bus interfaces.<br />
<br />
{{tip|If your CMake installation does not provide the PKGCONFIG_GETVAR, you can add [[Development/Tutorials/D-Bus/Accessing Interfaces/PkgConfigGetVar.cmake|this cmake module]] to your project.}}<br />
<br />
== Doing A Little Introspection ==<br />
<br />
It may also be helpful to find out if a given service is available or to check which application is providing it. Another {{qt|QDBusAbstractInterface}} subclass, {{qt|QDBusConnectionInterface}}, provides methods to query for such information as which services are registered and who owns them.<br />
<br />
Once you have a service name, you can then use {{qt|QDBusInterface}} to get the <tt>org.freedesktop.DBus.Introspectable</tt> interface and call <tt>Introspect</tt> on it. This will return an XML block describing the objects, which can in turn be introspected for what they provide. The XML itself can be processed using <tt>QDomDocument</tt>, making it a fairly simple process.<br />
<br />
The {{path|qdbus}} application that ships with Qt4 provides a nice example of code doing exactly this. It can be found in {{path|tools/qdbus/tools/qdbus/qdbus.cpp}} in the Qt4 source distribution.<br />
<br />
[[Category:C++]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials_(de)&diff=53372Development/Tutorials (de)2010-08-10T18:37:08Z<p>Bluesnik: /* D-Bus */</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials}}<br />
<br />
Tutorials sind der schnellste Weg um herauszufinden, was man mit KDE anstellen kann und wie man das macht. Es folgt eine Liste der verfügbaren Tutorials '''für KDE4'''. Tutorials und Anleitungen zu KDE3 und KDE2 finden Sie am Ende dieser Seite.<br />
<br />
== Einführung in die KDE4 Programmierung ==<br />
Sind Sie an der Entwicklung von Programmen für KDE 4 interesiert? Wenn ja sind Sie hier genau richtig. Diese Artikelserie richtet sich an alle, die noch nie mit KDE programmiert haben.<br />
;[[Development/Tutorials/First program (de)|Hallo Welt!]]<br />
:''Einführung in die Grundlagen der KDE Programmierung''<br />
<br />
;[[Development/Tutorials/Using KXmlGuiWindow (de)|Erstellen eines Hauptfensters]]<br />
:''Dieser Artikel erklärt, wie der wichtigste Teil eines grafischen Programmes erstellt wird: das Hauptfenster.''<br />
<br />
;[[Development/Tutorials/Using KActions (de)|Die Verwendung von KActions]]<br />
:''In diesem Artikel erfahren Sie, wie Aktionen und Werkzeugleisten (Toolbars) im Menü hinzugefügt werden können.''<br />
<br />
;[[Development/Tutorials/Saving and loading (de)|Laden und Speichern von Dateien]]<br />
:''Dieser Artikel führt die KIO Bibliothek ein und erklärt wie man Dateien laden und speichern kann.''<br />
<br />
;[[Development/Tutorials/KCmdLineArgs (de)|Befehlszeilen Argumente (todo)]]<br />
:''In diesem Artikel werden Sie lernen Ihrer Anwendung zu ermöglichen, Dateien über die Befehlszeile oder sogar unter Dolphin mit 'Öffnen mit' zu laden''<br />
<br />
== Grundlagen ==<br />
;[[Development/Tutorials/KDE4 Porting Guide (de)|Ihre Applikation nach KDE 4 portieren]]<br />
:''Anleitungen Qt3/KDE3 Applikationen nach Qt4/KDE4 zu portieren''<br />
<br />
;[[Development/Tutorials/CMake (de)|Einführung in CMake]]<br />
:''Wie man CMake in KDE 4 benutzt''<br />
<br />
;[[Development/Tutorials/Common Programming Mistakes (de)|Häufige Programmierfehler]]<br />
:''Einige häufige Fehler die man während der Entwicklung von Qt und KDE Applikationen machen kann und wie man sie vermeidet.''<br />
<br />
;[[Development/Tutorials/Using Qt Designer (de)|Den Qt Designer benutzen um Benutzerschnittstellen zu erzeugen]]<br />
:''Wie man UI Dateien mit dem Designer erzeugt und wie man diese in einem KDE Programm integriert.''<br />
<br />
== Testen und Fehler beheben ==<br />
<br />
;[[Development/Tutorials/Debugging (de)|Debugging Ihrer Applikation]]<br />
:''Tips, Tools und Techniken zum Debuggen von KDE Applikationen''<br />
<br />
;[[Development/Tutorials/Unittests|Schreiben von Unit-Tests für Qt4 und KDE4 mit QTestLib]] ([http://developer.kde.org/documentation/tutorials/writingunittests/writingunittests.html Original link])<br />
:''Tutorial von [mailto:bradh@frogmouth.net Brad Hards] das beschreibt, wie man Unit-Tests mit dem QTestLib Framework erstellt. Das Tutorial wird anhand eines Beispiels beschrieben und befindet sich zur Zeit noch in Entwicklung.''<br />
<br />
;[[Development/Tutorials/Code_Checking|Halbautomatische Wege zur Erkennung von Programmierfehlern]]<br />
:''Techniken um Fehler in KDE Code aufzuspüren''<br />
<br />
== Konfigurationen mit KConfig verwalten ==<br />
;[[Development/Tutorials/KConfig (de)|Einführung in KConfig]]<br />
:''Eine Übersicht über die zu KConfig gehörenden Klassen und wie Sie diese in Ihre Anwendung einbinden können''<br />
<br />
;[[Development/Tutorials/Using KConfig XT|Benutzung von KConfig XT]]<br />
:''Tutorial über das effiziente Benutzen des KConfig XT Frameworks.''<br />
<br />
;[[Development/Tutorials/Updating KConfig Files|Update von KConfig Dateien]]<br />
:''Tutorial das beschreibt, wie man ein Update-Skript erstellt, dass Veränderungen am Format der Konfiguration Ihrer Anwendung mit den bereits vorgenommenen Einstellungen des Anwenders abgleicht.''<br />
<br />
== Dienste: Applikationen und Plugins ==<br />
;[[Development/Tutorials/Services/Introduction (de)|Einführung in das Dienst-Framework]]<br />
:''Eine Einführung über das Dienst-Framework in KDE und was es dem Applikationsentwickler zur Verfügung stellen kann. Beschäftigt sich mit dem system configuration cache (SyCoCa), den benötigten Dateien und wie indizierte Informationen benutzt werden.<br />
<br />
;[[Development/Tutorials/Services/Traders (de)|Dienste über Trader Queries finden]]<br />
:''Wie man mit der Trader Query Syntax Dienste wie Plugins oder Mimetypes findet, die im SyCoCa zwischengespeichert wurden. ''<br />
<br />
;[[Development/Tutorials/Services/Plugins|Erstellen und Laden von Plugins mit KService]]<br />
:''Zeigt, wie man eigene Plugintypen definiert, installiere Plugins findet (einschließlich denen von anderen Herstellern) und wie man diese einfach und portabel läd, indem man KService benutzt.''<br />
<br />
== Lokalisierung ==<br />
;[[Development/Tutorials/Localization/Unicode (de)|Einführung in Unicode]]<br />
:''Eine Einführung was Unicode ist und wie KDE Applikationen damit umgehen.''<br />
<br />
; [[Development/Tutorials/Localization/i18n (de)|Beim Schreiben der Applikation an die Lokalisierung denken]]<br />
:''Diese Anleitung beschäftigt sich damit, was Lokalisation ist, warum sie wichtig ist und wie man sicherstellt, dass die eigene Applikation bereit ist, lokalisiert zu werden. Jeder Applikationsentwickler sollte das lesen.''<br />
<br />
; [[Development/Tutorials/Localization/i18n Mistakes (de)|Häufige Fehler vermeiden]]<br />
:''Es gibt einige häufige Fehler, die es verhindern, dass eine Applikation angemesssen übersetzt werden kann. Diese Anleitung zeigt diese Fehler auf und zeigt, wie man sie vermeidet.''<br />
<br />
; [[Development/Tutorials/Localization/Building KDE's l10n Module|Erstellen von KDE's Lokalisierungs Modul]]<br />
:''Das Erstellen und Installieren der Sprachunterstützung mit KDE's Lokalisierungs-Modul (l10n) ist ratsam für alle, die an Anwendungen im KDE Haupt-Repository arbeiten. Hierdurch erreichen Sie, das Sie Ihre Anwendung in anderen Sprachen testen und somit auftauchende Probleme erkennen können. Dieses Tutorial bringt Ihnen genau das bei.''<br />
<br />
; [[Development/Tutorials/Localization/i18n Build Systems|Einbeziehen von i18n in das Build System]]<br />
:''Sobald Ihre Anwendung bereit dazu ist lokalisiert zu werden, ist es der nächste Schritt sicherzustellen, dass die Übersetzungsdateien automatisch erstellt und aktuell gehalten werden. Dieses Tutorial behandelt die nötigen Änderungen an den CMakeFile.txt Dateien sowie den Prozess um den resultierenden Nachrichten-Katalog mit Ihrer Applikation zu verteilen.''<br />
<br />
; [[Development/Tutorials/Localization/i18n Challenges|i18n - Herausforderungen and Lösungen]]<br />
:''Dieses Tutorial behandelt die Aufgaben und Fallstricke, die bei der Lokalisierung auftreten wie das Übersetzen von Handbüchern und anderen Daten die ausserhalb des Quellcodes auftreten, das Behandeln von nicht mehr gültigen .po-Dateien, das Umgehen mit Freezes, programmieren in anderen Sprachen als Englisch und Erstellung unabhängiger Releases oder das Verschieben von Anwendungen zwischen KDE Modulen.''<br />
<br />
; [[Development/Tutorials/Localization/i18n_Semantics|Semantisches Markup für Nachrichten]]<br />
:''Um eine konsistente und semantisch korrekte Darstellung von Nachrichten in Anwendungen sicherzustellen, können semantische Kommentare zu den Nachrichten, die übersetzt werden sollen, mit dem KUIT System hinzugefügt werden. Dieses Tutorial beschreibt die Funktionsweise dieses Systems.''<br />
<br />
; [[Development/Tutorials/Localization/i18n Krazy|Automatisierte i18n Codeüberprüfung]]<br />
:''Der Krazy Code-Checker durchsucht KDE's Code und meldet häufige i18n Fehler.''<br />
<br />
; [[Development/Tutorials/Localization/Language Change (de)|Mit Sprachänderungen umgehen]]<br />
:''Wie man seiner Applikation beibringt beim nächsten Start oder zur Laufzeit eine andere Sprache zu benutzen.''<br />
<br />
== Dokumentation ==<br />
<br />
;[[Development/Tutorials/API_Documentation|API Dokumentation]]<br />
:''Dieses Tutorial erklärt, wie Sie Ihre APIs korrekt dokumentieren.''<br />
<br />
;[[Development/Tutorials/Man_Pages|Man Seiten]]<br />
:''Das Schreiben und Erstellen von Referenz-Handbüchern.''<br />
<br />
== Anwendungsautomatisierung und Skripting ==<br />
<br />
=== D-Bus ===<br />
; [[Development/Tutorials/D-Bus/Introduction_(de)|Einführung in D-Bus]]<br />
:''Eine unkomplizierte Einführung in die Kernkonzepte von D-Bus aus der Sicht eines Anwendungs-Programmierers. Dieses Tutorial behandet was D-Bus ist, und wie Sie es in Ihren Anwendungen einsetzen können.''<br />
<br />
; [[Development/Tutorials/D-Bus/Accessing Interfaces|Zugriff auf D-Bus Schnittstellen]]<br />
:''Eine Schrittweise Anleitung zum Aufruf von D-Bus-Methoden und zur Verbindung mit D-Bus-Signalen unter Verwendung von QtDBus.''<br />
<br />
; [[Development/Tutorials/D-Bus/Intermediate_D-Bus|D-Bus für Fortgeschrittene]]<br />
:''Tips zur Verwendung von QtDBus wenn sie mit problematischen Realwelt-Schnittstellen konfrontiert werden.''<br />
<br />
; [[Development/Tutorials/D-Bus/Creating Interfaces|Erstellen von D-Bus Schnittstellen]]<br />
:''Lernen Sie, wie sie Funktionalität Ihrer Applikationen bereit stellen, indem Sie eigene D-Bus Schnittstellen erstellen und benutzen. Beschreibt das Erstellen von XML-Beschreibungen, die Bereitstellung von Schnittstellen zur Laufzeit und das Aufsetzen des Build-Systems mit CMake.''<br />
<br />
; [[Development/Tutorials/D-Bus/Autostart Services|D-Bus Autostart Dienste]]<br />
:''Machen Sie mit diesem Tutorial aus Ihrer Anwendung einen D-Bus-Autostart-Dienst. Dieses Feature, dass auch als "D-Bus Dienst Aktivierung" bekannt ist, ermöglicht es, dass D-Bus Aufrufe zu Ihrer Applikation selbst dann funktionieren, wenn sie gerade nicht läuft indem sie den D-Bus-Daemon Ihre Applikation starten lassen, wenn deren Funktionen benötigt werden.''<br />
<br />
; [[Development/Tutorials/Porting_to_D-Bus|Portieren von DCOP nach D-Bus]]<br />
: ''Portieren Sie mit Hilfe dieser Anleitung Ihre Anwendungen von DCOP nach D-Bus.''<br />
<br />
=== Konqueror ===<br />
; [[Development/Tutorials/Creating Konqueror Service Menus|Erstellung von Konqueror Dienstmenus]]<br />
:''Dieses Tutorial zeigt Ihnen wie Sie MIME-Typ-spezifische Aktionen in Konquerors Kontextmenu bereitstellen.''<br />
<br />
=== Kross ===<br />
; [[Development/Tutorials/Kross/Introduction|Einführung in Kross]]<br />
:''Eine Einführung in das Kross Scripting Framework.''<br />
<br />
; [[Development/Tutorials/Kross/Hello_World|Hallo Welt]]<br />
:''Eine erste Anwendung mit funktionierendem Kross Code.''<br />
<br />
; [[Development/Tutorials/Kross/Connecting_Signals_and_slots_in_Kross|Verbinden von Signalen und Slots in Kross]]<br />
:''Einfache Demonstration, wie man Signale von Objekten mit Slots von Skripten verbindet.''<br />
<br />
; [[Development/Tutorials/Kross/Scripts-as-Plugins|Skripte als Plugins mit Kross]]<br />
:''Dieses Tutorial bietet eine schrittweise Einführung, wie Sie Skripte als Plugins in eine KDE Anwendung integrieren.''<br />
<br />
=== KOffice ===<br />
; [[Development/Tutorials/KOffice Overview|KOffice Übersicht]]<br />
:''Dieses Dokument zeigt eine Übersicht über die verschiedenen KOffice Plugin Typen sowie ihren jeweiligen Nutzen und Stärken.'' Wenn KOffice Plugins neu für Sie sind, ist dieses Tutorial für Sie geeignet.<br />
<br />
; [[Development/Tutorials/Write a Flake Plugin|Erstellen von KOffice Flake Plugins]]<br />
:''Dieses Tutorial zeigt Ihnen wie Sie ein Plugin für KOffice Anwendungen erstellen das Ihnen mit Hilfe von Flake erlaubt, Inhalte in ODF-Dokumente einzubetten.''<br />
<br />
; [[Development/Tutorials/KWord Scripting|KWord Scripting]]<br />
:''Dieses Tutorial zeigt, wie man KWord mit Skriptsprachen wie Python, Ruby oder JavaScript über Kross anspricht.''<br />
<br />
; [[Development/Tutorials/KSpread Scripting|KSpread Scripting]]<br />
:''Dieses Tutorial zeigt, wie man KSpread mit Skriptsprachen wie Python, Ruby oder JavaScript über Kross anspricht.''<br />
<br />
; [[Development/Tutorials/Krita Scripting|Krita Scripting]]<br />
:''Dieses Tutorial zeigt, wie man Krita mit Skriptsprachen wie Python, Ruby oder JavaScript über Kross anspricht.''<br />
<br />
=== SuperKaramba ===<br />
; [[Development/Tutorials/SuperKaramba|SuperKaramba Tutorial]]<br />
:''Dieses Tutorial bietet einen Einblick in SuperKaramba, Themen-Dateien und das Skripten mit Python, Ruby und JavaScript.<br />
<br />
== Suche und Meta-Daten ==<br />
<br />
=== Strigi ===<br />
<br />
; [[Development/Tutorials/Writing file analyzers|Schreiben von Datei-Analysierern]]<br />
:''Datei-Analysierer extrahieren Daten aus Dateien um Sie in Datei-Dialogen und Datei-Managern anzeigen können. Die Daten die auf diesem Weg erhalten werden, werden auch für die Suche nach Dateien verwendet. KDE4 erlaubt die Benutzung von mehreren Analysierern pro Dateityp. Dieses Tutorial beschreibt, wie Sie neue Analysierer schreiben können.''<br />
<br />
=== [http://nepomuk.kde.org Nepomuk] ===<br />
<br />
; [[Development/Tutorials/Metadata/Nepomuk/Quickstart|Nepomuk Schnellstart]]<br />
:''Einfache Kurzeinführung in die Welt der Nepomuk-Techniken.''<br />
<br />
; [[Development/Tutorials/Metadata/Nepomuk/RDFIntroduction|RDF und Ontologien in Nepomuk]]<br />
:''Einführung in RDF und dessen Benutzung von Ontologien in Nepomuk.''<br />
<br />
; [[Development/Tutorials/Metadata/Nepomuk/Resources|Handling Resources with Nepomuk]]<br />
:''Nepomuk ist die KDE-Bibliothek, die Zugriff auf die Metadaten in Nepomuk erlaubt. Hier wird erklärt, wie ein Programm Metadaten mit Nepomuk schreiben und lesen kann.''<br />
<br />
; [[Development/Tutorials/Metadata/Nepomuk/ResourceGenerator|Using the Nepomuk Resource Generator]]<br />
:''Nepomuk includes a resource generator which creates convenience classes for handling metadata.''<br />
<br />
== Ansprechen von Hardware (Solid) ==<br />
<br />
;[[Development/Tutorials/Solid_Tutorials|Einführung in Solid]]<br />
:''Eine Einführung in die Benutzung der Solid Hardware-Erkennung und -Verwendung in KDE Applikationen.''<br />
<br />
;[[Development/Tutorials/Solid_Network_Tutorial|Zugriff auf Netzwerk-Informationen]]<br />
:''Wie man Solid benutzt um Informationen über das Netzwerk herauszufinden''<br />
<br />
== Multimedia (Phonon) ==<br />
<br />
;[[Development/Tutorials/Phonon/Introduction|Phonon]]<br />
:''Erste Schritte mit der Multimedia API''<br />
<br />
:''Erstellung und Benutzung von Phonon und seinem GStreamer Backend unter Linux mit Qt 4.3.x''<br />
::''Dieser Artikel gibt Ihnen eine kurze Anleitung wie Sie Phonon und sein GStreamer Backend unter GNU/Linux mit lediglich Qt 4.3.x beziehen, kompilieren und benutzen können. Gegen Ende beschreibt der Artikel zusätzlich, wie ein Entwickler Phonon benutzen kann um einfache Audio- und Video-Spieler zu erstellen. Sie können den Artikel [http://www.vcreatelogic.com/oss/docs/CompilingPhononOnLinux.pdf hier] lesen.<br />
Sie können die editierbare OpenDocumentText Datei von [http://www.prashanthudupa.com/phonon/CompilingPhononOnLinux.odt hier]. herunterladen''<br />
<br />
== Plasma ==<br />
<br />
;[[Development/Tutorials/Plasma/GettingStarted_(de)|Erste Schritte mit Plasmoids]]<br />
:''Erstellung Ihres ersten Plasma-Widgets oder Plasmoids in C++ mit einem SVG Hintergrund, einem Icon und etwas Text''<br />
<br />
;[[Development/Tutorials/Plasma/DataEngines|Schreiben einer DataEngine]]<br />
:''DataEngines bieten eine standardisierte Schnittstelle zur Darstellung von Daten aus verschiedenen Datenquellen. Lernen Sie was eine DataEngine ist und wie Sie selbst ein schreiben können.''<br />
<br />
;[[Development/Tutorials/Plasma/UsingDataEngines|Benutzung von DataEngines in Plasmoids]]<br />
:''Mit einer DataEngine ist es möglich, Daten auf einfache und standardisierte Art und Weise zu empfangen und darzustellen. Dieses Tutorial behandelt das Thema, wie man DataEngines zu diesem Zweck in Plasma einsetzt.''<br />
<br />
;[[Development/Tutorials/Plasma/AbstractRunner|Erstellen von Runners]]<br />
:''Runners sind Plugins die Aktions-basierte Suchfunkionalität im Plasma Ausführen-Dialog erlauben. Diese Plugins können von jeder Applikation verwendet werden, die libplasma einbindet.''<br />
<br />
== Kate / Kwrite ==<br />
<br />
;[[Development/Tutorials/Kate/KTextEditor Plugins|Erste Schritte mit KTextEditor Plugins]]<br />
:''Erstellung Ihres ersten KTextEditor Plugins''<br />
<br />
== Drucken ==<br />
<br />
;[[Development/Tutorials/Printing Hello World|Hallo Welt]]<br />
:''Einführung in das KDE Drucksystem''<br />
<br />
;[[Development/Tutorials/Printing Print Dialog|Druckdialog]]<br />
:''Benutzung des KDE Druckdialogs''<br />
<br />
== Neue Dinge herunterladen ==<br />
; [[Development/Tutorials/Introduction to Get Hot New Stuff|Einführung in "Neue Dinge herunterladen"]]<br />
:''Eine Einführung in das Entwickler-freundliche Netzwerk-Update-System das KDE Applikationen erlaubt, neue Anwendungsdaten zur Laufzeit auf benutzerfreundliche Weise herunterzuladen.''<br />
<br />
;[[Development/Tutorials/KNewStuffSecure|Sicherheit mit KNewStuff]] ([http://developer.kde.org/documentation/tutorials/knewstuffsecure/index.html Original Link])<br />
:''Tutorial das zeigt, wie man Ressourcen auf sichere Weise teilt (KDE 3.4 und später).'' Geschrieben von Andr&#225;s Mantia &lt;amantia@kde.org&gt;.<br />
<br />
== Schnelle Anwendungsentwicklung ==<br />
<br />
=== Python ===<br />
<br />
;[[Development/Tutorials/Python introduction to signals and slots|101 Einführung in Signale und Slots]]<br />
:''Eine einfache Einführung in Qt's Signal- und Slot-Architektur.''<br />
<br />
=== Ruby ===<br />
<br />
;[http://developer.kde.org/language-bindings/ruby/kde3tutorial/index.html KDE Ruby Korundum Tutorial]<br />
:''Eine Ruby-Version von Antonio Larossa Jim&eacute;nezs KDE Tutorial von Richard Dale. Sehen Sie sich for Qt Tutorials und andere Informationen auch die [http://developer.kde.org/language-bindings/ruby/index.html Ruby Developers Corner] an.''<br />
<br />
;[[Development/Tutorials/Qt4_Ruby_Tutorial|Qt4 Ruby Tutorial]]<br />
:''Trolltechs sagenhaftes Einstiegstutorial in Qt, übersetzt für Ruby.''<br />
<br />
=== Shell ===<br />
<br />
;[[Development/Tutorials/Shell_Scripting_with_KDE_Dialogs|Shell Scripting mit KDE Dialogen]] ([http://developer.kde.org/documentation/tutorials/kdialog/t1.html Original Link])<br />
:''Tutorial von [mailto:bradh@frogmouth.net Brad Hards] das beschreibt, wie man KDE Dialoge mit Hilfe von kdialog in Shell-Skripten verwendet. Das Tutorial wird anhand eines Beispiels durchgeführt.''<br />
<br />
== Andere Tutorials ==<br />
<br />
=== Benutzung der KDE Games Bibliothek ===<br />
;[[Development/Tutorials/Games/KStandardGameAction| KStandardGameAction]]<br />
:''Benutzung von libkdegames um Ihr Spiel dem kdegames Standard anzupassen''<br />
;[[Development/Tutorials/Games/Highscores| Highscores]]<br />
:''Implementierung einer einfachen Highscore-Tabelle in Ihrem Spiel''<br />
;[[Development/Tutorials/Games/Theme Selector| Themen-Auswahl]]<br />
:'' Benutzung des libkdegames Themen-Auswahl-Dialogs''<br />
<br />
=== 2D Plotting (KPlotWidget) ===<br />
;[[Development/Tutorials/KPlotWidget|Benutzen des KDE Daten-Plotting Widgets]]<br />
:''Dieses Tutorial führt KPlotWidget ein, welches zum plotten zweidimensionaler Daten verwendet werden kann. Es enthält Informationen zu einfachen Benutzung des Widgets (inklusive Hinzufügen und Änderung von Datensätzen sowie Anpassung der Koordinatenachsen und deren Beschriftung) sowie erweiterten Anwendungsfällen (inklusive Erweiterung des Widgets durch Vererbung).''<br />
<br />
=== Rechtschreib- und Grammatikprüfung (Sonnet) ===<br />
;[[Development/Tutorials/Sonnet/SonnetTutorial|Rechtschreib- oder Grammatikprüfung in KDE Applikationen einbinden]]<br />
:''Diess Tutorial führt in Sonnet ein und wie man es benutzt um Sprachkorrekturen in der eigenen KDE Anwendung zu verwenden. Sonnets Hilffunktionen sollen in einem weiteren Tutorial beschrieben werden.''<br />
<br />
=== Pixmap cache (KPixmapCache) ===<br />
;[[Development/Tutorials/KPixmapCache|Benutzung des KDE Pixmap Caches]]<br />
:''Dieses Tutorial demonstriert die Benutzung von KPixmapCache zum Zwischenspeichern von beispielsweise Pixmaps die aus SVGs oder Daten erstellt wurden.''<br />
<br />
== Material für KDE2 und KDE3 ==<br />
<br />
;[[Development/Tutorials/KDE3|KDE3 Tutorials]]<br />
:''Diese Tutorials behandeln Themen im Bezug auf KDE3.''<br />
<br />
;[[Development/Tutorials/KDE2|KDE2 Tutorials]]<br />
:''Diese Tutorials behandeln Themen im Bezug auf KDE2.''<br />
<br />
[[Category:KDE4]]</div>Bluesnikhttps://techbase.kde.org/index.php?title=Development/Tutorials/D-Bus/Introduction_(de)&diff=53292Development/Tutorials/D-Bus/Introduction (de)2010-08-09T21:26:24Z<p>Bluesnik: Übersetzung der englischen Seite, 1. Fassung</p>
<hr />
<div>{{Template:I18n/Language Navigation Bar|Development/Tutorials}} <br />
<br />
== Übersicht ==<br />
[http://www.freedesktop.org/wiki/Software/dbus D-Bus] ist ein freier, Quelloffener Software - '''I'''nter-'''P'''rocess-'''C'''ommunication (IPC)- Mechanismus, der zur Zeit (2010) weitverbreitet in Open-Source-Desktop Software ist. Er ist Teil des [http://freedesktop.org/ freedesktop.org] Projekts und wird von den meisten aktuellen Anwendungen eingesetzt. Beispiele hierfür sind die Hotplug-Notifications unter Linux, Desktop-Such-Anfragen mit Strigi und in primärer Bedeutung die IPC in KDE4.<br />
Dieses Tutorial stellt die D-Bus Terminologie vor und wirft einen Blick aus Sicht des Anwendungs-Entwicklers auf die zentralen Konzepte des D-Bus.<br />
<br />
<br />
== Was ist IPC? ==<br />
Der Begriff "IPC" beschreibt eine beliebige Anzahl von Methoden, um Informationen von einem Prozess zu einem anderen zu übermitteln. Die übertragenen Informationen können in Form von Applikationsdaten, Methodenaufrufen oder spontane Signalen aus z.B. einem DSP, vorliegen. Die eigentliche Kommunikation erfolgt dann über (Unix-)Sockets oder Pipes und manchmal, wie im Fall vom D-Bus, übernimmt ein Prozess das Message-Routing, Service-Aktivierung und Zugriffskontrolle.<br />
<br />
Der normale Fall von IPC auf dem Desktop, erstreckt sich von Skripten ( die es dem User erlauben, in einer gemeinsamen Umgebung mit einer Vielzahl von anderen Anwendungen zu interagieren, bzw. sie zu kontrollieren), über das Bereitstellen zentraler Dienste, bis hin zur Koordination zwischen mehrfachen Instanzen kooperativer Anwendungen.<br />
<br />
Als konkretes Beispiel kann der Dateizugriff in KDE dienen, der üblicherweise über das KIO Virtual File System (VFS) erfolgt und dabei KIOSlaves nutzt. Diese KIOSlaves sind kleine Programme, die Lese-, Schreib-, usw. -Zugriffe auf die gewünschten Daten, über gegebene Protokolle, bzw. Spezifikationen (wie z.B. http oder local Filesystem API), zur Verfügung stellen. Die Slaves laufen als unabhängige Prozesse und tauschen ihre Daten mit der Anwendung - die der User gerade verwendet - asynchron über IPC. Dies erlaubt nicht nur, dass der selbe Slave von verschiedenen Anwendungen angesprochen werden kann, sondern auch, dass der Slave selbst so einfach wie möglich gehalten werden kann. Es sind z.B. blockierende Operationen möglich, ohne dass die grafische Anwendung selbst blockiert wird. Die grafische Anwendung "sieht" niemals die aktuelle IPC, die im Hintergrund der KIO API erfolgt.<br />
<br />
Ein anderes Beispiel für IPC ist der Gebrauch in KDE's "Unique Application Support". Wenn eine UniqueApplication gestartet wird, erfolgt eine Prüfung, ob bereits eine Instanz der selben Anwendung läuft und diese dann gegebenenfalls in den Vordergrund geholt, indem eine entsprechende Nachricht an sie gesendet wird, sich selbst zu zeigen.<br />
<br />
Der primäre IPC Mechanismus für Anwendungen unter KDE4, ist D-Bus, ein populäres System, das von verschiedenster Software genutzt wird. QT4 stellt einen Satz intuitiver, stabiler Zugriffsmethoden zum D-Bus in Form von C++ Klassen bereit. Diese Tutorial-Serie stellt den D-Bus, sowie den Gebrauch der QT4 D-Bus API, vor. Dieser Artikel beschreibt die übergeordneten Aspekte des D-Bus und überlässt die Details, wie man diese Möglichkeiten nutzt, dem folgenden Kapitel.<br />
<br />
<br />
== Busse ==<br />
D-Bus bietet mehrere Nachrichten-"Busse" zur Kommunikation der Anwendungen untereinander. Jeder Bus verfügt über seinen eigenen Satz an Eigenschaften, was es erlaubt verschiedene Kategorien von Nachrichten zu unterscheiden: Nachrichten auf einem Bus können nicht von einem anderen Bus aus erreicht und manipuliert werden, aber die Anwendungen, die an einem gemeinsamen Bus hängen, können jederzeit miteinander kommunizieren. Verschiedene Anwendungen können jederzeit mit jedem gegebenen Bus verbunden sein. Und eine Anwendung kann gleichzeitig mit mehreren Bussen verbunden sein. Dies erlaubt verschiedene Sicherheitsstufen auf verschiedenen Bussen während gleichzeitig eine effiziente Verteilung globaler und lokaler Nachrichten gewährleistet ist.<br />
<br />
Ein Systemweiter Bus für Nachrichten des OS-Kernel selbst und andere Systemglobale Dienste steht standardmäßig zur Verfügung und wird sinnigerweise der '''system bus''' genannt. Dieser Bus wird zur Signalisierung genutzt, wenn neue Hardware am System verfügbar ist, wie z.B ein angesteckter USB Stick oder eine neu eingelegte DVD.<br />
<br />
Jede Desktop Sitzung (z.B. jeder eingeloggte User) ist mit einem oder mehreren Bussen verbunden. Diese werden die '''session busse''' genannt. Der Standard Bus für die aktuelle Sitzung (Session) wird als ''der'' Session Bus bezeichnet und ist derjenige, den Desktopanwendungen am häufigsten zu benutzen versuchen.<br />
<br />
Außerdem kann eine Anwendung ihren eigenen privaten Bus zwischen sich und einer anderen Anwendung, wie eine peer to peer Verbindung, aufbauen.<br />
<br />
Es gibt praktisch keine Grenze der Anzahl an Bussen, die von Anwendungen von einem spezifischen User genutzt werden können. Wie auch immer, es ist die Fähigkeit, Busse, und damit die darüber geschickten Nachrichten, gemeinsam nutzen zu können, durch die Systeme wie der D-Bus glänzen.<br />
<br />
== Nachrichten ==<br />
Die grundlegende Einheit der Kommunikation auf einem Bus ist die Nachricht. Jede Information, die über den Bus geschickt wird, geschieht in Form einer Nachricht, ähnlich, wie jede Information in TCP/IP Netzen in Paketen verschickt wird. Anders als in Netzwerk-Paketen, garantiert der D-Bus die vollständige Übermittlung des gesamten Datensatzes. Zusätzlich zu den Nutzdaten werden der Sender und Empfänger protokolliert, um ein verlässliches (Daten-)Routing bieten zu können.<br />
<br />
Dieses System bildet die interne Arbeitsweise von Desktop-Anwendungen sehr gut ab: Methodenaufrufe resultieren in ausgeführten Aktionen mit der Möglichkeit, Werte zurückzuliefern. Eine der primären zusätzlichen Eigenschaften der D-Bus Nachrichten, ist ihre Asynchronität: eine Nachricht kann gesendet werden, während die Antwort nicht innerhalb einer bestimmten, erwarteten Zeit erfolgt (Timeouts werden angeboten, um ein "Deadlock" zu verhindern). Natürlich gibt es bequeme Möglichkeiten in der Qt4-D-Bus-API, um Aufrufe zu tätigen, die ''scheinbar'' synchron mit der aufrufenden Anwendung laufen.<br />
<br />
Eine Anwendung kann Nachrichten an sich selbst schicken. Diese werden sozusagen "kurzgeschlossen" und verbleiben lokal zu der Anwendung. Dadurch ist es nich nötig, innerhalb der Anwendung Code bereitzustellen, der zwischen internen und externen Nachrichtenaufrufen unterscheidet. Für die Anwendung ist es egal woher die Nachricht stammt, solange die Reaktion darauf festgelegt ist. Das ist in hoch integrierten Anwendungssuiten oft sehr nützlich und verhindert schon viele Möglichkeiten eines Deadlocks, in dem mehrere Prozesse wechselseitig auf ihre Ergebnisse warten.<br />
<br />
== Namensräume und Adressen ==<br />
Da mehrere Anwendungen auf demselben Bus operieren können und eine Anwendung mehrere Objekte besitzen kann, die Nachrichten empfangen und verarbeiten können, ist es notwendig ein Mittel zur eindeutigen Identifizierung einer gegebenen Nachricht zu haben. Ähnlich wie eine Wohnortsangabe durch Stadt, Strasse und Hausnummer gibt es 3 Informationen, die zusammengenommen eine eindeutige Adressierung für jedes Objekt auf dem Bus ermöglichen: die Schnittstelle, der Dienst und der Objektname.<br />
<br />
=== Schnittstellen (Interface) ===<br />
Eine '''Schnittstelle''' ist ein Satz aufrufbarer Methoden und Signale, die an den Bus gebunden sind. Eine Schnittstelle ist ein "Vertrag" zwischen den Anwendungen, der den Namen, die erforderlichen Parameter (wenn vorhanden) und Rückgabewerte (wenn vorhanden), definiert. Diese Methoden müssen nicht 1:1 auf Methoden oder das API der Anwendung abgebildet sein, wenn sie es auch häufig sind. Dies erlaubt es, dass verschiedenen Anwendungen, den gleichen Satz an Steuerungsmöglichkeiten anzubieten, selbst wenn die darunterliegende Funktionalität gänzlich anders implementiert wurde.<br />
<br />
Schnittstellen können durch Anwendung von XML, für die Dokumentation und laufenden Code gleichzeitig beschrieben werden. Nicht nur, dass User und Programmierer dies als Referenz benutzen, es ist auch möglich (Objekt-) Klassen automatisch aus XML Beschreibungen heraus generieren zu lassen, was das Benutzen des D-Bus vereinfacht und die Fehlerträchtigkeit senkt (z.B. kann der Compiler die Syntax von Nachrichten schon zur Kompilierzeit überprüfen).<br />
<br />
=== Dienste (Services) ===<br />
Ein '''Dienst''' stellt eine Verbindung der Anwendung zu einem Bus dar.<br />
<br />
'''Dienst''' bedeutet hier einer der "well known (wohlbekannter)" [http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names Bus Namen] in der D-Bus Spezifikation Terminologie. Der Begriff "Bus Name" ist ein wenig verwirrend, ungeachtet seines Klangs. '''Bus Namen''' sind die Namen der Verbindungen(!) auf dem Bus, NICHT die Namen von Bussen. Der Begriff "Dienst" bzw. seine englische Bezeichnung "service", wird hier in der gleichen Weise benutzt, wie die QT Dokumentation es handhabt.<br />
<br />
Dienste werden eindeutig identifizier- und ansprechbar gehalten, indem ein "Reverse Domain Name" Ansatz angewendet wird, wie es sich in vielen anderen Systemen bewährt hat, die Namensräume für viele Komponenten benötigen. Die meisten Dienste die von Anwendungen innerhalb des KDE Projekts bereitgestellt werden, benutzen das Prefix "org.kde". Also kann man höchstwahrscheinlich den Namen "org.kde.screensaver" auf dem session Bus wiederfinden, da er dort, wie oben beschrieben, proklamiert wird.<br />
<br />
Man sollte den Domainnamen der eigenen Organisation und den Namen der Anwendung für einen guten Servicenamen zusammenfassen. Zum Beispiel, der Domainname lautet "fantastischsoft.de" und der Anwendungsname "unglaublichgut", dann könnte man seine Anwendung unter dem Dienstnamen (servicename) "de.fantastischsoft.unglaublichgut" auf dem D-Bus proklamieren.<br />
<br />
Wenn eine Anwendung mehr als eine Verbindung zum Bus hat, oder wenn mehrere Instanzen der selben Anwendung zeitgleich aktiv sind, wird ein eindeutiger Dienstname für jede Verbindung benötigt. Der Einfachkeit halber wird dann meist die Prozess-ID an den Dienstnamen angehängt.<br />
<br />
=== Objekte ===<br />
Natürlich kann eine Anwendung wünschen, auf mehr als ein Objekt auf dem Bus zuzugreifen. Diese Viele-zu-Eins Beziehung zwischen Objekten und Diensten wird durch das Angebot einer Pfad-Komponente zur entsprechenden Adresse erreicht. Jeder Pfad zu einem Dienst stellt ein eindeutiges, klar unterscheidbares Objekt dar. Ein Beispiel könnte <code>/MainInterface</code> oder <code>/Documents/Doc1</code> sein. Die aktuelle Pfadstruktur ist völlig beliebig und es liegt an der Anwendung, den Dienst anzubieten wie diese Pfadstruktur zu interpretieren ist. Diese Pfade stellen einen einfachen Weg dar, Objekte, die Nachrichten an die Anwendung senden, zu identifizieren und logisch zusammenzufassen.<br />
<br />
Einige (Software-)Bibliotheken exportieren Objekte mit vorangestellter "reverse Domain", um ihre Objekte in einem definierten eigenem Namensraum benutzen zu können.Das ist üblich für Bibliotheken und "Plugins", die sich einen beliebigen Dienst teilen und so eine Kollision der Objekt-Namen vermeiden, die ja auch von anderen Komponenten exportiert werden könnten. Allerdings wird diese Praxis nicht innerhalb von KDE Anwendungen und Bibliotheken angewendet.<br />
<br />
Objekte bieten Zugriff auf Schnittstellen. Tatsächlich kann ein bestimmtes Objekt Zugriff auf mehrere Schnittstellen gleichzeitig bieten.<br />
<br />
== Zusammenfassung ==<br />
Eine D-Bus-Nachricht enthält eine Adresse aus allen oben genannten Komponenten, so dass sie auf die richtige Anwendung, Objekt und Methode geroutet werden kann. Eine solche Adresse kann wie folgt aussehen:<br />
<code>org.kde.krunner /ScreenSaver org.kde.screensaver.setBlankOnly</code><br />
In diesem Fall ist "org.kde.krunner" der Dienst. "/ScreenSaver" ist der Pfad zum Objekt. "org.kde.screensaver" ist die Schnittstelle, die vom Objekt exportiert wird und "setBlankOnly" ist eine Methode, die in der Schnittstelle definiert ist. Wenn das /ScreenSaver Objekt nur die org.kde.screensaver Schnittstelle anbietet (oder die setBlankOnly Methode einzigartig unter den eingebundenen Diensten ist), dann ist der folgende Aufruf gleichbedeutend mit dem obigen:<br />
<code>org.kde.krunner /ScreenSaver setBlankOnly</code><br />
Auf diese Weise wird jedes mögliche Ziel eindeutig und zuverlässig adressierbar.<br />
<br />
== Aufrufen und Aufgerufen werden ==<br />
Jetzt, da wir einen Weg haben, jeden beliebigen Endpunkt auf dem Bus zu adressieren, können wir die Möglichkeiten prüfen, wenn es um das tatsächlich Senden oder Empfangen von Nachrichten geht.<br />
<br />
=== Methoden ===<br />
Methoden sind Nachrichten, die gesendet werden, um Programmcode in der empfangenden Anwendung ausführen zu lassen. Wenn die Methode nicht verfügbar ist, weil z.B. die Adresse falsch ist, oder die angeforderte Anwendung nicht ausgeführt wird, wird ein Fehler an die aufrufende Anwendung zurückgegeben.<br />
Wenn die Methode erfolgreich aufgerufen wird, wird ein optionaler Rückgabewert an die aufrufende Anwendung zurückgegeben. Selbst wenn kein Rückgabewert vorgesehen ist, wird eine entsprechende Erfolgsmeldung zurückgegeben. Diese Vorgehensweise erzeugt eine Menge "Overhead" und es ist wichtig, dies bei Performance-kritischem Code im Auge zu behalten.<br />
<br />
Solche Methodenaufrufe erfolgen immer durch die rufende Anwendung und die resultierenden Nachrichten haben genau einen Ursprung und eine Zieladresse.<br />
<br />
=== Signale ===<br />
Signale sind wie Methodenaufrufe, außer, dass sie in die "umgekehrte" Richtung passieren und sind nicht auf ein einzelnes Ziel gebunden sind. Ein Signal wird von der Anwendung emittiert (ausgegeben), die die Schnittstelle bereitstellt und ist für jede Anwendung auf dem gleichen Bus verfügbar. Dies ermöglicht es einer Anwendung, spontane Veränderungen im Status, oder andere Ereignisse, an jede Anwendung, die daran interessiert sein könnte, zu propagieren.<br />
<br />
Wenn das jetzt alles wie der Signal-Slott Mechanismus von QT klingt, dann liegt das daran, dass es letztendlich dieser ist. Für alle Absichten und Zwecke ist es eine nicht-lokale Version der gleichen Funktionalität.<br />
<br />
== Nützliche Werkzeuge ==<br />
Es gibt mehrere nützliche Werkzeuge für die Erkundung des D-Bus sowie die Entwicklung von Applikationen, die D-Bus verwenden. Werfen wir hier einen kurzen Blick auf die Hilfsmittel, die in den folgenden Kapiteln detaillierter behandelt werden:<br />
<br />
=== qdbus ===<br />
qdbus ist ein Kommandozeilen Werkzeug, das dazu benutzt werden kann, die Dienste, Objekte und Schnittstellen auf einem gegebenen Bus aufzulisten. Man kann damit das System den "default session bus" erforschen. Wenn der [pre]--system[/pre] Parameter mitgegeben wird, verbindet sich qdbus mit dem System-Bus, ansonsten mit dem Session-Bus.<br />
<br />
qdbus interpretiert weitere Argumente als Adress und, soweit vorhanden, als an das Objekt zu übergebende Parameter. Wenn keine vollständige Adresse angegeben wird, dann werden alle verfügbaren Objekte dieses Busendpunktes aufgelistet. Wenn z.B. gar keine Adresseb übergeben wurde, werden alle verfügbaren Dienste aufgezeigt. Wenn ein Dienst angegeben wurde, dann werden alle dazugehörigen Objektpfade gelistet. Usw. Auf diese Weise kann man ganz einfach mit Objekten interagieren und diese erforschen. Das macht qdbus zum idealen Werkzeug zum Testen, Skripten und einfach nur zum Untersuchen.<br />
<br />
=== qdbusviewer ===<br />
qdbusviewer ist eine QT Anwendung mit grafischer Oberfläche, die die gleiche Funktionalität wie qdbus auf der Kommandozeile bietet. Nur eben grafisch. Dies ist eine etwas benutzerfreundlichere Art, mit dem Bus herumzuspielen und ihn zu untersuchen. qdbusviewer wird zusammen mit QT4 ausgeliefert und ist für jemanden der die Grundkonzepte des D-Bus kennt, intuitiv zu bedienen.</div>Bluesnik