我正在尝试使用Qt的QDBus调用WPA请求者的DBus接口(interface)
类库。特别是,我正在尝试使用“获取”属性
调用以检索“接口(interface)”属性值。

“获取”的DBus规范(通过自省(introspection))为:

<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类型)。对于“接口(interface)”属性,我是
期望变体是对象路径的数组(DBus类型“ao”)。

我正在使用QDBusInterface::call()调用DBus方法,该方法
返回QDBusMessage,但我不知道如何提取数据
由此。
QDBusMessage::arguments()返回一个QList<QVariant>。我试过了
此列表中各项的各种转换,以查找我的
对象路径数组,但我似乎最终以一个空字符串结尾
反而。
QVariant::type()似乎应该有所帮助,但似乎只能
返回QDBusMessage类型,这显然是错误的。例如:
// 'message' is of type QDBusMessage
qDebug() << "Argument 0 type is" << message.arguments().at(0).type();

打印:
Argument 0 type is QVariant::QDBusMessage

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

最佳答案

我发现的最简单的方法是使用qDebug()随手打印结果。这通常会指出您需要转换为下一个类型,直到您最终找到最里面的类型。

Qdbusviewer 是确定DBus参数的有用工具,
将被要求。在这种情况下:

  • WPAS服务:“fi.w1.wpa_supplicant1”
  • WPAS路径:“/fi/w1/wpa_supplicant1”
  • 属性接口(interface)标识符:“org.freedesktop.DBus.Properties”
  • WPAS接口(interface)标识符:“fi.w1.wpa_supplicant1”

  • 在初始化QDBusInterface以调用Get时,我们需要使用Properties接口(interface),因为这是提供Get的接口(interface)
    方法。

    在使用Get方法调用QDBusInterface::call()时,第二个和
    第三个参数对应于
    内省(introspection)输出("interface""propname")。 "interface"
    在哪里可以找到该属性,对于"Interfaces"属性
    "fi.w1.wpa_supplicant1"(可以使用 qdbusviewer 确认)。
    "propname"参数只是属性的名称:
    在这种情况下为"Interfaces"

    到目前为止的代码:
    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" );
    

    这是困难的部分。 QDBusInterface::call()返回一个QDBusMessage
    其中包含我们的属性(property)信息。
        qDebug() << result;
    

    此调试语句打印:
    QDBusMessage(type=MethodReturn, service=":1.2431", signature="v", contents=([Variant: [ObjectPath: /fi/w1/wpa_supplicant1/Interfaces/7/Networks/0]]) )
    

    看起来挺好的。我们追求的是“ObjectPath”,它肯定在
    在某处。

    接下来,我们需要QDBusMessage::arguments(),“返回列表
    将要发送或从D-Bus接收的参数。”
    返回QList<QVariant>
        QList<QVariant> outArgs = result.arguments();
        qDebug() << outArgs;
    

    调试语句打印:
    (QVariant(QDBusVariant, ) )
    

    这个“符号”还不太清楚(方括号是否表示列表?),但我们将
    继续。
        QVariant first = outArgs.at(0);
        qDebug() << first;
    

    打印:
    QVariant(QDBusVariant, )
    

    所以外括号似乎确实表示一个数组,尽管为什么
    是在内部集合中使用的逗号,而不是在外部集合中使用的逗号
    一个谜。

    在遇到类型时,我们一直在转换类型:
        QDBusVariant dbvFirst = first.value<QDBusVariant>();
        //qDebug() << dbvFirst; // compile error!
    
    qDebug()不了解QDBusVariant,因此没有调试打印
    在这里可用。相反,如果我们查看有关QDBusVariant,我们看到它为
    转换为常规的variant()类型。
        QVariant vFirst = dbvFirst.variant();
        qDebug() << vFirst;
    

    我们似乎确实在转圈,但打印输出有点
    这次不同:
    QVariant(QDBusArgument, )
    

    另一转换:
        QDBusArgument dbusArgs = vFirst.value<QDBusArgument>();
    

    不幸的是,QVariant在这里也不起作用。 qDebug()type可以容纳许多不同的元素类型,下面对此进行了说明
    在Qt文档中。 QDBusArgument告诉您哪个
    输入您的类型。在我们的情况下:
        qDebug() << "QDBusArgument current type is" << dbusArgs.currentType();
    

    打印:
    QDBusArgument current type is 2
    

    2表示QDBusArgument::currentType()

    根据ArrayType文档,我们可以提取
    数组的元素使用如下代码:
        QDBusObjectPath path;
        dbusArgs.beginArray();
        while (!dbusArgs.atEnd())
        {
            dbusArgs >> path;
            // append path to a vector here if you want to keep it
        }
        dbusArgs.endArray();
    

    我假设数组元素的类型为QDBusArgument,因为在这一点上,它使
    感觉如此。如果我是对的,那就很清楚了。

    如果收到错误消息QDBusObjectPath,请将QDBusArgument: write from a read-only object的声明更改为:
        const QDBusArgument &dbusArgs = vFirst.value<QDBusArgument>();
    
    dbusArgs也不支持qDebug(),但是QDBusObjectPath返回一个QDBusObjectPath::path(),因此我们可以进行调试
    像这样打印:
        qDebug() << path.path();
    

    打印:
    "/fi/w1/wpa_supplicant1/Interfaces/7"
    

    终于!

    关于c++ - 如何在Qt DBus调用中从QDBusMessage提取返回的数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20206376/

    10-09 13:37