PDA

View Full Version : how can i pass objects using DBus?



mismael85
11th January 2010, 08:36
hello everybody,
i want to pass objects between processes using DBus i have read the documentation but i did not understand it very well.
i understood that i can not pass objects except struct , arrays, and Qmap .
i must declare the object with the macro Q_DECLARE_METATYPE() ,and implement the operators << >> to serialize QDBusArgument .
how then can i pass the object QDBusArgument between two processes?

mismael85
12th January 2010, 19:18
AnyBody?
plz help

wysota
12th January 2010, 19:38
What did you already try? Do you have an adaptor in one application and an interface to it in the other one? Please post the service object (not the data object) you want to share between applications.

mismael85
13th January 2010, 11:40
the data and service object are


class City{
int cityId;
QString cityName;
double latitude;
double longtude;
};
class ClientServiceProvider : public QObject
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.mycompany.ptimes")
public:
ClientServiceProvider(QObject *parent = 0);
public slots:
QString getSettingsValue(QString );
void setSettingsValue(QString);
City getCountries();
signals:

private:
void loadSettings();


private:
DBManager* m_pDBMan;
QHash<QString,Settings*> m_settingsHash;
};


i want to return the city object from the function getCountries().
i have already interface and adaptor and i am already using dbus to pass QString and QStringList.
but the problem is to pass custom objects
is it possible to pass custom objects and how?
if not , is there any other solution to do some thing like this?

wysota
13th January 2010, 12:20
Well, you need to implement streaming operators (for QDataStream) for the object and declare a metatype for the class.

Something like:

struct City {
int id;
QString name;
double lat;
double lon;
};

Q_DECLARE_METATYPE(City);

QDataStream& operator<<(QDataStream &str, const City &city){
str <<"City"<< id << name << lat << lon;
return str;
}

QDataStream& operator>>(QDataStream &str, City &city){
QString magic;
str >> magic;
if(magic!="City") return str; // error
magic >> city.id >> city.name >> city.lat >> city.lon;
return str;
}

mismael85
13th January 2010, 14:27
thank you ,
but after that how can i transfer the QDataStream between the two process .
should i define the function as follows:

QDataStream getCountries();

instead of
City getCountries();

wysota
13th January 2010, 17:07
No, why? You just need to be able to serialize your structure so that Qt can forward it to dbus.

mismael85
14th January 2010, 15:15
i put the code above in my application as follows

QDBusArgument &operator<<(QDBusArgument &argument, const QList<Country> &countries)
{
argument.beginArray();
for(int i = 0 ; i < countries.count(); i++)
{
argument<<countries.at(i).countryId << countries.at(i).countryName;
}
argument.endArray();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries)
{

return argument;
}

and every thing working fine but when i implement the operator>> i get a compilation error :

country.cpp: In function ‘const QDBusArgument& operator>>(const QDBusArgument&, QList<Country>&)’:
country.cpp:18: error: no match for ‘operator>>’ in ‘argument >> ((QList<Country>*)countries)->QList<T>::at [with T = Country](i)->Country::countryId’
what is the problem?

wysota
14th January 2010, 16:10
Are you sure the signature is correct? Should QDbusArgument be a const reference and not a non-const reference?

mismael85
14th January 2010, 16:43
it is constant and here are the declaration of the tow operators

QDBusArgument &operator<<(QDBusArgument &argument, const QList<Country> &countries);
const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries);
note when i ran the application without writing any code inside operator>> except return statement, the application compiled
but when it call a dbus function the server and the client were crashed.

wysota
14th January 2010, 17:20
Did you remember about qDBusRegisterMetaType?

mismael85
14th January 2010, 17:45
yes i used it in the main. look this my code
country.h

#ifndef MYSTRUCT_H
#define MYSTRUCT_H

#include <QtCore/QList>
#include <QtCore/QMetaType>
#include <QtDBus/QtDBus>

class Country
{
public:
int countryId;
QString countryName;
};
Q_DECLARE_METATYPE(QList<Country>)
inline void registerCommType()
{
qDBusRegisterMetaType< QList<Country> >();
}

QDBusArgument &operator<<(QDBusArgument &argument, const QList<Country> &countries);
const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries);

#endif

country.cpp

#include "country.h"

QDBusArgument &operator<<(QDBusArgument &argument, const QList<Country> &countries)
{
argument.beginArray();
for(int i = 0 ; i < countries.count(); i++)
{
argument<<countries.at(i).countryId << countries.at(i).countryName;
}
argument.endArray();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries)
{
argument.beginArray();
for(int i = 0 ; i < countries.count(); i++)
{
argument>>countries.at(i).countryId >> countries.at(i).countryName;
}
argument.endArray();
return argument;
}

when i compile this code i get the following error

country.cpp: In function ‘const QDBusArgument& operator>>(const QDBusArgument&, QList<Country>&)’:
country.cpp:18: error: no match for ‘operator>>’ in ‘argument >> ((QList<Country>*)countries)->QList<T>::at [with T = Country](i)->Country::countryId’

wysota
14th January 2010, 19:19
The operator's contents seems incorrect to me. What will countries.count() return in the for loop? To me it seems the loop will never be entered so even if the code compiled, it wouldn't work. Also in the first function beginArray() should probably contain the meta-type id as a parameter. Next, QList::at() is not an L-value but a R-value, you can't assign data to it. The code should probably look like this:

const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries) {
argument.beginArray();
countries.clear();
while(!argument.atEnd()){
Country country;
argument >> country.countryId >> country.countryName;
countries.append(country);
}
argument.endArray();
return argument;
}

But I think this won't work either as here QDBusArgument assumes you are going to read arrays and not arrays of structs. So the final code should be:

const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries) {
argument.beginArray();
countries.clear();
while(!argument.atEnd()){
Country country;
argument >> country;
countries.append(country);
}
argument.endArray();
return argument;
}

Of course you have to match operator<< to it.

Next... :) The docs say that you don't have to write this code for QList. So all you need to do is to provide serialization of your Country structure.

mismael85
16th January 2010, 10:34
i used this code but still i get a compilation error
country.h

#ifndef MYSTRUCT_H
#define MYSTRUCT_H

#include <QtCore/QList>
#include <QtCore/QMetaType>
#include <QtDBus/QtDBus>

class Country
{
public:
int countryId;
QString countryName;
};
Q_DECLARE_METATYPE(Country)
inline void registerCommType()
{
qDBusRegisterMetaType< Country >();
}

QDBusArgument &operator<<(QDBusArgument &argument, const Country &aCountry);
const QDBusArgument &operator>>(const QDBusArgument &argument, Country & aCountry);

#endif

country.cpp

#include "country.h"

QDBusArgument &operator<<(QDBusArgument &argument, const Country &aCountry)
{
argument.beginStructure();
argument << aCountry.countryId << aCountry.countryName;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument, Country & aCountry)
{
argument.beginStructure();
argument >> aCountry.countryId >> aCountry.countryName;
argument.endStructure();
return argument;
}

i get the following error

In file included from /usr/include/qt4/QtDBus/qdbusmacros.h:46,
from /usr/include/qt4/QtDBus/qdbusconnection.h:45,
from /usr/include/qt4/QtDBus/QDBusConnection:1,
from main.cpp:4:
/usr/include/qt4/QtCore/qmetatype.h: In static member function ‘static int QMetaTypeId2<T>::qt_metatype_id() [with T = QList<Country>]’:
/usr/include/qt4/QtCore/qmetatype.h:199: instantiated from ‘int qMetaTypeId(T*) [with T = QList<Country>]’
/usr/include/qt4/QtDBus/qdbuspendingreply.h:85: instantiated from ‘int QDBusPendingReplyTypes::metaTypeFor(T1*) [with T1 = QList<Country>]’
/usr/include/qt4/QtDBus/qdbuspendingreply.h:98: instantiated from ‘static void QDBusPendingReplyTypes::ForEach<T1, T2, T3, T4, T5, T6, T7, T8>::fillMetaTypes(int*) [with T1 = QList<Country>, T2 = void, T3 = void, T4 = void, T5 = void, T6 = void, T7 = void, T8 = void]’
/usr/include/qt4/QtDBus/qdbuspendingreply.h:192: instantiated from ‘void QDBusPendingReply<T1, T2, T3, T4, T5, T6, T7, T8>::calculateMetaTypes() [with T1 = QList<Country>, T2 = void, T3 = void, T4 = void, T5 = void, T6 = void, T7 = void, T8 = void]’
/usr/include/qt4/QtDBus/qdbuspendingreply.h:199: instantiated from ‘void QDBusPendingReply<T1, T2, T3, T4, T5, T6, T7, T8>::assign(const QDBusPendingCall&) [with T1 = QList<Country>, T2 = void, T3 = void, T4 = void, T5 = void, T6 = void, T7 = void, T8 = void]’
/usr/include/qt4/QtDBus/qdbuspendingreply.h:141: instantiated from ‘QDBusPendingReply<T1, T2, T3, T4, T5, T6, T7, T8>& QDBusPendingReply<T1, T2, T3, T4, T5, T6, T7, T8>::operator=(const QDBusPendingCall&) [with T1 = QList<Country>, T2 = void, T3 = void, T4 = void, T5 = void, T6 = void, T7 = void, T8 = void]’
/usr/include/qt4/QtDBus/qdbuspendingreply.h:135: instantiated from ‘QDBusPendingReply<T1, T2, T3, T4, T5, T6, T7, T8>::QDBusPendingReply(const QDBusPendingCall&) [with T1 = QList<Country>, T2 = void, T3 = void, T4 = void, T5 = void, T6 = void, T7 = void, T8 = void]’
ptimes_interface_p.h:43: instantiated from here
/usr/include/qt4/QtCore/qmetatype.h:189: error: ‘qt_metatype_id’ is not a member of ‘QMetaTypeId<QList<Country> >’
and here are the function i use in the interface class
Ptimes_interface_p.h

inline QDBusPendingReply<QList<Country> > getCountries()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QLatin1String("getCountries"), argumentList);
}
and here how i used this function


PtimesInterface * iface = new PtimesInterface("com.mycompany.ptimes","/ClientServiceProvider", QDBusConnection::sessionBus(), this);
QList<Country> countries = iface->getCountries();

mismael85
17th January 2010, 08:13
i found a solution for my previous problem with the code

#ifndef MYSTRUCT_H
#define MYSTRUCT_H

#include <QtCore/QList>
#include <QtCore/QMetaType>
#include <QtDBus/QtDBus>

class Country
{
public:
int countryId;
QString countryName;
};
Q_DECLARE_METATYPE(QList<Country>)
Q_DECLARE_METATYPE(Country)
inline void registerCommType()
{
qDBusRegisterMetaType< QList<Country> >();
qDBusRegisterMetaType< Country >();

}

QDBusArgument &operator<<(QDBusArgument &argument, const QList<Country> &countries);
const QDBusArgument &operator>>(const QDBusArgument &argument, QList<Country> &countries);
QDBusArgument &operator<<(QDBusArgument &argument, const Country &countries);
const QDBusArgument &operator>>(const QDBusArgument &argument, Country &countries);

#endif
but i got another problem. the program are compiled but when i use a function calling DBus the program crashes and i got the following message

QDBusArgument: read from a write-only object
process 4668: arguments to dbus_message_unref() were incorrect, assertion "message->generation == _dbus_current_generation" failed in file dbus-message.c line 1392.
This is normally a bug in some application using the D-Bus library.
*** glibc detected *** /home/mismael/workspace/Nokia_N900_PKG_2010/Sources/PrayerTimes/PrayerTimesClient/PrayerTimesClient: double free or corruption (!prev): 0x091f6078 ***