QObject::connect signal not found in dll with Pointer to Member Function



  • This problem is specific to a library compiled as a shared library on Windows i.e. a dll when trying to connect to a signal in an object in the library using a pointer to the member signal function.

    When trying to connect to a signal in a dll using a PointerToMemberFunction signal QObject::connect function, it fails with a runtime error of QObject::connect signal not found in <Class name>.
    The following sample code can be used to demonstrate the problem:

    #ifndef LIBRARY_H
    #define LIBRARY_H
    #include <QObject>
    class Library : public QObject
    {
    Q_OBJECT
    public:
        void emitSignal(){ emit signal(); }
    signals:
        void signal();
    };
    #endif // LIBRARY_H
    
    #include "library.h"
    #include <iostream>
    int main()
    {
        Library library;
        QObject::connect(&library, &Library::signal, []()
        {
            std::cout << "Caught signal!" << std::endl;
        });
        library.emitSignal();
    }
    

    The above code compiles and works correctly on Linux and Mac with the library compiled as a shared library or a static library. It also compiles and works on Windows when the library is compiled as a static library. It compiles, but fails to connect on Windows when the library is compiled as a shared library i.e. a dll.

    In addition to the above problem description I can confirm the following:

    1. It works if the above code is changed to use one of the const char *signal QObject::connect functions. However, there are two reasons this is not a satisfactory solution: a) There are no Functor options with the const char *signal QObject::connect functions. b) Using PointerToMemberFunction signal options should provide compile time errors if the signal does not exist. Ironically, this is exactly the opposite of the problem being experienced.

    2. The code is failing inside the moc code generated for the library object.

    void Library::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
    {
        if (_c == QMetaObject::InvokeMetaMethod) {
            auto *_t = static_cast<Library *>(_o);
            Q_UNUSED(_t)
            switch (_id) {
            case 0: _t->signal(); break;
            default: ;
            }
        } else if (_c == QMetaObject::IndexOfMethod) {
            int *result = reinterpret_cast<int *>(_a[0]);
            {
                using _t = void (Library::*)();
                _t left = *reinterpret_cast<_t *>(_a[1]);
                _t right = static_cast<_t>(&Library::signal);
                if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Library::signal)) {
                    *result = 0;
                    return;
                }
            }
        }
        Q_UNUSED(_a);
    }
    

    I have added the two lines to visualise the two sides being compared in the following line:

                _t left = *reinterpret_cast<_t *>(_a[1]);
                _t right = static_cast<_t>(&Library::signal);
    

    When debugging the Windows dll version, both left and right point to the same function, but left is pointing to code inside the application and right is pointing to code inside the library. (In all other versions, both left and right point to the same location in memory: inside the library.)

    1. There is nothing wrong with the pointer to the function in the application, as it can be used to call the signal function: it will call the moc generated code inside the dll.

    Any ideas?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You are not exporting your symbols correctly. See the Creating Shared Libraries chapter in Qt's documentation.


Log in to reply
 

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