Unsolved COM object and QtVariant casting issue
-
Hello every one,
I'm trying to use a COM object and I'm having trouble casting a returned function value. I am using Qt 5.7.0 and I got .h and .cpp file for COM object with dumpcpp tool.class SCAPILIB_EXPORT IAttrList : public QAxObject { public: IAttrList(IDispatch *subobject = 0, QAxObject *parent = 0) : QAxObject((IUnknown*)subobject, parent) { internalRelease(); } /* Method AddItem method AddItem */ inline void AddItem(Attr Attribute, const QVariant& value); /* Method FindItemIndex method FindItemIndex */ inline int FindItemIndex(int startIndex, SCAPILib::Attr Attribute); /* Method GetCount method GetCount */ inline int GetCount(); /* Method GetIndex method GetIndex */ inline QVariant GetIndex(int index, Attr& pAttribute); /* Method GetItem method GetItem */ inline QVariant GetItem(Attr Attribute); /* Method OutputToString method OutputToString */ inline QString OutputToString(); /* Method RestoreFromBlob method RestoreFromBlob */ inline void RestoreFromBlob(QVariant blob); /* Method SaveToBlob method SaveToBlob */ inline void SaveToBlob(QVariant& pBlob); /* Method SetIndex method SetIndex */ inline void SetIndex(int index, SCAPILib::Attr Attribute, const QVariant& value); // meta object functions static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const { return &staticMetaObject; } virtual void *qt_metacast(const char *); };
The function GetItem always returned a QVariant, usually the QVariant contain a QString, QInt or QBool, but with a determinate attribute the returned value will be a pointer to the base class(IAttrList *).
inline QVariant IAttrList::GetItem(Attr Attribute) { QVariant qax_result; void *_a[] = {(void*)&qax_result, (void*)&Attribute}; qt_metacall(QMetaObject::InvokeMetaMethod, 12, _a); return qax_result; }
I can use the function of the COM object just fine, except when it will be return a indicated class pointer. In this case de QVariant returnet type is (IUnknown *) and I not able to cast this to (IAttrLits *).
I'm tried with:
IAttrList * Attr = AttrList.GetItem(Some_Attribute).Value<IAttrList *>();
But compiler returned error: static assertion failed: qobject_cast requires the type to have a Q_OBJECT macro
Which I understand is normal because, according to QT documentation, classes derived from QAxObject can not contain the Q_OBJECT macro.
I have also tried with:
IAttrList * attr = static_cast<IAttrList *>(AttrList.GetItem(Some_attribute).data());
and
IAttrList * attr = static_cast<IAttrList *>(AttrList.GetItem(Some_attribute).value<void *>();
It's compile but the AttrList pointer does not seem to be valid because I get a segmentation fault to try use it.
I do not know what the problem might be, any subgestion?. Thanks in advanced.
-
Hi @mlago,
Two things to note here.
- You have to add Q_OBJECT macro in private section of the class.
- Before doing qvariant_cast, non-standard data types need to be registered, using the qRegisterMetaType() function
-
Hi @sonulohani ,
Thanks for the answer. The class was generated by dumpcpp from a COM object dll and I can't add Q_OBJECT macro because the class derive of QAxObject and not from QObject. -
@mlago said in COM object and QtVariant casting issue:
the class derive of QAxObject and not from QObject.
QAxObject
derives fromQObject
however. If I remember correctly, you can dynamic cast the unknown interface too. Something along the lines of:IUnknown * interface; //< Comes from the COM API IAttrList * attrList = dynamic_cast<IAttrList *>(interface); if (attrList) { // ... Do things } else { // Not dealing with that type of object at all ... }
-
Hi,
I tried with you say but not work:error: cannot dynamic_cast 'interface' (of type 'struct IUnknown*') to type 'class IAttrList*' (source is a pointer to incomplete type)
I thinking that de right way is using QueryInterface but I have not been able to make it work yet. First all i dont have the UUID class because the dumpcpp dont generate any for this class. I tried asigned one with SetControl method, but in this case, the call:
HRESULT Hr = AttrList.QueryIntrface (IID_AttrList, (void **) & var);
Always returns, 0x80004001 E_NOTIMPL
I do not understand how something seemingly simple may be getting so complicated.
Thanks once again.
-
Hi, to get an instance of IAttrList, I think you need to create it first. (COM doesn't do that for you). Perhaps instead of calling QueryInterface, try a
querySubObject()
, something like:QAxObject *iAttrList = AttrList.GetItem(Some_Attribute).querySubObject("IAttrList");
-
Thanks @hskoglund ,
The QVariant object returned by the function GetItem not have a QuerySubObject method and I can`t do the call in this way.A casting from the QVariant to QAxObject is posible:
QAxObject * axObj =AttrList.GetItem(some_attribute).value<QAxObject *>();
but return with a null pointer in axObj.
thank you anyway.
-
Hmm, if you have some .NET code that successfully retrieves an IAttrList class instance, could you post it here..
-
In case it helps, I bring another part of the code, of the class header file showing in my first post, where it refers to MetaTypeFuntionHelper, I have not found documentation about this struct:
template<> struct QMetaTypeFunctionHelper<SCAPILib::IAttrList, /* Accepted */ true> { static void Destruct(void *t) { Q_UNUSED(t) static_cast<SCAPILib::IAttrList*>(t)->SCAPILib::IAttrList::~IAttrList(); } static void *Construct(void *where, const void *t) { Q_ASSERT(!t); Q_UNUSED(t) return new (where) SCAPILib::IAttrList; } #ifndef QT_NO_DATASTREAM static void Save(QDataStream &stream, const void *t) { stream << *static_cast<const SCAPILib::IAttrList*>(t); } static void Load(QDataStream &stream, void *t) { stream >> *static_cast<SCAPILib::IAttrList*>(t); } #endif // QT_NO_DATASTREAM };
Today I have also tried adding Q_DECLARE_METATYPE() macro to the end of the class declaration, outside the namespace:
namespace SCAPILib { (...) #endif } Q_DECLARE_METATYPE(SCAPILib::IAttrList)
But with these compiler errors:
qmetatype.h:1864: error: specialization of 'QMetaTypeId<SCAPILib::IAttrList>' after instantiation struct QMetaTypeId< TYPE > qmetatype.h:1864: error: redefinition of 'struct QMetaTypeId<SCAPILib::IAttrList>' struct QMetaTypeId< TYPE > qmetatype.h:1596: error: previous definition of 'struct QMetaTypeId<SCAPILib::IAttrList>' struct QMetaTypeId : public QMetaTypeIdQObject<T>