I\'m trying to call WPA supplicant\'s DBus interface using Qt\'s QDBus class library. In particular, I\'m trying to use the \"Get\" property call to retrieve the \"Interface
The easiest way I've found is to use qDebug()
to print results as you go. This usually points you to which type you need to convert to next, until you finally reach the innermost type.
Qdbusviewer is a useful tool for determining the DBus parameters that will be required. In this case:
In initialising the QDBusInterface
for calling Get
, we need to use the
Properties
interface, since that's the interface that provides the Get
method.
In calling Get
using the QDBusInterface::call()
method, the second and
third parameters correspond to the parameters listed in the
Introspection output ("interface"
and "propname"
). "interface"
is
where the property can be found, which for the "Interfaces"
property
is "fi.w1.wpa_supplicant1"
(this can be confirmed using qdbusviewer).
The "propname"
parameter is just the name of the property:
"Interfaces"
in this case.
The code so far:
std::string getInterface()
{
QDBusInterface interface( "fi.w1.wpa_supplicant1",
"/fi/w1/wpa_supplicant1",
"org.freedesktop.DBus.Properties",
QDBusConnection::systemBus() );
// Calls DBus method
QDBusMessage result = interface.call( "Get",
"fi.w1.wpa_supplicant1",
"Interfaces" );
This is the hard part. QDBusInterface::call()
returns a QDBusMessage
,
which has our property information trapped within.
qDebug() << result;
This debug statement prints:
QDBusMessage(type=MethodReturn, service=":1.2431", signature="v", contents=([Variant: [ObjectPath: /fi/w1/wpa_supplicant1/Interfaces/7/Networks/0]]) )
Looks good. The "ObjectPath" is what we're after, and it's definitely in there somewhere.
Next we need QDBusMessage::arguments()
, which "Returns the list of
arguments that are going to be sent or were received from D-Bus." It
returns a QList<QVariant>
.
QList<QVariant> outArgs = result.arguments();
qDebug() << outArgs;
The debug statement prints:
(QVariant(QDBusVariant, ) )
This 'notation' is a bit unclear (do brackets mean lists?), but we'll keep going.
QVariant first = outArgs.at(0);
qDebug() << first;
prints:
QVariant(QDBusVariant, )
So the outer brackets do seem to indicate an array, though why there is a comma used in the inner set and not in the outer set is a bit of a mystery.
We keep converting types as we come across them:
QDBusVariant dbvFirst = first.value<QDBusVariant>();
//qDebug() << dbvFirst; // compile error!
qDebug()
doesn't understand QDBusVariant
, so no debug print is
available here. Instead if we look at the documentation for
QDBusVariant
, we see that it provides a variant()
method for
converting to a regular QVariant
type.
QVariant vFirst = dbvFirst.variant();
qDebug() << vFirst;
We do seem to be going in circles, but the print output is a bit different this time:
QVariant(QDBusArgument, )
Another conversion:
QDBusArgument dbusArgs = vFirst.value<QDBusArgument>();
Unfortuately, qDebug()
doesn't work here either. The QDBusArgument
type can hold a number of different element types, which are described
in the Qt documentation. QDBusArgument::currentType()
tells you which
type you have. In our case:
qDebug() << "QDBusArgument current type is" << dbusArgs.currentType();
prints:
QDBusArgument current type is 2
2 means ArrayType
.
According to the QDBusArgument
documentation, we can extract the
elements of the array using code like the following:
QDBusObjectPath path;
dbusArgs.beginArray();
while (!dbusArgs.atEnd())
{
dbusArgs >> path;
// append path to a vector here if you want to keep it
}
dbusArgs.endArray();
I've assumed the array element type is QDBusObjectPath
, since at this point it makes
sense for it to be so. It'll be clear if I'm right.
If you get the error message QDBusArgument: write from a read-only object
, change the declaration of dbusArgs
to:
const QDBusArgument &dbusArgs = vFirst.value<QDBusArgument>();
qDebug()
doesn't support QDBusObjectPath
either, but
QDBusObjectPath::path()
returns a QString
, so we can get our debug
print like this:
qDebug() << path.path();
prints:
"/fi/w1/wpa_supplicant1/Interfaces/7"
At last!
My goal was to get the object path returned by GetInterface
method of fi.w1.wpa_supplicant1
interface.
@MatthewD's answer was really helpful to get me started with the experiment but unfortunately didnt work for me as required. I tried all posibilities. But at the end, somehow, I got my required result in a different and a rather shorter way.
What I did was:
- I had the interface:
QDBusInterface interface("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1", "fi.w1.wpa_supplicant1", QDBusConnection::systemBus());
- Call the method and store message
QDBusMessage mesg = interface.call("GetInterface", "wlan0");
- Then get the first argument
QVariant var = mesg.arguments().at(0);
- Then get the object path
QDBusObjectPath objpath = var.value<QDBusObjectPath>();
- And finally
QString path_str = objpath.path();
Now you print the path as string:
printf("Object path: %s\n", path_str);