How do I extract the returned data from QDBusMessage in a Qt DBus call?

蓝咒 提交于 2019-11-30 07:52:55

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:

  • WPAS Service: "fi.w1.wpa_supplicant1"
  • WPAS Path: "/fi/w1/wpa_supplicant1"
  • Properties interface identifier: "org.freedesktop.DBus.Properties"
  • WPAS interface identifier: "fi.w1.wpa_supplicant1"

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);

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!