QVariant + QDataStream + qRegisterMetaType

  • I have a problem with a class that exchanges data using TCP/IP socket. That class receives a list of variants (wrapping various data) and converts those variants into a binary stream using QDataStream <<. On the other end another Qt application receives the binary stream and reads the variants from it using QDataStream >>.

    This worked very well... until today. I just tried to transfer a custom datatype. I declared it as a metatype using Q_DECLARE_METATYPE, registered it using qRegisterMetaType(), wrote two data stream operators and registered them using qRegisterMetaTypeStreamOperators. Everything looked fine.

    However the actual transfer failed because server and client application registered the custom type to different IDs. This means IDs have different meaning for sender and receiver which make the communication fail.

    I wonder how this can be solved. With some effort maybe I could write special work-around routines that detect the type of the QVariant and use special handling for user types (e.g. using fix IDs or using type name). But this is nasty and it is hard to believe there is no solution in Qt.

    Is there any way to reserve type IDs or to register types with predefined IDs?
    Any other clean solution?

  • Uh... You relied upon QVariant for serialization. Nope. You can't do that. Although it does bring on lot of free stuff on table, but you can only rely upon QDataStream. You need to hand craft your code in stream. Stream type before as string or number then class itself. While deserializing, do the reverse. Ugly switch cases, but no other way.
    May be you will find this thread useful."streaming custom qvariant":http://www.qtcentre.org/threads/21195-Streaming-custom-QVariant

  • Thank for your answer and the link.

    Oh my... this is a little disappointing. I would have expected Qt providing a solution for this.

  • However, silicomancer, I had something of a similar problem. Can you tell me whether you are able to stream it and destream it? Don't send it over. Write it to some file. Because I think, if you can, it means it won't rely upon QVariant::UserType() number. Clearly as a user, we cannot determine the order in which it gets created. The QVariant::type() is always the same. And I think you can write a custom type in QSettings. So if QSettings can recreate the QVariant without relying upon QVariant::UserType(), God knows how, then it should in principle, be sent over to other machine too.
    I tried going through the qt code to dig it out. Basically how the stream function once defined works, and how QSettings is able to push and pull to a file a custom type. But couldn't get it.

  • I tested the code for the dependecy of the type ID: I built one application using the original order of registration calls (the type IDs are incremented in the order of registration) and then I changed to order or registration calls and build the other application. They couldn't communicate and called wrong stream operators.

    So its definitely a matter of different type IDs.

    I have no idea how QSettings is related to this since I never used QVariant for that but special settings-template-classes.

  • Very, very strange. Sometimes I am really tempted to believe in paranormal forces.

    I just had a look into the Qt code and found that the Qt classes already handle user types in a separate way (using type name instead of type ID). Starting with that second I was not able to reproduce the problem anymore that I could previously reproduce easily by changing registration order.

    I have no idea what happened. But it looks like Qt already handles user types properly. At least it works now and refuses to fail.

Log in to reply