Search code examples
c++windowsnetwork-programmingwlanapi

Wifi notifications in Windows


I would like to know how a windows C++ app can get notified when windows system changes its wifi network. I'm interested in the following cases:

  1. When the user has switched on the wifi and has connected to a new network
  2. When the user has switched off the wifi and has disconnected from a network
  3. When the user has changed from network A to network B

Note: Switching on/off the wifi is not of interest. Device needs to be connected to a network. Network may or may not have an internet connection.

I'm trying to achieve this using the wlanapi.h and have checked out a few examples, but have not been able to achieve this.

Let me know if someone was able to achieve this using wlanapi.h. Or is there an another way? Pls demonstrate with an example.

Any help would be appreciated.

EDIT: Adding code

#include    <windows.h>
#include    <Wlanapi.h>
#include    <iostream>

// Link wlanapi.lib

#pragma     comment(lib, "wlanapi.lib")

void    DetectWifiNetworkChanges ();
void    EventLoop ();

// Callback func to receive network notifications

void    WlanNotificationCallback (PWLAN_NOTIFICATION_DATA  pData, PVOID pContext);

int main ()
{

    DetectWifiNetworkChanges ();

    printf ("\n");

    getchar ();
    return 0;
}

void DetectWifiNetworkChanges ()
{
    printf ("DetectWifiNetworkChanges\n");

        HANDLE  client;
        DWORD   client_version  = 2;
        DWORD   current_version = 0;
        DWORD   result;

    result = WlanOpenHandle (client_version, NULL, &current_version, &client);
    if (result != ERROR_SUCCESS) {

        printf ("WlanOpenHandle failed !!\n");
        return;
    }

    result = WlanRegisterNotification (client, WLAN_NOTIFICATION_SOURCE_ALL, FALSE, WlanNotificationCallback, NULL, NULL, NULL);
    if (result != ERROR_SUCCESS) {

        printf ("WlanRegisterNotification failed !!\n");
        return;
    }

    printf ("WlanRegistration successful\n");

    // An infinite loop (Ctrl + C to quit the app for now)
    EventLoop ();

    result = WlanCloseHandle (client, NULL);
    if (result != ERROR_SUCCESS) {

        printf ("WlanCloseHandle !!\n");
        return;
    }
}

Output

DetectWifiNetworkChanges
WlanRegistration successful
EventLoop

I tried to connect and disconnect from my network, but the callback is not called.

But sometimes, without me disconnecting from the network, the callback is called lots of times.


Solution

  • The solution was simple. I just had to change the type of notifications while registering and capture the states in the callback (The callback was empty previously).

    When registering, the notification source should be WLAN_NOTIFICATION_SOURCE_ACM.

    I captured all the states in the callback. Here is the modified working code

    #include    <windows.h>
    #include    <Wlanapi.h>
    #include    <iostream>
    
    // Link wlanapi.lib
    
    #pragma     comment(lib, "wlanapi.lib")
    
    void    DetectWifiNetworkChanges ();
    void    HandleACMNotifications (PWLAN_NOTIFICATION_DATA pNotification);
    
    // Callback func to receive wifi notifications
    
    void    WlanNotificationCallback (PWLAN_NOTIFICATION_DATA  pData, PVOID pContext);
    
    int
    main ()
    {
    
        DetectWifiNetworkChanges ();
    
        printf ("\n");
    
        getchar ();
        return 0;
    }
    
    // Entry point.
    // Will be called from int main
    void
    DetectWifiNetworkChanges ()
    {
        printf ("DetectWifiNetworkChanges\n");
    
            HANDLE  client;
            DWORD   client_version  = 2;
            DWORD   current_version = 0;
            DWORD   result;
    
        result = WlanOpenHandle (client_version, NULL, &current_version, &client);
        if (result != ERROR_SUCCESS) {
    
            printf ("WlanOpenHandle failed !!\n");
            return;
        }
    
        result = WlanRegisterNotification (client, WLAN_NOTIFICATION_SOURCE_ACM, FALSE, WlanNotificationCallback, NULL, NULL, NULL);
        if (result != ERROR_SUCCESS) {
    
            printf ("WlanRegisterNotification failed !!\n");
            return;
        }
    
        printf ("WlanRegistration successful\n");
    
        // Wait for input from user
        // The program pauses here. Toggle the wifi, change wifi network etc.
        // to see the wifi notifications
    
        getchar ();
    
        result = WlanCloseHandle (client, NULL);
        if (result != ERROR_SUCCESS) {
    
            printf ("WlanCloseHandle !!\n");
            return;
        }
    }
    
    void
    WlanNotificationCallback (PWLAN_NOTIFICATION_DATA pNotification, PVOID pContext)
    {
    
        printf ("WlanNotificationCallback\n");
    
        if (pNotification->NotificationSource == WLAN_NOTIFICATION_SOURCE_ACM)
            HandleACMNotifications (pNotification);
    }
    
    void
    HandleACMNotifications (PWLAN_NOTIFICATION_DATA pNotification)
    {
    
        printf ("HandleACMNotifications\n");
    
        switch (pNotification->NotificationCode) {
    
            case wlan_notification_acm_start:
                printf ("wlan_notification_acm_start\n");
                break;
    
            case wlan_notification_acm_autoconf_enabled:
                printf ("wlan_notification_acm_autoconf_enabled\n");
                break;
    
            case wlan_notification_acm_autoconf_disabled:
                printf ("wlan_notification_acm_autoconf_disabled\n");
                break;
    
            case wlan_notification_acm_background_scan_enabled:
                printf ("wlan_notification_acm_background_scan_enabled\n");
                break;
                    
            case wlan_notification_acm_background_scan_disabled:
                printf ("wlan_notification_acm_background_scan_disabled\n");
                break;
    
            case wlan_notification_acm_bss_type_change:
                printf ("wlan_notification_acm_bss_type_change\n");
                break;
    
            case wlan_notification_acm_power_setting_change:
                printf ("wlan_notification_acm_power_setting_change\n");
                break;
    
            case wlan_notification_acm_scan_complete:
                printf ("wlan_notification_acm_scan_complete\n");
                break;
    
            case wlan_notification_acm_scan_fail:
                printf ("wlan_notification_acm_scan_fail\n");
                break;
    
            case wlan_notification_acm_connection_start:
                printf ("wlan_notification_acm_connection_start\n");
                break;
    
            case wlan_notification_acm_connection_complete:
                printf ("wlan_notification_acm_connection_complete\n");
                break;
    
            case wlan_notification_acm_connection_attempt_fail:
                printf ("wlan_notification_acm_connection_attempt_fail\n");
                break;
    
            case wlan_notification_acm_filter_list_change:
                printf ("wlan_notification_acm_filter_list_change\n");
                break;
    
            case wlan_notification_acm_interface_arrival:
                printf ("wlan_notification_acm_interface_arrival\n");
                break;
    
            case wlan_notification_acm_interface_removal:
                printf ("wlan_notification_acm_interface_removal\n");
                break;
    
            case wlan_notification_acm_profile_change:
                printf ("wlan_notification_acm_profile_change\n");
                break;
    
            case wlan_notification_acm_profile_name_change:
                printf ("wlan_notification_acm_profile_name_change\n");
                break;
    
            case wlan_notification_acm_profiles_exhausted:
                printf ("wlan_notification_acm_profiles_exhausted\n");
                break;
    
            case wlan_notification_acm_network_not_available:
                printf ("wlan_notification_acm_network_not_available\n");
                break;
    
            case wlan_notification_acm_network_available:
                printf ("wlan_notification_acm_network_available\n");
                break;
    
            case wlan_notification_acm_disconnecting:
                printf ("wlan_notification_acm_disconnecting\n");
                break;
    
            case wlan_notification_acm_disconnected:
                printf ("wlan_notification_acm_disconnected\n");
                break;
    
            case wlan_notification_acm_adhoc_network_state_change:
                printf ("wlan_notification_acm_adhoc_network_state_change\n");
                break;
    
            case wlan_notification_acm_profile_unblocked:
                printf ("wlan_notification_acm_profile_unblocked\n");
                break;
    
            case wlan_notification_acm_screen_power_change:
                printf ("wlan_notification_acm_screen_power_change\n");
                break;
    
            case wlan_notification_acm_profile_blocked:
                printf ("wlan_notification_acm_profile_blocked\n");
                break;
    
            case wlan_notification_acm_scan_list_refresh:
                printf ("wlan_notification_acm_scan_list_refresh\n");
                break;
    
            case wlan_notification_acm_operational_state_change:
                printf ("wlan_notification_acm_operational_state_change\n");
                break;
    
            case wlan_notification_acm_end:
                printf ("wlan_notification_acm_end\n");
                break;
        }
    }
    
    

    Observation:

    When I click on the wifi icon to see the list of available networks, the callback is invoked with the following notifications

    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_scan_complete
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_scan_list_refresh
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_network_available
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_profiles_exhausted
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_network_available
    

    Note: WlanNotificationCallback, HandleACMNotifications are my printfs, as shown in the code. These two are pasted in the output along with the notification code as per the flow.

    These notifications will be repeated since the system scans and displays the list of available networks in the following scenarios

    1. When clicking on the wifi icon to choose and connect to a network
    2. When disconnected from a network and the list of available networks is visible again.

    Notifications received when disconnecting from the network:

    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_scan_complete
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_scan_list_refresh
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_profile_change
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_disconnecting
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_disconnected
    

    Notifications received when connecting to a network:

    wlan_notification_acm_profile_change
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_connection_start
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_scan_fail
    WlanNotificationCallback
    HandleACMNotifications
    wlan_notification_acm_connection_complete
    

    Ignoring the intermediate notification codes, handling wlan_notification_acm_connection_complete and wlan_notification_acm_disconnected will work.