通过 dbus 共享对象

Posted

技术标签:

【中文标题】通过 dbus 共享对象【英文标题】:Sharing objects over dbus 【发布时间】:2015-11-14 13:33:02 【问题描述】:

我的项目来源于这个例子:http://doc.qt.io/qt-5/qtdbus-remotecontrolledshower-example.html

有两个进程,淋浴器和控制器,控制器可以向淋浴器发送简单的消息(我只是将那个项目中的汽车重命名为淋浴器)并将花哨的汽车 GUI 更改为一个简单的 Widget。我这样做没有任何问题。 我的问题是当我尝试使用自定义类发送消息时

#ifndef MESSAGE_H
#define MESSAGE_H

#include <QtDBus>

class message

public:
    QString articleName;
    QString categoryName;

    message() : articleName(""), categoryName("") 
    message( QString a, QString b ) : articleName(a), categoryName(b) 
    message(const message &other) : articleName( other.articleName ), categoryName( other.categoryName ) 
    message& operator=(const message &other)
    
       articleName = other.articleName;
       categoryName = other.categoryName;
       return *this;
    
    //register Message with the Qt type system
    static void registerMetaType()
    
        qRegisterMetaType<message>("message");

        qDBusRegisterMetaType<message>();
    

    friend QDBusArgument &operator<<(QDBusArgument &argument, const message &mess )
    
        argument.beginStructure();
        argument << mess.articleName;
        argument << mess.categoryName;
        argument.endStructure();
        return argument;
    

    friend const QDBusArgument &operator>>(const QDBusArgument &argument, message &mess )
    
        argument.beginStructure();
        argument >> mess.articleName;
        argument >> mess.categoryName;
        argument.endStructure();

        return argument;
    
;


Q_DECLARE_METATYPE( message )

#endif // MESSAGE_H

我在接收消息对象的淋浴类中添加了一个方法

#ifndef shower_H
#define shower_H

#include "ui_Categories.h"
#include "message.h"

class shower : public QWidget

    Q_OBJECT

public:
    shower(QWidget *parent = 0);
    //shower();
    //QRectF boundingRect() const;

public Q_SLOTS:
    void accelerate();
    void decelerate();
    void turnLeft();
    void turnRight();
    void doThat();
    void addMessage( const message &msg );
    QString Get( int param );

Q_SIGNALS:
    void crashed();

protected:
    void timerEvent(QTimerEvent *event);
private:
    Ui::Categories ui;
    qreal wheelsAngle; // used when applying rotation
    qreal speed; // delta movement along the body axis
;

#endif // shower_H

这是我定义淋浴界面的xml

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
    "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node name="/com/trollech/examples/shower">
    <interface name="org.example.Examples.showerInterface">
        <method name="accelerate"/>
        <method name="decelerate"/>
        <method name="turnLeft"/>
        <method name="turnRight"/>
        <method name="addMessage">
            <arg name="param" type="a(ii)" direction="in"/>
            <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="message"/>
        </method>
        <signal name="crashed"/>
    </interface>
</node>

还有专业文件

QT += dbus widgets

DBUS_ADAPTORS += shower.xml
HEADERS += shower.h \
    message.h
SOURCES += shower.cpp main.cpp

# install
target.path = $$[QT_INSTALL_EXAMPLES]/dbus/wikidbusqt/shower
INSTALLS += target

FORMS += \
    Categories.ui

OTHER_FILES += \
    shower.xml

我无法编译,我得到了这个错误日志

20:45:21: Running steps for project wikidbusqt...
20:45:21: Starting: "/usr/lib/x86_64-linux-gnu/qt5/bin/qmake" /home/hector/workspace/wikidbusqt/shower/shower.pro -r -spec linux-g++-64
20:45:21: The process "/usr/lib/x86_64-linux-gnu/qt5/bin/qmake" exited normally.
20:45:21: Starting: "/usr/bin/make" 
/usr/lib/x86_64-linux-gnu/qt5/bin/uic ../../wikidbusqt/shower/Categories.ui -o ui_Categories.h
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -fPIE -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_DBUS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++-64 -I../../wikidbusqt/shower -I/usr/include/qt5 -I/usr/include/qt5/QtWidgets -I/usr/include/qt5/QtDBus -I/usr/include/qt5/QtGui -I/usr/include/qt5/QtCore -I. -I. -I. -o shower.o ../../wikidbusqt/shower/shower.cpp
In file included from /usr/include/qt5/QtCore/qvariant.h:48:0,
                 from /usr/include/qt5/QtCore/QVariant:1,
                 from ./ui_Categories.h:12,
                 from ../../wikidbusqt/shower/shower.h:46,
                 from ../../wikidbusqt/shower/shower.cpp:42:
/usr/include/qt5/QtCore/qmetatype.h:1708:12: error: specialization of 'QMetaTypeId<message>' after instantiation
     struct QMetaTypeId< TYPE >                                          \
            ^
../../wikidbusqt/shower/message.h:53:1: note: in expansion of macro 'Q_DECLARE_METATYPE'
 Q_DECLARE_METATYPE( message )
 ^
/usr/include/qt5/QtCore/qmetatype.h:1708:12: error: redefinition of 'struct QMetaTypeId<message>'
     struct QMetaTypeId< TYPE >                                          \
            ^
../../wikidbusqt/shower/message.h:53:1: note: in expansion of macro 'Q_DECLARE_METATYPE'
 Q_DECLARE_METATYPE( message )
 ^
/usr/include/qt5/QtCore/qmetatype.h:1491:8: error: previous definition of 'struct QMetaTypeId<message>'
 struct QMetaTypeId : public QMetaTypeIdQObject<T>
        ^
In file included from /usr/include/qt5/QtCore/qatomic.h:42:0,
                 from /usr/include/qt5/QtCore/qvariant.h:45,
                 from /usr/include/qt5/QtCore/QVariant:1,
                 from ./ui_Categories.h:12,
                 from ../../wikidbusqt/shower/shower.h:46,
                 from ../../wikidbusqt/shower/shower.cpp:42:
/usr/include/qt5/QtCore/qmetatype.h: In instantiation of 'int qMetaTypeId() [with T = message]':
/usr/include/qt5/QtDBus/qdbusmetatype.h:85:29:   required from 'int qDBusRegisterMetaType(T*) [with T = message]'
../../wikidbusqt/shower/message.h:28:40:   required from here
/usr/include/qt5/QtCore/qglobal.h:679:85: error: invalid application of 'sizeof' to incomplete type 'QStaticAssertFailure<false>'
     enum Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __COUNTER__) = sizeof(QStaticAssertFailure<!!(Condition)>)
                                                                                     ^
/usr/include/qt5/QtCore/qglobal.h:684:47: note: in expansion of macro 'Q_STATIC_ASSERT'
 #define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
                                               ^
/usr/include/qt5/QtCore/qmetatype.h:1638:5: note: in expansion of macro 'Q_STATIC_ASSERT_X'
     Q_STATIC_ASSERT_X(QMetaTypeId2<T>::Defined, "Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system");
     ^
make: *** [shower.o] Error 1
20:45:24: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project wikidbusqt (kit: Desktop)
When executing step 'Make'
20:45:24: Elapsed time: 00:03.

我不知道发生了什么,我按照本教程中概述的步骤操作:https://techbase.kde.org/Development/Tutorials/D-Bus/CustomTypes#DBusChat.pro,但我不知道我忽略了什么。

【问题讨论】:

【参考方案1】:

您只能在Q_DECLARE_METATYPE 在范围内之后调用qRegisterMetaType 和类似方法。因此,您必须将registerMetaType() 的主体移出类,放入.cpp 文件中:

message.h(相关片段)

...
class message

  ...
  /// Register message with the Qt type system.
  static void registerMetaType();
  ...
;
Q_DECLARE_METATYPE( message )
...

message.cpp(整个文件)

#include "message.h"

void message::registerMetaType()

  qRegisterMetaType<message>("message");
  qDBusRegisterMetaType<message>();

您不能将registerMetaType 的类外定义放入头文件,因为它会破坏单一定义规则并且链接器会抱怨多重定义的符号。

【讨论】:

谢谢!现在看来,我的 IDE 正在做一些奇怪的事情:它生成了一个 Makefile,它不会将 message.h 添加到 qdbusxml2cpp 调用中。在使用 qmake 生成的 makefile 中,我得到 shower_adaptor.h: ../../wikidbusqt/shower/shower.xml /usr/lib/x86_64-linux-gnu/qt5/bin/qdbusxml2cpp -a shower_adaptor.h: ../../wikidbusqt/shower/shower.xml 并且无法编译当它应该是 shower_adaptor.h: ../../wikidbusqt/shower/shower.xml /usr/lib/x86_64-linux-gnu/qt5/bin/qdbusxml2cpp -i message.h -a shower_adaptor.h: ../../wikidbusqt/shower/shower.xml 这编译时

以上是关于通过 dbus 共享对象的主要内容,如果未能解决你的问题,请参考以下文章

声明在 DBus 上订阅了哪些信号?

如何通过 dbus-send 发送方法调用?

如何通过 dbus 调用 varargs 函数?

通过 python 和 dbus 启动用户 systemd 服务

通过python监控dbus消息

QtDBUS:通过 DBUS 发送枚举