如何用qdbusxml2cpp生成同步接口class?
How to generate synchronous interface class with qdbusxml2cpp?
问题总结: qdbusxml2cpp
生成一个 QDBusAbstractInterface
sub-class 其方法获取 D-Bus 异步回复 ,但我希望它是同步的(即它应该阻塞直到收到回复)。
XML 输入:
<?xml version="1.0"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="some.interface.Foo">
<method name="GetValues">
<arg name="values" type="a(oa{sv})" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList<SomeStruct>" />
</method>
</interface>
</node>
使用此命令生成 header 和 .cpp 文件(未显示):
qdbusxml2cpp-qt5 -c InterfaceFoo -p interface_foo foo.xml
生成的header:
class InterfaceFoo: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "some.interface.Foo"; }
public:
InterfaceFoo(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
~InterfaceFoo();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<QList<SomeStruct> > GetValues()
{
QList<QVariant> argumentList;
// NOTICE THIS LINE.
return asyncCallWithArgumentList(QStringLiteral("GetValues"), argumentList);
}
Q_SIGNALS: // SIGNALS
};
namespace some {
namespace interface {
typedef ::InterfaceFoo Foo;
}
}
#endif
如您所见,生成的方法 asyncCallWithArgumentList()
是异步的:它期望 connect()
ed 到 D-Bus 回复到达时触发的插槽。
相反,我希望能够做到:
some::interface::Foo *interface = new some::interface::Foo("some::interface", "/Foo", QDBusConnection::systemBus(), this);
// THIS SHOULD block until a reply is received or it times out.
QList<SomeStruct> data = interface->GetValues();
您可以在 return 值上使用 value()
进行阻止,GetValues()
保持原样:
auto reply = interface->GetValues();
auto data = reply.value<QList<QVariant>>();
唉,生成的界面是为了生成一次,然后成为你的源的一部分。您应该修改它以使用阻塞调用,并添加从变体到具体类型的转换:
inline QDBusPendingReply<QList<SomeStruct>> GetValues()
{
QList<QVariant> argumentList;
auto msg = callWithArgumentList(QDBus::Block, QStringLiteral("GetValues"), argumentList);
Q_ASSERT(msg.type() == QDBusMessage::ReplyMessage);
QList<SomeStruct> result;
for (auto const & arg : msg.arguments())
result << arg.value<SomeStruct>();
return result;
}
最后,您可能希望重新考虑使其同步:现实世界是异步的,因此编写代码时就好像它不是异步的通常会适得其反。如果您的代码在主线程中运行并且有一个图形用户界面,您将提供糟糕的用户体验。如果将代码移至辅助线程,那么您就是在浪费整个线程来支持同步编码风格。即使您正在编写相当于非交互式批处理样式 utility/service 的内容,您也可能会增加延迟,例如不并行发出呼叫。
问题总结: qdbusxml2cpp
生成一个 QDBusAbstractInterface
sub-class 其方法获取 D-Bus 异步回复 ,但我希望它是同步的(即它应该阻塞直到收到回复)。
XML 输入:
<?xml version="1.0"?>
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="some.interface.Foo">
<method name="GetValues">
<arg name="values" type="a(oa{sv})" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QList<SomeStruct>" />
</method>
</interface>
</node>
使用此命令生成 header 和 .cpp 文件(未显示):
qdbusxml2cpp-qt5 -c InterfaceFoo -p interface_foo foo.xml
生成的header:
class InterfaceFoo: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "some.interface.Foo"; }
public:
InterfaceFoo(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
~InterfaceFoo();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<QList<SomeStruct> > GetValues()
{
QList<QVariant> argumentList;
// NOTICE THIS LINE.
return asyncCallWithArgumentList(QStringLiteral("GetValues"), argumentList);
}
Q_SIGNALS: // SIGNALS
};
namespace some {
namespace interface {
typedef ::InterfaceFoo Foo;
}
}
#endif
如您所见,生成的方法 asyncCallWithArgumentList()
是异步的:它期望 connect()
ed 到 D-Bus 回复到达时触发的插槽。
相反,我希望能够做到:
some::interface::Foo *interface = new some::interface::Foo("some::interface", "/Foo", QDBusConnection::systemBus(), this);
// THIS SHOULD block until a reply is received or it times out.
QList<SomeStruct> data = interface->GetValues();
您可以在 return 值上使用 value()
进行阻止,GetValues()
保持原样:
auto reply = interface->GetValues();
auto data = reply.value<QList<QVariant>>();
唉,生成的界面是为了生成一次,然后成为你的源的一部分。您应该修改它以使用阻塞调用,并添加从变体到具体类型的转换:
inline QDBusPendingReply<QList<SomeStruct>> GetValues()
{
QList<QVariant> argumentList;
auto msg = callWithArgumentList(QDBus::Block, QStringLiteral("GetValues"), argumentList);
Q_ASSERT(msg.type() == QDBusMessage::ReplyMessage);
QList<SomeStruct> result;
for (auto const & arg : msg.arguments())
result << arg.value<SomeStruct>();
return result;
}
最后,您可能希望重新考虑使其同步:现实世界是异步的,因此编写代码时就好像它不是异步的通常会适得其反。如果您的代码在主线程中运行并且有一个图形用户界面,您将提供糟糕的用户体验。如果将代码移至辅助线程,那么您就是在浪费整个线程来支持同步编码风格。即使您正在编写相当于非交互式批处理样式 utility/service 的内容,您也可能会增加延迟,例如不并行发出呼叫。