Qt·DBus快速入门

news2024/11/17 11:22:56

目录

一、QtDBus简介

二、QtDBus类型系统

1、QtDBus类型系统简介

2、原生类型

3、复合类型

4、类型系统的使用

5、扩展类型系统

三、QtDBus常用类

1、QDBusMessage

2、QDBusConnection

3、QDBusInterface

4、QDBusReply

5、QDBusAbstractAdaptor

6、QDBusAbstractInterface

7、QDBusArgument

8、QDBusConnectionInterface

9、QDBusVariant

四、QtDBus工具

1、qdbusviewer

2、qdbuscpp2xml

3、qdbusxml2cpp

五、QtDBus编程

1、创建服务并注册对象

2、通过QDBusMessage访问Service

3、通过QDBusInterface 访问Service

4、从D-Bus XML自动生成Proxy类

5、使用Adapter注册Object

6、自动启动Service


一、QtDBus简介

QtDBus是一个使用D-Bus协议进行进程间通信的仅在Unix运行的库,是对D-Bus底层API的封装实现。
QtDBus模块提供了使用Qt信号槽机制扩展的接口。要使用QtDBus模块,需要在头文件中加入以下代码:

#include <QtDBus>

如果使用qmake构建程序,需要在工程文件中增加下列代码来链接QtDBus库。

QT += qdbus

本文的编译环境为:银河麒麟V10服务器——Kylin Linux Advanced Server release V10 (Tercel),Kernel: 4.19.90-20.2.ky10.x86_64,Build版本:Kylin Linux Advanced Server release V10 (SP1) /(Tercel)-x86_64-Build08/20200902。开发环境:Qt 5.11.1,编译C/C++使用GCC(x86 64bit)。
在该环境下尝试在pro文件中添加以上qdbus语句会提示找不到模块qdbus,改用QT += dbus后编译通过。
以下是系统中dbus相关包以及版本:

[root@localhost qtcreator]# rpm -qa|grep dbus
dbus-tools-1.12.16-13.ky10.x86_64
python3-pydbus-0.6.0-10.ky10.noarch
dbus-glib-0.110-5.ky10.x86_64
python3-dbus-1.2.8-8.ky10.x86_64
dbus-1.12.16-13.ky10.x86_64
lvm2-dbusd-2.02.181-8.ky10.x86_64
dbus-x11-1.12.16-13.ky10.x86_64
qt5-qdbusviewer-5.11.1-4.p01.ky10.x86_64
python2-dbus-1.2.8-8.ky10.x86_64
dbus-libs-1.12.16-13.ky10.x86_64
dbus-common-1.12.16-13.ky10.noarch
dbus-daemon-1.12.16-13.ky10.x86_64

二、QtDBus类型系统

1、QtDBus类型系统简介

D-Bus提供了一种基于“几种原生类型 与 在数组和结构中的原生类型组成的复合类型"的扩展类型系统。QtDBus模块通过QDBusArgument类实现了该类型系统,允许用户通过总线发送和接收每一种C++类型。

2、原生类型

QtDBus通过QDBusArgument支持原生类型,不需要特殊的定制。

Qt类型D-Bus类型
ucharBYTE
boolBOOLEAN
shortINT16
ushortUINT16
intINT32
uintUINT32
qlonglongINT64
qulonglongUINT64
doubleDOUBLE
QStringSTRING
QDBusVariantVARIANT
QDBusObjectPathOBJECT_PATH
QDBusSignatureSIGNATURE

除了原生类型,QDBusArgument也支持在Qt应用中广泛使用的两种非原生类型,QStringList和QByteArray。

3、复合类型

D-Bus指定由原生类型聚合而成的三种复合类型:ARRAY、STRUCT和 maps/dictionaries。ARRAY是零个或多个相同元素的集合,STRUCT是由不同类型的固定数量的元素组成的集合,Maps or dictionaries是元素对的数组,一个map中可以有零个或多个元素。

4、类型系统的使用

为了在QtDBus模块使用自定义类型,自定义类型必须使用Q_DECLARE_METATYPE( )声明为Qt元类型,使用qDBusRegisterMetaType( )函数注册。流操作符会被注册系统自动找到。
QtDBus模块为Qt容器类使用数组和map提供了模板特化,例如QMap和QList,不必实现流操作符函数。对于其它的类型,流操作符必须显示实现。

5、扩展类型系统

QtDBus定义的所有类型能用于通过总线发送和接收消息。不能使用上述类型之外的任何类型,包括typedefs定义的列表类型,如

QList<QVariant> 和 QMap<QString,QVariant>

三、QtDBus常用类

1、QDBusMessage

QDBusMessage类表示D-Bus总线发送或接收的一个消息。
QDBusMessage对象代表总线上四种消息类型中的一种,四种消息类型如下:
A、Method calls
B、Method return values
C、Signal emissions
D、Error codes
可以使用静态函数createError()、createMethodCall()、createSignal()创建消息。使用QDBusConnection::send() 函数发送消息。

2、QDBusConnection

QDBusConnection代表到D-Bus总线的一个连接,是一个D-Bus会话的起始点。通过QDBusConnection连接对象,可以访问远程对象、接口,连接远程信号到本地槽函数,注册对象等。
D-Bus连接通过connectToBus()函数创建,connectToBus()函数会创建一个到总线服务端的连接,完成初始化工作,并关联一个连接名到连接。
使用disconnectFromBus()函数会断开连接。一旦断开连接后,调用connectToBus()函数将不会重建连接,必须创建新的QDBusConnection实例。
作为两种最常用总线类型的辅助,sessionBus()和systemBus()函数分别创建到会话在总线和系统总线的连接并返回,会在初次使用时打开,在QCoreApplication析构函数调用时断开。
D-Bus支持点对点通信,不必使用总线服务。两个应用程序可以直接交流和交换消息。可以通过传递一个地址到connectToBus()函数实现。

以下是常用方法的简介:

  • QDBusConnection connectToBus(BusType type, const QString & name)
    打开一个type类型的连接,并关联name连接名,返回关联本连接的QDBusConnection对象。
  • QDBusConnection connectToBus(const QString & address, const QString & name)
    打开一个地址为address的私有总线,并关联name连接名,返回关联本连接的QDBusConnection对象。
  • QDBusConnection connectToPeer(const QString & address, const QString & name)
    打开一个点对点的连接到address地址,并关联name连接名,返回关联本连接的QDBusConnection对象。
  • void disconnectFromBus(const QString & name)
    关闭名为name的总线连接
  • void disconnectFromPeer(const QString & name)
    关闭名为name的对等连接
  • QByteArray localMachineId()
    返回一个D-Bus总线系统知道的本机ID
  • QDBusConnection sender()
    返回发送信号的连接
  • QDBusConnection sessionBus()
    返回一个打开到session总线的QDBusConnection对象
  • QDBusConnection systemBus()
    返回一个打开到system总线的QDBusConnection对象
  • QDBusPendingCall asyncCall(const QDBusMessage & message, int timeout = -1)const
    发送message消息到连接,并立即返回。本函数只支持method调用。返回一个用于追踪应答的QDBusPendingCall对象。
  • QDBusMessage call(const QDBusMessage & message, QDBus::CallMode mode = QDBus::Block, int timeout = -1 ) const
    通过本连接发送消息message,并且阻塞,等待应答。
  • bool registerObject(const QString & path, QObject * object, RegisterOptions options = ExportAdaptors)
    注册object对象到路径path,options选项指定由多少对象会被暴露到D-Bus总线,如果注册成功,返回true。
  • bool registerService(const QString & serviceName)
    试图在D-Bus总线上注册serviceName服务,如果注册成功,返回true;如果名字已经在其它应用被注册,则注册失败。

3、QDBusInterface

QDBusInterface是远程对象接口的代理。
QDBusInterface是一种通用的访问器类,用于调用远程对象,连接到远程对象导出的信号,获取/设置远程属性的值。当没有生成表示远程接口的生成代码时时,QDBusInterface类对远程对象的动态访问非常有用。
调用通常是通过使用call()函数来实现,call函数构造消息,通过总线发送消息,等待应答并解码应答。信号使用QObject::connect()函数进行连接。最终,使用QObject::property()和QObject::setProperty()函数对属性进行访问。

4、QDBusReply

QDBusReply类用于存储对远程对象的方法调用的应答。
一个QDBusReply对象是方法调用的应答QDBusMessage对象的一个子集。QDBusReply对象只包含第一个输出参数或错误代码,并由QDBusInterface派生类使用,以允许将错误代码返回为函数的返回参数。

QDBusReply<QString> reply = interface->call("RemoteMethod");
 if (reply.isValid())
     // use the returned value
     useValue(reply.value());
 else
     // call failed. Show an error condition.
     showError(reply.error());

对于没有输出参数或返回值的远程调用,使用isValid()函数测试应答是否成功。

5、QDBusAbstractAdaptor

QDBusAbstractAdaptor类使用D-Bus Adaptor基类。
QDBusAbstractAdaptor类是用于使用D-Bus向外部提供接口的所有对象的起点。可以通过将一个或多个派生自QDBusAbstractAdaptor的类附加到一个普通QObject对象上,使用QDBusConnection::registerObject注册QObject对象可以实现。QDBusAbstractAdaptor是一个轻量级封装,主要用于中继调用实际对象及其信号。
每个QDBusAbstractAdaptor派生类都应该使用类定义中的Q_CLASSINFO宏来定义D-Bus接口。注意,这种方式只有一个接口可以暴露。
QDBusAbstractAdaptor使用了信号、槽、属性的标准QObject机制来决定哪些信号、槽、属性被暴露到总线。任何QDBusAbstractAdaptor派生类发送的信号通过任何D-Bus连接自动中继到注册的对象上。
QDBusAbstractAdaptor派生类对象必须使用new创建在堆上,不必由用户删除。

6、QDBusAbstractInterface

QDBusAbstractInterface是QtDBus模块中允许访问远程接口的所有D-Bus接口的基类。
自动生成的代码类也继承自QDBusAbstractInterface,此描述的所有方法在生成的代码中也有效。除了此处的描述,生成代码类为远程方法提供了成员函数,允许在编译时检查正确参数和返回值,以及匹配的属性类型和匹配的信号参数。

QDBusPendingCall asyncCall(const QString & method, 
                           const QVariant & arg1 = QVariant(), 
                           const QVariant & arg2 = QVariant(), 
                           const QVariant & arg3 = QVariant(), 
                           const QVariant & arg4 = QVariant(),
                           const QVariant & arg5 = QVariant(), 
                           const QVariant & arg6 = QVariant(), 
                           const QVariant & arg7 = QVariant(), 
                           const QVariant & arg8 = QVariant())

调用本接口中的method方法,传递参数到远程的method。
要调用的参数会通过D-Bus输入参数传递到远程方法,返回的QDBusPendingCall对象用于定义应答信息。
本函数最多有8个参数,如果参数多于8个,或是传递可变数量的参数,使用asyncCallWithArgumentList()函数。

QString value = retrieveValue();
QDBusPendingCall pcall = interface->asyncCall(QLatin1String("Process"), value);

QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall, this);

QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
                 this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));

7、QDBusArgument

QDBusArgument类用于整理和分发D-Bus参数。QDBusArgument用于通过D-Bus发送参数到远程应用,并接收返回。
QDBusArgument是QtDBus类型系统的核心类,QtDBus类型系统用于解析和原生类型。复合类型可以通过在数组、词典或结构中使用一个或多个原生类型创建。
下列代码展示了使用QtDBus类型系统构造的包含一个整数和字符串的结构。

struct MyStructure
 {
     int count;
     QString name;
 };
 Q_DECLARE_METATYPE(MyStructure)
// Marshall the MyStructure data into a D-Bus argument
QDBusArgument &operator<<(QDBusArgument &argument, const MyStructure &mystruct)
{
    argument.beginStructure();
    argument << mystruct.count << mystruct.name;
    argument.endStructure();
    return argument;
}

// Retrieve the MyStructure data from the D-Bus argument
const QDBusArgument &operator>>(const QDBusArgument &argument, MyStructure &mystruct)
{
    argument.beginStructure();
    argument >> mystruct.count >> mystruct.name;
    argument.endStructure();
    return argument;
}

在QDBusArgument使用这个结构前,必须使用qDBusRegisterMetaType()函数进行注册。因此,在程序中应该则增加如下代码:
qDBusRegisterMetaType<MyStructure>();
一旦注册,类型可以在呼出方法调用QDBusAbstractInterface::call()、来自注册对象的信号发射或来自远程应用的传入调用。

8、QDBusConnectionInterface

QDBusConnectionInterface类提供了对D-Bus总线服务的访问。
D-Bus总线服务端中提供了一个特殊的接口org.freedesktop.DBus,允许客户端运行访问总线的某些属性,例如当前连接的客户端列表,QDBusConnectionInterface类提供对org.freedesktop.DBus接口的访问。
本类中最常用的是使用registerService()和unregisterService()在总线上注册和注销服务名。
QDBusConnectionInterface类定义四个信号,在总线上有服务状态变化时发送。

void callWithCallbackFailed(const QDBusError & error, const QDBusMessage & call)
void serviceOwnerChanged(const QString & name, const QString & oldOwner, const QString & newOwner)
void serviceRegistered(const QString & serviceName)
void serviceUnregistered(const QString & serviceName)

9、QDBusVariant

QDBusVariant类使程序员能够识别由D-Bus类型系统提供的Variant类型。一个使用整数、D-Bus变体类型和字符串作为参数的D-Bus函数可以使用如下的参数列表调用。

QList<QVariant> arguments;
arguments << QVariant(42) << QVariant::fromValue(QDBusVariant(43)) << QVariant("hello");
myDBusMessage.setArguments(arguments);

当D-Bus函数返回一个D-Bus变体类型时,可以使用如下方法获取:

// call a D-Bus function that returns a D-Bus variant
QVariant v = callMyDBusFunction();
// retrieve the D-Bus variant
QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(v);
// retrieve the actual value stored in the D-Bus variant
QVariant result = dbusVariant.variant();

QDBusVariant中的QVariant需要区分一个正常的D-Bus值和一个QDBusVariant中的值。

四、QtDBus工具

1、qdbusviewer

qdbusviewer用于查看D-Bus总线上的服务、对象、接口以及接口的method。使用方法直接在命令行执行:qdbusviewer

 

2、qdbuscpp2xml

qdbuscpp2xml会解析QObject派生类的C++头文件或是源文件,生成D-Bus的内省xml文件。qdbuscpp2xml 会区分函数的输入输出,如果参数声明为const则会是输入,否则可能会被当作输出。
qdbuscpp2xml使用语法如下:
qdbuscpp2xml [options...] [files...]
Options参数如下:
-p|-s|-m:只解析脚本化的属性、信号、方法(槽函数)
-P|-S|-M:解析所有的属性、信号、方法(槽函数)
-a:输出所有的脚本化内容,等价于-psm
-A:输出所有的内容,等价于-PSM
-o filename:输出内容到filename文件
解析所有的方法输出到spark.test.xml文件命令如下:
qdbuscpp2xml -M test.h -o spark.test.xml

<!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="com.scorpio.test.value">
    <method name="maxValue">
      <arg type="i" direction="out"/>
    </method>
    <method name="minValue">
      <arg type="i" direction="out"/>
    </method>
    <method name="value">
      <arg type="i" direction="out"/>
    </method>
    <method name="setValue">
      <arg name="value" type="i" direction="in"/>
    </method>
  </interface>
</node>

3、qdbusxml2cpp

qdbusxml2cpp根据输入文件中定义的接口,生成C++实现代码。
qdbusxml2cpp可以辅助自动生成继承于QDBusAbstractAdaptor和QDBusAbstractInterface两个类的实现代码,用于进程通信服务端和客户端,简化了开发者的代码设计。
qdbusxml2cpp使用语法如下:
qdbusxml2cpp [options...] [xml-or-xml-file] [interfaces...]
Options参数如下:
-a filename:输出Adaptor代码到filename
-c classname:使用classname作为生成类的类名
-i filename:增加#include到输出
-l classname:当生成Adaptor代码时,使用classname作为父类
-m:在cpp文件中包含 #include "filename.moc"语句
-N:不使用名称空间
-p filename:生成Proxy代码到filename文件
解析spark.test.xml文件,生成Adaptor类ValueAdaptor,文件名称为valueAdaptor.h、valueAdaptor.cpp命令行如下:
qdbusxml2cpp spark.test.xml -i test.h -a valueAdaptor
解析spark.test.xml文件,生成Proxy类ComScorpioTestValueInterface,文件名称为testInterface.h、testInterface.cpp命令行如下:
qdbusxml2cpp spark.test.xml -p testInterface

五、QtDBus编程

分为两个部分,DBus服务和访问DBus服务。

1、创建服务并注册对象

创建DBus服务的大致流程:


test.h文件:

#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QtDBus>

class test: public QObject
{
    Q_OBJECT
// 这里定义的是DBus连接的接口,client需要这个"spark.test.interface"接口对DBus服务进行访问。
    Q_CLASSINFO("D-Bus Interface", "spark.test.interface")
public:
    test(int value);

public slots:
    void set_value(int value);
    int get_value();
private:
    int m_value;
};

#endif // TEST_H

test.cpp文件:

#include "test.h"

test::test(int value)
{
    m_value = value;
}

void test::set_value(int value)
{
    m_value = value;
}

int test::get_value()
{
    return m_value;
}

main.cpp文件:

#include <QCoreApplication>
#include <QDBusConnection>
#include <QDebug>
#include <QDBusError>
#include "test.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 建立到session bus的连接
    QDBusConnection connection = QDBusConnection::sessionBus();
    // 在session bus上注册名为spark.test的服务
    // spark.test是服务的名字,注意和test.h中的接口名字spark.test.interface区别
    if(!connection.registerService("spark.test"))
    {
        qDebug() << "error:" << connection.lastError().message();
        exit(-1);
    }
    test test_object(60);
    // 注册名为/test/test_objects的对象,把类Object所有槽函数导出为object的method
    connection.registerObject("/test/test_objects", &test_object, QDBusConnection::ExportAllSlots);
    
    return a.exec();
}

启动程序后,在命令行打开qdbusviewer,查看session bus。


双击Method方法会调用该方法。这里接口类设置为只设置了两个方法,set_value和get_value,可以通过双击调用,设置和获取test类中的m_value属性值。

2、通过QDBusMessage访问Service

本节使用QDBusMessage来访问服务,调用服务的Method方法。

确保spark.test服务运行在总线上,可用qdbusviewer查看。(注释:可以在DBus服务的工程目录下make一个服务的可执行文件,用终端去执行,就可以随时取消掉。分两个步骤:1.qmake-qt5生成Makefile:qmake-qt5 -o Makefile ***.pro;2.直接make即可生成可执行文件。)
现在,继续创建一个Qt Widgets Application工程,使用消息访问spark.test服务。
其中main.cpp文件如下:

#include "mainwindow.h"
#include <QtGui>
#include <QApplication>
#include <QDesktopWidget>
#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QMessageBox>
#include <iostream>
#include <unistd.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    MainWindow w;
    w.show();
    // 让MainWindow窗口显示在屏幕中央
    w.move((QApplication::desktop()->width() - w.width())/2, (QApplication::desktop()->height() - w.height())/2);
    
    // 构造一个method_call消息,服务名称为:spark.test,对象路径为:/test/test_objects
    // 接口名称为spark.test.interface,method名称为get_value。注意这里信息不能填错,如果接口名或Method名不正确就无法正常通信和调用。
    QDBusMessage message = QDBusMessage::createMethodCall("spark.test",
                           "/test/test_objects",
                           "spark.test.interface",
                           "get_value");
    //发送消息
    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    //判断method是否被正确返回
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        //从返回参数获取返回值
    	int value = response.arguments().takeFirst().toInt();
        QMessageBox::warning(NULL, "message", QObject::tr("value = %1").arg(value));
    }
    else
    {
    	QMessageBox::warning(NULL, "error", QObject::tr("value method called failed!"));
    }

    return a.exec();
}

运行结果:

3、通过QDBusInterface 访问Service

继续创建一个Qt Widgets Application工程,使用接口访问spark.test服务。

#include "mainwindow.h"
#include <QtGui>
#include <QApplication>
#include <QDesktopWidget>
#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QMessageBox>
#include <QDBusReply>
#include <iostream>
#include <unistd.h>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 创建QDBusInterface接口
    QDBusInterface interface("spark.test", 									             "/test/test_objects",
                             "spark.test.interface",
                             QDBusConnection::sessionBus());
    if (!interface.isValid())
    {
        QString mes = QDBusConnection::sessionBus().lastError().message();
        QMessageBox::warning(NULL, "message", QObject::tr("lastError = %1").arg(mes));
        exit(1);
    }
    
    // 调用远程的get_value方法。
    // Todo: set_value带参数方法测试无效,需进一步研究
    QDBusReply<int> reply = interface.call("get_value");
    if (reply.isValid())
    {
        int value = reply.value();
        QMessageBox::warning(NULL, "message", QObject::tr("value = %1").arg(value));
    }
    else
    {
        QMessageBox::warning(NULL, "message", QObject::tr("value method called failed!"));
    }

    return a.exec();
}

代码运行结果同上一小节。
目前上面两种访问DBus的方法,使用带参数的set_value方法均无效,需要进一步研究如何使用。

4、从D-Bus XML自动生成Proxy类

Proxy Object提供了一种更加直观的方式来访问Service,如同调用本地对象的方法一样。
生成Proxy类的流程如下:
A、使用工具qdbuscpp2xml从object.h生成XML文件;
qdbuscpp2xml -M test.h -o spark.test.xml

<!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="com.scorpio.test.value">
    <method name="maxValue">
      <arg type="i" direction="out"/>
    </method>
    <method name="minValue">
      <arg type="i" direction="out"/>
    </method>
    <method name="value">
      <arg type="i" direction="out"/>
    </method>
  </interface>
</node>

B、使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类
qdbusxml2cpp spark.test.xml -p valueInterface
生成两个文件:valueInterface.cpp和valueInterface.h
valueInterface.h文件:

/*
* This file was generated by qdbusxml2cpp version 0.7
* Command line was: qdbusxml2cpp com.scorpio.test.xml -p testInterface
*
* qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef TESTINTERFACE_H_1526737677
#define TESTINTERFACE_H_1526737677
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
/*
* Proxy class for interface com.scorpio.test.value
*/
class ComScorpioTestValueInterface:
public QDBusAbstractInterface
{
Q_OBJECTpublic:
    static inline const char *staticInterfaceName()
    {
        return "com.scorpio.test.value";
    }
public:
    ComScorpioTestValueInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0);
    ~ComScorpioTestValueInterface();
public Q_SLOTS: // METHODS
    inline QDBusPendingReply<int> maxValue()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QLatin1String("maxValue"), argumentList);
    }
    inline QDBusPendingReply<int> minValue()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QLatin1String("minValue"), argumentList);
    }
    inline QDBusPendingReply<int> value()
    {
        QList<QVariant> argumentList;
        return asyncCallWithArgumentList(QLatin1String("value"), argumentList);
    }
Q_SIGNALS: // SIGNALS

};

namespace com
{
    namespace scorpio
    {
        namespace test
        {
            typedef ::ComScorpioTestValueInterface value;
        }
    }
}
#endif

valueInterface.cpp文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -p testInterface
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * This file may have been hand-edited. Look for HAND-EDIT comments
 * before re-generating it.
 */

#include "testInterface.h"

/*
 * Implementation of interface class ComScorpioTestValueInterface
 */

ComScorpioTestValueInterface::ComScorpioTestValueInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
    : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}

ComScorpioTestValueInterface::~ComScorpioTestValueInterface()
{
}

调用Proxy类访问Service如下:

#include <QCoreApplication>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusReply>
#include <QDBusInterface>
#include <QDebug>
#include "testInterface.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    // 初始化自动生成的Proxy类com::scorpio::test::value
    com::scorpio::test::value test("com.scorpio.test",
                                   "/test/test_objects",
                                   QDBusConnection::sessionBus());
    // 调用value方法
    QDBusPendingReply<int> reply = test.value();
    //qdbusxml2cpp生成的Proxy类是采用异步的方式来传递Message,
    //所以需要调用waitForFinished来等到Message执行完成
    reply.waitForFinished();
    if (reply.isValid())
    {
        int value = reply.value();
        qDebug() << QString("value =  %1").arg(value);
    }
    else
    {
        qDebug() << "value method called failed!";
    }

    return a.exec();
}

5、使用Adapter注册Object

可以直接把test类注册为消息总线上的一个Object,但QT4不推荐。QT4推荐使用Adapter来注册Object。
大多数情况下,可能只需要把自定义的类里的方法有选择的发布到消息总线上,使用Adapter可以很方便的实现选择性发布。
生成Adapter类的流程如下:
A、使用工具 qdbuscpp2xml从test.h生成XML文件
qdbuscpp2xml -M test.h -o spark.test.xml
B、编辑spark.test.xml,选择需要发布的method,不需要发布的删除。
C、使用工具qdbusxml2cpp从XML文件生成继承自QDBusInterface的类
qdbusxml2cpp spark.test.xml -i test.h -a valueAdaptor
生成两个文件:valueAdaptor.cpp和valueAdaptor.h
valueAdaptor.h文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -i test.h -a valueAdaptor
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * This file may have been hand-edited. Look for HAND-EDIT comments
 * before re-generating it.
 */

#ifndef VALUEADAPTOR_H_1526742670
#define VALUEADAPTOR_H_1526742670

#include <QtCore/QObject>
#include <QtDBus/QtDBus>
#include "test.h"
class QByteArray;
template<class T> class QList;
template<class Key, class Value> class QMap;
class QString;
class QStringList;
class QVariant;

/*
 * Adaptor class for interface com.scorpio.test.value
 */
class ValueAdaptor: public QDBusAbstractAdaptor
{
    Q_OBJECT
    Q_CLASSINFO("D-Bus Interface", "com.scorpio.test.value")
    Q_CLASSINFO("D-Bus Introspection", ""
"  <interface name=\"com.scorpio.test.value\">\n"
"    <method name=\"maxValue\">\n"
"      <arg direction=\"out\" type=\"i\"/>\n"
"    </method>\n"
"    <method name=\"minValue\">\n"
"      <arg direction=\"out\" type=\"i\"/>\n"
"    </method>\n"
"  </interface>\n"
        "")
public:
    ValueAdaptor(QObject *parent);
    virtual ~ValueAdaptor();

public: // PROPERTIES
public Q_SLOTS: // METHODS
    int maxValue();
    int minValue();
Q_SIGNALS: // SIGNALS
};

#endif

valueAdaptor.cpp文件:

/*
 * This file was generated by qdbusxml2cpp version 0.7
 * Command line was: qdbusxml2cpp com.scorpio.test.xml -i test.h -a valueAdaptor
 *
 * qdbusxml2cpp is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
 *
 * This is an auto-generated file.
 * Do not edit! All changes made to it will be lost.
 */

#include "valueAdaptor.h"
#include <QtCore/QMetaObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>

/*
 * Implementation of adaptor class ValueAdaptor
 */

ValueAdaptor::ValueAdaptor(QObject *parent)
    : QDBusAbstractAdaptor(parent)
{
    // constructor
    setAutoRelaySignals(true);
}

ValueAdaptor::~ValueAdaptor()
{
    // destructor
}

int ValueAdaptor::maxValue()
{
    // handle method call com.scorpio.test.value.maxValue
    int out0;
    QMetaObject::invokeMethod(parent(), "maxValue", Q_RETURN_ARG(int, out0));
    return out0;
}

int ValueAdaptor::minValue()
{
    // handle method call com.scorpio.test.value.minValue
    int out0;
    QMetaObject::invokeMethod(parent(), "minValue", Q_RETURN_ARG(int, out0));
    return out0;
}

调用Adaptor类注册Object对象如下:

#include <QCoreApplication>
#include <QDBusConnection>
#include <QDebug>
#include <QDBusError>
#include "test.h"
#include "valueAdaptor.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QDBusConnection connection = QDBusConnection::sessionBus();
    test object(60);
    //ValueAdaptor是qdbusxml2cpp生成的Adaptor类
    ValueAdaptor valueAdaptor(&object);
    if (!connection.registerService("com.scorpio.test"))
    {
        qDebug() << connection.lastError().message();
        exit(1);
    }
    connection.registerObject("/test/test_objects", &object);
    return a.exec();
}

使用qdbusviewer查看发布的method。

6、自动启动Service

D-Bus系统提供了一种机制可以在访问某个service时,自动把应用程序运行起来。
需要在/usr/share/dbus-1/services下面建立spark.test.service文件,文件的内容如下:

[D-BUS Service]
Name=com.scorpio.test
Exec=/path/to/scorpio/test

在访问test的method前,不必手动运行应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/445519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python_Opencv图像处理框架】图像阈值与滤波

写在前面 本篇文章是opencv学习的第二篇文章&#xff0c;主要讲解了图像的阈值和滤波操作&#xff0c;作为初学者&#xff0c;我尽己所能&#xff0c;但仍会存在疏漏的地方&#xff0c;希望各位看官不吝指正❤️ 写在中间 一、 图像阈值 &#xff08; 1 &#xff09;简单介绍…

扩散模型原理记录

1 扩散模型原理记录 参考资料&#xff1a; [1]【54、Probabilistic Diffusion Model概率扩散模型理论与完整PyTorch代码详细解读】 https://www.bilibili.com/video/BV1b541197HX/?share_sourcecopy_web&vd_source7771b17ae75bc5131361e81a50a0c871 [2] https://t.bili…

音视频通讯QoS技术及其演进

利用多种算法和策略进行网络传输控制&#xff0c;最大限度满足弱网场景下的音视频用户体验。 良逸&#xff5c;技术作者 01 什么是QoS&#xff1f;音视频通讯QoS是哪一类&#xff1f; QoS&#xff08;Quality of Service&#xff09;是服务质量的缩写&#xff0c;指一个网络能够…

MoE 系列(二)|Golang 扩展从 Envoy 接收配置

文&#xff5c;朱德江&#xff08;GitHub ID&#xff1a;doujiang24) MOSN 项目核心开发者蚂蚁集团技术专家 专注于云原生网关研发的相关工作 本文 1445 字 阅读 5 分钟 上一篇我们用一个简单的示例&#xff0c;体验了用 Golang 扩展 Envoy 的极速上手。 这次我们再通过一个…

这篇把「精准测试」算是讲明白了

作为测试同学&#xff0c;我们经常在工作中会有这样的困惑&#xff1a;我写的用例真的有效且全面吗&#xff0c;我的测试真的做到有效覆盖了吗&#xff1f;回归阶段我到底需要回归什么&#xff0c;回归验证充分吗&#xff1f;这次的改动到底影响范围有多大&#xff1f;针对以上…

JAVA集成强密码校验

JAVA集成强密码校验 1 : 背景2 : 代码设计编写2.1 : 引入规则配置2.2 : 密码校验工具类 3 : 验证4 : 相关链接 1 : 背景 最近系统需要做用户密码升级&#xff0c;增加强密码校验&#xff0c;密码长度&#xff0c;复杂度等等&#xff0c;所以整理了一份通用的密码复杂度控制代码…

你了解这2类神经性皮炎吗?常常预示着这5类疾病!

属于慢性皮肤病&#xff0c;患者皮肤可出现局限性苔藓样变&#xff0c;同时伴有阵发性瘙痒。神经性皮炎易发生在颈部两侧和四肢伸侧&#xff0c;中年人是高发人群。到目前为止神经性皮炎病因还并不是很明确&#xff0c;不过一部分病人发病前常常出现精神神经方面异常&#xff0…

SLAM 十四讲(第一版)各章方法总结与理解

SLAM 十四讲&#xff08;第一版&#xff09;各章方法总结与理解 总结十四讲中各章各步骤提到的各种方法&#xff0c;以及具体方法在哪个 c 库中可以调用。目的在于能更直观地了解 slam 过程各步骤到底在做什么&#xff0c;以及是怎么联系在一起的。 2. 初识 SLAM SLAM&#x…

ggplot作图中的图例处理方法

文章目录 改变坐标轴和图例的名称方法1, labs()方法2&#xff0c;scale_xxx_discrete/continuous() 删除坐标轴和图例的名称方法1&#xff0c; labs()方法2&#xff0c;scale_xxx_discrete/continuous()方法3&#xff0c;theme()方法4&#xff0c;guides()可以去图例名称 改变图…

怎么挣点零花钱,哪里可以赚点零花钱?以下这些方式值得参考一下

想赚零花钱的人群包括但不限于&#xff1a;大学生、宝妈/宝爸、自由职业者、比较有闲暇时间的上班族。 他们想要赚零花钱的原因不尽相同&#xff0c;但主要就是这几点&#xff1a;经济需求、个人发展、好奇心和乐趣等等。想赚取零花钱的人具有实际需求和个人发展的目标&#xf…

【hello C++】模板初阶

目录 1. 泛型编程 2. 函数模板 2.1 函数模板的概念 2.2 函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5 模板参数的匹配原则 3. 类模板 3.1 类模板的定义格式 3.2 类模板的实例化 4. STL简介 4.1 什么是STL 4.2 STL的版本 4.3 STL的六大组件 4.4 STL的重要性 4.5 …

基于.Net开发的ChatGPT客户端,兼容Windows、IOS、安卓、MacOS、Linux

2023年目前要说最热的点,肯定是ChatGPT了。 ChatGPT官方提供的网页版本,还有需要科学上网,很多人都会基于此进行封装。 现在是移动互联网时代,基于手机APP的需求还是很大的。 所以,今天给大家推荐一个ChatGPT客户端开源项目,兼容苹果和安卓手机、PC。 项目简介 这是…

若依管理系统修改页面标题和logo

一&#xff1a;修改网页上的logo 把public目录下favicon.ico&#xff0c;换成自己logo 注&#xff1a;替换图片的名字最好还是以favicon.ico命名&#xff0c;如果改变,就要改public目录下的index.html代码 二&#xff1a;修改页面上的logo 把src/assets/logo/logo.png换成自己l…

【Chano的SFM教程】3dmax 面部表情.VTA基本制作教程

本篇教程作者为&#xff1a;小鸟Chano&#xff0c;转载请表明作者和出处&#xff1a;CSDN 欢迎观看本次教程 本教程将会为你演示使用3D MAX 制作一个基本的SFM表情控制器【表情滑条】并导入SFM进行使用。 Chano自己也是近期才掌握的这项知识&#xff0c;所以过程中可能有很多…

GDB调试实验

一、实验准备 在 Linux 环境软件开发中&#xff0c;GDB 是调试 C 和 C 程序的主要工具。本次实验围绕着GDB常用的调试操作进行。 1、设置断点的意义 当我们想查看变量内容&#xff0c;堆栈情况等等&#xff0c;可以指定断点。程序执行到断点处会暂停执行。break 命令用来设置…

React 条件渲染组件

组件通常需要根据不同的条件显示不同的内容&#xff0c;以及根据应用的状态变化只渲染其中的一部分。 在 React 中&#xff0c;可以使用 JavaScript 语法有条件地呈现 JSX&#xff0c;比如 if 语句、&&和 ?: 操作符。 根据条件返回 JSX Demo.js 文件&#xff1a; …

【高危】vm2 <3.9.17 沙箱逃逸漏洞(POC)(CVE-2023-30547 )

漏洞描述 vm2 是一个基于 Node.js 的沙箱环境&#xff0c;可以使用列入白名单的 Node 内置模块运行不受信任的代码。 由于 CVE-2023-29199 的修复不完整&#xff0c;vm2 3.9.17 之前版本的 transformer.js 文件中的 transformer 函数异常处理逻辑存在缺陷。攻击者可以利用这个…

【01-Java Web先导课】-如何进行JDK的安装(或Java环境的配置)

文章目录 一、JDK&#xff08;jdk-8u371-windows-x64.exe&#xff09;的下载1、下载网址2、选择相应版本进行下载 二、JDK&#xff08;jdk-8u371-windows-x64.exe&#xff09;的安装1、JDK安装2、系统环境变量配置3、classspath环境变量设置 免责说明 一、JDK&#xff08;jdk-8…

❤echarts 南丁格尔玫瑰图的使用以及南丁格尔玫瑰图详细配置

❤echarts 南丁格尔玫瑰图的使用以及南丁格尔玫瑰图详细配置 1、认识 使用可以参考之前文章&#xff0c;会使用直接跳过1 引入官网的南丁格尔玫瑰图效果如下&#xff1a; 使用函数配置分为三个部分&#xff1a;初始化> 设置配置> 地图使用参数 配置代码如下 option…

法学考生必看—外经贸法学专业在职研究生

法学专业就业面比较广&#xff0c;但很多人工作后都觉得还是缺少核心竞争力&#xff0c;想通过读研来改变现状&#xff0c;23考研已经落幕&#xff0c;想要今年就能入班学习的院校有吗&#xff1f;有法学专业的吗&#xff1f; 一、学校介绍 对外经济贸易大学创建于1951年&…