6

我正在尝试使用 Qt 的 QDBus 类库调用 WPA 请求者的 DBus 接口。特别是,我正在尝试使用“Get”属性调用来检索“Interfaces”属性值。

“Get”的 DBus 规范(通过自省)是:

<interface name="org.freedesktop.DBus.Properties">
    <method name="Get">
        <arg name="interface" type="s" direction="in"/>
        <arg name="propname" type="s" direction="in"/>
        <arg name="value" type="v" direction="out"/>
    </method>
    ...
</interface>

看起来很简单。两个字符串输入和输出是一个变体(这些是 DBus 类型)。对于“接口”属性,我期望变体是对象路径数组(DBus 类型“ao”)。

QDBusInterface::call()用来调用 DBus 方法,它返回 a QDBusMessage,但我不知道如何从中提取我的数据。

QDBusMessage::arguments()返回一个QList<QVariant>。我已经尝试过对这个列表中的项目进行各种转换,以试图找到我的对象路径数组,但我似乎最终得到了一个空字符串。

QVariant::type()似乎它应该有所帮助,但它似乎只返回 type QDBusMessage,这显然是错误的。例如:

// 'message' is of type QDBusMessage
qDebug() << "Argument 0 type is" << message.arguments().at(0).type();

印刷:

Argument 0 type is QVariant::QDBusMessage

如何提取实际的消息数据?

4

3 回答 3

17

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!

于 2013-11-26T00:34:44.453 回答
1

我的目标是获取接口GetInterface方法返回的对象路径。fi.w1.wpa_supplicant1

@MatthewD 的回答对我开始实验很有帮助,但不幸的是没有按要求为我工作。我尝试了所有可能性。但最后,不知何故,我以一种不同的、更短的方式得到了我想要的结果。

我所做的是:
-我有接口:
QDBusInterface interface("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1", "fi.w1.wpa_supplicant1", QDBusConnection::systemBus());

-调用方法并存储消息
QDBusMessage mesg = interface.call("GetInterface", "wlan0");

-然后获取第一个参数
QVariant var = mesg.arguments().at(0);

-然后获取对象路径
QDBusObjectPath objpath = var.value<QDBusObjectPath>();

-最后
QString path_str = objpath.path();

现在将路径打印为字符串:
printf("Object path: %s\n", path_str);

于 2019-08-12T10:12:23.000 回答
0

好吧,经过这么长时间!

我想在调试回复并看到它之后QDBusVariant......

结果的方法将variant()QDBus QDBusVariantVariant 作为QVariant对象返回。因此,调用:

const auto &resultArg = result.arguments().at(0).value<QDBusVariant>().variant();

返回一个QVariant.. 我们可以轻松地在调试中打印或转换为对象中的存储值。

于 2021-06-10T09:00:16.413 回答