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.

    1. You have to add Q_OBJECT macro in private section of the class.
    2. 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.


  • Qt Champions 2016

    @mlago said in COM object and QtVariant casting issue:

    the class derive of QAxObject and not from QObject.

    QAxObject derives from QObject 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>
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.