Emit signal from static function issue



  • Hi! I want to emit signal when wlan connection has been registered from static notificationCallBack function.

    Code:
    WirelessConnect.h

    static void WINAPI notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context);
    

    WirelessConnect.cpp

    DWORD dwResult = 0;
    dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, notificationCallBack, NULL, NULL, &dwPrevNotif);
    
    void WINAPI WirelessConnect::notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context)
    {
        context = NULL;
        switch (wlanData->NotificationCode) {
            case wlan_notification_acm_connection_complete:
                emit apConnectionComplete();
                qDebug() << "Connected!";
            break;
    
            case wlan_notification_acm_connection_attempt_fail:
                emit apConnectionFailed();
                qDebug() << "Failed!";
            break;
    
            default:
                break;
        }
    }
    

    Test .cpp:

    WirelessConnect *wirelessAPConnect = new WirelessConnect();
    connect(wirelessAPConnect, &WirelessConnect::apConnectionComplete, setAPConnection);
    connect(wirelessAPConnect, &WirelessConnect::apConnectionFailed, setAPConnectionFailed);
    

    The problem is error: C2355: 'this': can only be referenced inside non-static member functions or non-static data member initializers.

    So how to emit signal from the static function, for example to display QMessageBox about the wlan connection in Test class? Thanks in advance.


  • Moderators

    Static method does not construct an object, so there is no object which could emit the signal. That's why it is forbidden.

    Can you change the method so that it is not static? A const method should be enough.

    If you absolutely have to keep the method static, you can add a QObject parameter and pass there an object which will emit the signal instead of your notificationCallBack method.



  • @sierdzio

    Yes, notificationCallBack is required by WlanRegisterNotification function, and it should be only static.

    If you absolutely have to keep the method static, you can add a QObject parameter and pass there an object which will emit the signal instead of your notificationCallBack method.

    You mean for example, static Test::notificationCallBack pass it to WlanRegisterNotification? Thanks.



    • pass wirelessAPConnect as the pCallbackContext parameter to WlanRegisterNotification
    • remove context = NULL;
    • (optional but recommended) add, at the beginning of the function, Q_ASSERT(dynamic_cast<WirelessConnect*>(context));
    • change emit apConnectionComplete(); to qobject_cast<WirelessConnect*>(context)->apConnectionComplete();
    • change emit apConnectionFailed(); to qobject_cast<WirelessConnect*>(context)->apConnectionFailed();


  • @VRonin

    Ok. I have changed to:

    void WINAPI WirelessConnect::notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context)
    {
        Q_ASSERT(dynamic_cast<WirelessConnect*>(context));
        switch (wlanData->NotificationCode) {
            case wlan_notification_acm_connection_complete:
                qobject_cast<WirelessConnect*>(context)->apConnectionComplete();
                qDebug() << "Connected!";
            break;
    
            case wlan_notification_acm_connection_attempt_fail:
                qobject_cast<WirelessConnect*>(context)->apConnectionFailed();
                qDebug() << "Failed!";
            break;
    
            default:
                break;
        }
    }
    
    WirelessConnect wirelessAPConnect; 
    dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, wirelessAPConnect, NULL, NULL, &dwPrevNotif);
    

    And there are a lot of errors:
    error: C2355: 'this': can only be referenced inside non-static member functions or non-static data member initializers
    error: C2681: 'PVOID': invalid expression type for dynamic_cast
    error: C2665: 'qobject_cast': none of the 2 overloads could convert all the argument types
    error: C2664: 'DWORD WlanRegisterNotification(HANDLE,DWORD,BOOL,WLAN_NOTIFICATION_CALLBACK,PVOID,PVOID,PDWORD)': cannot convert argument 4 from 'WirelessConnect' to 'WLAN_NOTIFICATION_CALLBACK'



  • Then I changed the code to:

    dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, notificationCallBack, NULL, NULL, &dwPrevNotif);
    
    void WINAPI WirelessConnect::notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context)
    {
        WirelessConnect *pThis = (WirelessConnect*)context;
        switch (wlanData->NotificationCode) {
            case wlan_notification_acm_connection_complete:
                qobject_cast<WirelessConnect*>(pThis)->apConnectionComplete();
                qDebug() << "Connected!";
            break;
    
            case wlan_notification_acm_connection_attempt_fail:
                qobject_cast<WirelessConnect*>(pThis)->apConnectionFailed();
                qDebug() << "Failed!";
            break;
    
            default:
                break;
        }
    }
    

    By removing Q_ASSERT(dynamic_cast<WirelessConnect*>(context)); some error fixed. But some errors still exists:

    0_1505735072054_2017-09-18_144245.png



  • These errors are with connect:

    connect(wirelessAPConnect, &WirelessConnect::apConnectionComplete, setAPConnection);
    connect(wirelessAPConnect, &WirelessConnect::apConnectionFailed, setAPConnectionFailed);
    

    How to connect static signals/slots? Thanks.



  • I have fixed the compile errors.

    Code:
    initialized outside of the WirelessConnect class to make it global:
    static WirelessConnect wirelessConnectObj;

    void WINAPI WirelessConnect::notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context)
    {
        context = NULL;
        switch (wlanData->NotificationCode) {
            case wlan_notification_acm_connection_complete:
                wirelessConnectObj.apConnectionComplete();
                qDebug() << "Connected!";
            break;
    
            case wlan_notification_acm_connection_attempt_fail:
                wirelessConnectObj.apConnectionFailed();
                qDebug() << "Failed!";
            break;
    
            default:
                break;
        }
    }
    
    dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, notificationCallBack, NULL, NULL, &dwPrevNotif);
    

    Test.cpp

    connect(&wirelessConnectObj, &WirelessConnect::apConnectionComplete, this, &Test::setAPConnection);
    connect(&wirelessConnectObj, &WirelessConnect::apConnectionFailed, this, &Test::setAPConnectionFailed);
    

    But nothing executes in the slots. It connects to the wireless network, but nothing is shown in GUI any message, nothing.


  • Moderators

    @Cobra91151 Did you check that connect() calls actually succeeded?
    Was the callback called?
    Also using global variables is bad design.



  • @jsulm

    Hi! The callback was called but connect is not working.

    Also using global variables is bad design.

    Then how to connect the same static instance in both classes (where signals emits and where it connects)?


  • Moderators

    @Cobra91151 If connect is not working it prints an error at runtime - is there any?

    How to connect depends on your design/architecture.



  • @jsulm

    Sometimes I get at runtime: QObject::disconnect: Unexpected null parameter.



  • I have fixed the issue:

    I set this to the function:

    
    WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, notificationCallBack, this, NULL, &dwPrevNotif);
    
    void WINAPI WirelessConnect::notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context)
    {
        //context = NULL;
        WirelessConnect *pThis = (WirelessConnect*) context;
        switch (wlanData->NotificationCode) {
            case wlan_notification_acm_connection_complete:
                pThis->apConnectionComplete();
                qDebug() << "Connected!";
            break;
    
            case wlan_notification_acm_connection_attempt_fail:
                pThis->apConnectionFailed();
                qDebug() << "Failed!";
            break;
    
            default:
                break;
        }
    }
    

    Then connect it as not static instance:

    connect(wirelessAPConnect, &WirelessConnect::apConnectionComplete, this, &Test::setAPConnection); 
    connect(wirelessAPConnect, &WirelessConnect::apConnectionFailed, this, &Test::setAPConnectionFailed);
    

    So I don't need the static global instance anymore and it works now.

    Edited:

    After some diagnostics (connecting/disconnecting from Access Points), the solution lead to application crash.



  • @VRonin

    When using this:

    WirelessConnect *pThis = new WirelessConnect(this);
     dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, notificationCallBack, pThis, NULL, &dwPrevNotif);
    
    void WINAPI WirelessConnect::notificationCallBack(PWLAN_NOTIFICATION_DATA wlanData, PVOID context)
    {
        Q_ASSERT(dynamic_cast<WirelessConnect*>(context));
    
        switch (wlanData->NotificationCode) {
            case wlan_notification_acm_connection_complete:
                qobject_cast<WirelessConnect*>(context)->apConnectionComplete();
            break;
    
            case wlan_notification_acm_connection_attempt_fail:
                qobject_cast<WirelessConnect*>(context)->apConnectionFailed();
            break;
    
            default:
                break;
        }
    }
    

    I get a lot of errors:

    0_1507324921791_2017-10-07_002151.png

    Can you describe your solution more properly? Thanks.



  • My bad, replace qobject_cast with dynamic_cast, I was trying to over optimise


Log in to reply
 

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