0

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.

NightFuryLxD
  • 847
  • 5
  • 15
  • 2
    _"but have not been able to achieve this."_ what specifically did you try, and what went wrong. Show some code you've tried. – πάντα ῥεῖ Oct 09 '21 at 13:31
  • 2
    [The `WlanRegisterNotification` function is used to register and unregister notifications on all wireless interfaces.](https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlanregisternotification) – Richard Critten Oct 09 '21 at 13:40
  • @πάνταῥεῖ I have added the code. I'm sure there is a big gap in my understanding of the library. I've been spinning on this for quite a while. I was hoping to understand with this question. – NightFuryLxD Oct 10 '21 at 13:14

1 Answers1

1

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.

NightFuryLxD
  • 847
  • 5
  • 15