C + + get WiFi list (Native WiFi API)

Keywords: network Windows

C + + get WiFi list (Native WiFi API)

Official Demo

Process of obtaining WiFi: open Wlan Handle → enumerate network card information → obtain WiFi list, official Demo, Here
Required interfaces:

WlanOpenHandle entry: Here
WlanEnumInterfaces entrance: Here
WlanGetAvailableNetworkList entry: Here

According to the official Demo, you can get the WiFi list. Everything seems to be normal.

problem

After a period of use, it is found that the WiFi list information obtained by using this code is not updated at all, and the same list is maintained for a long time, so there must be a problem, so a search is started NativaWiFi API

Solve

Ultimately in WlanScan We found the answer.

The WlanScan function requests a scan for available networks on the indicated interface.

The WlanScan function requests a scan of the available networks on the specified interface.
There is a detailed description of the WiFi interface in the Remark description.

The Wireless LAN Service does not send notifications when available wireless networks change. The Wireless LAN Service does not track changes to the list of available networks across multiple scans. The current default behavior is that the Wireless LAN Service only asks the wireless interface driver to scan for wireless networks every 60 seconds, and in some cases (when already connected to wireless network) the Wireless LAN Service does not ask for scans at all. The WlanScan function can be used by an application to track wireless network changes. The application should first register for WLAN_NOTIFICATION_SOURCE_ACM notifications. The WlanScan function can then be called to initiate a scan. The application should then wait to receive the wlan_notification_acm_scan_complete notification or timeout after 4 seconds. Then the application can call the WlanGetNetworkBssList or WlanGetAvailableNetworkList function to retrieve a list of available wireless networks. This process can be repeated periodically with the application keeping tracking of changes to available wireless networks.

When the available wireless network changes, the WLAN service does not send notifications. The WLAN service does not track changes in the list of available networks after multiple scans. The current default behavior is that the wireless LAN service only requires the wireless interface driver to scan the wireless network once every 60 seconds. In some cases (when connected to the wireless network), the wireless LAN service does not require scanning at all. WlanScan features can be used by applications to track changes in wireless networks.
So the key to solve the WiFi problem is WlanScan. Applications can periodically send detection requests to the network card driver, so that the latest WiFi information can be obtained from the network card information.
Here is the code to get WiFi list:

#ifndef UNICODE
#define UNICODE
#endif

#include <windows.h>
#include <wlanapi.h>
#include <objbase.h>
#include <wtypes.h>

#include <iostream>
#include <chrono>
#include <vector>
#include <mutex>
#include <condition_variable>
#include <string>

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

class CDefer
{
public:
    CDefer(const std::function<void()>& constructor, const std::function<void()>& destructor);

    ~CDefer();

private:
    std::function<void()> _constructor;
    std::function<void()> _destructor;
};

CDefer::CDefer(const std::function<void()>& constructor, const std::function<void()>& destructor)
    : _constructor(constructor)
    , _destructor(destructor)
{
    if (_constructor)
    {
        _constructor();
    }
}
CDefer::~CDefer()
{
    if (_destructor)
    {
        _destructor();
    }
}

class ApSsidInstance
{
    friend void OnNotificationCallback(PWLAN_NOTIFICATION_DATA data, PVOID context);
public:
    static ApSsidInstance& GetInstance()
    {
        static ApSsidInstance instance;
        return instance;
    }
    bool GetSsidList(std::vector<std::string>& wifilist);
    void CvNotify();
private:
    ApSsidInstance()
        : _wlanHandle(NULL)
    {
    }

    bool InitialHandle();
private:
    HANDLE _wlanHandle;
    std::vector<std::string> _ssidList;
    std::condition_variable _cv;
    std::mutex _mutex;
};

int wmain()
{
    while (true)
    {
        std::vector<std::string> wifis;
        ApSsidInstance::GetInstance().GetSsidList(wifis);
        Sleep(100);
    }

    while (true) std::this_thread::sleep_for(std::chrono::hours(10));
    return 0;
}

bool ApSsidInstance::GetSsidList(std::vector<std::string>& wifilist)
{
    bool result = false;
    if (!InitialHandle())
    {
        std::cout << "initial wlan handle failed" << std::endl;
        return false;
    }

    DWORD dwResult = 0;
    PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
    PWLAN_INTERFACE_INFO pIfInfo = NULL;
    WCHAR GuidString[39] = { 0 };

    PWLAN_AVAILABLE_NETWORK_LIST pBssList = NULL;
    PWLAN_AVAILABLE_NETWORK pBssEntry = NULL;

    CDefer pIfRaii([]() {}, [&pBssList, &pIfList]()
                     {
                         if (pBssList != NULL)
                         {
                             WlanFreeMemory(pBssList);
                             pBssList = NULL;
                         }

                         if (pIfList != NULL)
                         {
                             WlanFreeMemory(pIfList);
                             pIfList = NULL;
                         }
                     });

    unsigned int i, j;

    dwResult = WlanEnumInterfaces(_wlanHandle, NULL, &pIfList);
    if (dwResult != ERROR_SUCCESS)
    {
        return false;
    }
    else
    {
        for (i = 0; i < (int)pIfList->dwNumberOfItems; i++)
        {
            pIfInfo = (WLAN_INTERFACE_INFO*)&pIfList->InterfaceInfo[i];

            dwResult = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR)&GuidString,
                                       sizeof(GuidString) / sizeof(*GuidString));

            dwResult = WlanScan(_wlanHandle, (const GUID*)(&pIfInfo->InterfaceGuid), NULL, NULL, NULL);
            if (dwResult != ERROR_SUCCESS)
            {
                return false;
            }
        }
    }

    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cv.wait_for(lock, std::chrono::seconds(4));
    }

    for (i = 0; i < (int)pIfList->dwNumberOfItems; i++)
    {
        pIfInfo = (WLAN_INTERFACE_INFO*)&pIfList->InterfaceInfo[i];
        dwResult = WlanGetAvailableNetworkList(_wlanHandle,
                                               &pIfInfo->InterfaceGuid,
                                               0,
                                               NULL,
                                               &pBssList);

        if (dwResult != ERROR_SUCCESS)
        {
            std::cout << "WlanGetAvailableNetworkList failed with error:" << dwResult;
            return false;
        }
        for (j = 0; j < pBssList->dwNumberOfItems; j++)
        {
            pBssEntry = (WLAN_AVAILABLE_NETWORK*)&pBssList->Network[j];
            std::string temp = std::string(reinterpret_cast<char*>(pBssEntry->dot11Ssid.ucSSID));
            if (temp.find("BugM") != std::string::npos)
            {
                std::cout << "+++++++++++++++++" << std::endl;
            }
            wifilist.emplace_back(temp);
            std::cout << "wifi name:" << temp << std::endl;
        }
    }

    return true;
}

void ApSsidInstance::CvNotify()
{
    _cv.notify_all();
}

bool ApSsidInstance::InitialHandle()
{
    DWORD dwResult = 0;
    DWORD dwCurVersion = 0;
    DWORD dwMaxClient = 2;
    if (_wlanHandle == NULL)
    {
        if ((dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &_wlanHandle)) != ERROR_SUCCESS)
        {
            std::cout << "wlanOpenHandle failed with error: " << dwResult << std::endl;
            _wlanHandle = NULL;
            return false;
        }
        if ((dwResult = WlanRegisterNotification(_wlanHandle, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, WLAN_NOTIFICATION_CALLBACK(OnNotificationCallback), NULL, nullptr, nullptr)) != ERROR_SUCCESS)
        {
            std::cout << "wlanRegisterNotification failed with error: " << dwResult << std::endl;
            _wlanHandle = NULL;
            return false;
        }
    }
    return true;
}

void OnNotificationCallback(PWLAN_NOTIFICATION_DATA data, PVOID context)
{
    if (data != NULL && data->NotificationSource == WLAN_NOTIFICATION_SOURCE_ACM && (data->NotificationCode == wlan_notification_acm_scan_complete || data->NotificationCode == wlan_notification_acm_start))
    {
        ApSsidInstance::GetInstance().CvNotify();
    }
}

Published 5 original articles, praised 0, visited 49
Private letter follow

Posted by nadeem14375 on Mon, 02 Mar 2020 21:51:53 -0800