如何在 Qt DBus 调用中从 QDBusMessage 中提取返回的数据?
Posted
技术标签:
【中文标题】如何在 Qt DBus 调用中从 QDBusMessage 中提取返回的数据?【英文标题】:How do I extract the returned data from QDBusMessage in a Qt DBus call? 【发布时间】: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<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
如何提取实际的消息数据?
【问题讨论】:
【参考方案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<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
类型。
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<QDBusObjectPath>();
- 最后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
.. 我们可以轻松地在调试中打印或转换为对象中的存储值。
【讨论】:
以上是关于如何在 Qt DBus 调用中从 QDBusMessage 中提取返回的数据?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Ubuntu 中从控制台运行 Qt Creator?
如何在 qt 4.8 中通过 dbus 接收 QList<QVariantMap>?