【问题标题】:How do I extract the returned data from QDBusMessage in a Qt DBus call?如何在 Qt DBus 调用中从 QDBusMessage 中提取返回的数据?
【发布时间】:2013-12-10 23:08:45
【问题描述】:

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

“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 方法,该方法 返回QDBusMessage,但我不知道如何提取我的数据 从此。

QDBusMessage::arguments() 返回一个QList&lt;QVariant&gt;。我试过了 此列表中的项目的各种转换,以试图找到我的 对象路径数组,但我似乎只是以一个空字符串结束 而是。

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

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

打印:

Argument 0 type is QVariant::QDBusMessage

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

【问题讨论】:

    标签: c++ dbus qtdbus qdbus


    【解决方案1】:

    我发现最简单的方法是使用qDebug() 随时打印结果。这通常会指示您接下来需要转换为哪种类型,直到您最终到达最里面的类型。

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

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

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

    在使用QDBusInterface::call() 方法调用Get 时,第二个和 第三个参数对应于列出的参数 自省输出("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, 其中包含我们的财产信息。

        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&lt;QVariant&gt;

        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 类型。

        QVariant vFirst = dbvFirst.variant();
        qDebug() << vFirst;
    

    我们似乎在绕圈子,但打印输出有点 这次不一样:

    QVariant(QDBusArgument, )
    

    另一个转换:

        QDBusArgument dbusArgs = vFirst.value<QDBusArgument>();
    

    不幸的是,qDebug() 在这里也不起作用。 QDBusArgument type 可以容纳许多不同的元素类型,描述 在 Qt 文档中。 QDBusArgument::currentType() 告诉你哪个 你有的类型。在我们的例子中:

        qDebug() << "QDBusArgument current type is" << dbusArgs.currentType();
    

    打印:

    QDBusArgument current type is 2
    

    2 表示ArrayType

    根据QDBusArgument 文档,我们可以提取 使用如下代码的数组元素:

        QDBusObjectPath path;
        dbusArgs.beginArray();
        while (!dbusArgs.atEnd())
        {
            dbusArgs >> path;
            // append path to a vector here if you want to keep it
        }
        dbusArgs.endArray();
    

    我假设数组元素类型是QDBusObjectPath,因为此时它使 感觉是这样。如果我是对的,那就很清楚了。

    如果您收到错误消息QDBusArgument: write from a read-only object,请将dbusArgs 的声明更改为:

        const QDBusArgument &dbusArgs = vFirst.value<QDBusArgument>();
    

    qDebug() 也不支持QDBusObjectPath,但是 QDBusObjectPath::path() 返回一个QString,所以我们可以得到我们的调试 像这样打印:

        qDebug() << path.path();
    

    打印:

    "/fi/w1/wpa_supplicant1/Interfaces/7"
    

    终于!

    【讨论】:

    • 谢谢@Zimano!当时我花了很长时间才弄清楚,所以我决定在这里记录一下。
    【解决方案2】:

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

    @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&lt;QDBusObjectPath&gt;();

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

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

    【讨论】:

      【解决方案3】:

      好吧,过了这么久!

      我认为在调试回复并看到它的QDBusVariant 之后......

      QDBusVariant 结果的 variant() 方法将 QDBus 变体返回为 QVariant 对象 .. 因此,调用:

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

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

      【讨论】:

        猜你喜欢
        • 2021-03-02
        • 2012-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-10
        • 1970-01-01
        • 2020-06-23
        • 2020-05-05
        相关资源
        最近更新 更多