C++获取WiFi列表(Native WiFi API)

C++获取WiFi列表(Native WiFi API)

官方Demo

获取WiFi的流程:打开Wlan Handle→枚举网卡信息→获取WiFi列表,官方Demo,Here
所需要用到的接口:

WlanOpenHandle 入口:Here
WlanEnumInterfaces 入口:Here
WlanGetAvailableNetworkList 入口:Here

根据官方给出的Demo,确实可以获取到WiFi列表,一切看起来似乎很正常。

问题

经过一段时间的使用之后,发现使用这段代码获取到的WiFi列表信息,根本无更新,长时间维持同一份列表,那么肯定是有问题了,于是开始一顿搜索NativaWiFi API

解决

最终在WlanScan找到了答案。

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

WlanScan函数请求扫描指定接口上的可用网络。
在Remark说明中对WiFi接口有详细的说明。

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.

当可用的无线网络发生变化时,无线局域网服务不会发送通知。无线局域网服务不跟踪多次扫描后可用网络列表的变化。当前的默认行为是,无线LAN服务只要求无线接口驱动程序每60秒扫描一次无线网络,在某些情况下(当已经连接到无线网络时),无线LAN服务根本不要求扫描。WlanScan功能可以被应用程序用来跟踪无线网络的变化。
所以解决WiFi问题的关键点就在于WlanScan,应用程序可以周期性的向网卡驱动发送探测请求,这样就就可以在网卡信息中获取到最新的WiFi信息。
下面是实现获取WiFi列表的代码:

#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();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值