VC++玩转Native Wifi API

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

               


Windows应用想要实现连接wifi,监听wifi信号,断开连接等功能,用NativeWifi API是个不错的选择。

打开MSDN,搜索NativeWifi Api,找到Native Wifi页。在这里


信息量很大,如果像我着急实现上述功能,看海量的文档有些来不及。如果直接给我例子,在运行中调试,阅读代码,效率会更高。

但是,我并没有成功。首先,SampleSDK

中,参见这里我下载几次都失败了,最后放弃这条路。后来同事给了我一份Sample,我不敢确定是否就是这个,但是代码写的也是很晦涩。我的初衷是简单的使用这些API的例子。


看来还是自己动手吧。看相关API,如果不懂,就找有经验人的例子。

几经周折,终于实现我的需求。让我慢慢道来。

1.获得可用AP列表

参见WlanGetAvailableNetworkList的官方文档,下面有例子。

DWORD WINAPI WlanGetAvailableNetworkList(  _In_        HANDLE hClientHandle,  _In_        const GUID *pInterfaceGuid,  _In_        DWORD dwFlags,  _Reserved_  PVOID pReserved,  _Out_       PWLAN_AVAILABLE_NETWORK_LIST *ppAvailableNetworkList);

由可用列表便可以找到当前哪个AP正在连接,并显示信号强度。

2.监听当前连接

在获得可用AP列表的基础上,遍历当前AP,看谁正在连接,并取得它的信号。代码片段如下:

bool isConnect = false;int numberOfItems = pWLAN_AVAILABLE_NETWORK_LIST->dwNumberOfItems;        for(int i = 0; i <= numberOfItems; i++)        {            WLAN_AVAILABLE_NETWORK wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[i];            if(wlanAN.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)            {                Wprintf(WLAN signal is %s:%d\n",  wlanAN.strProfileName, wlanAN.wlanSignalQuality);                isConnect = true;                   }        }        if(!isConnect){             wprintf("Wifi is disconnected!\n");}

3.断开连接

如果wifi处于连接状态,将其断开。WlanDisconnect还是容易使用的。原型如下:

DWORD WINAPI WlanDisconnect(  _In_        HANDLE hClientHandle,  _In_        const GUID *pInterfaceGuid,  _Reserved_  PVOID pReserved);

代码演示在后面。

4.连接一个有profile的AP(已保存过密码)

这是本文的重点。
虽然连接函数WlanConnect原型很简单:

DWORD WINAPI WlanConnect(  _In_        HANDLE hClientHandle,  _In_        const GUID *pInterfaceGuid,  _In_        const PWLAN_CONNECTION_PARAMETERS pConnectionParameters,  _Reserved_  PVOID pReserved);


但参数PWLAN_CONNECTION_PARAMETERS却是很复杂,只要有一个配错,连接就会失败。
还好我的需求还是蛮简单的,只要连接已有的profile的AP。那么我的工作就会有针对性的开展。挫折了好多天,每次都连接失败,原因是ERROR_INVALID_PARAMETER。
就在今天,我终于成功了。真是会者不难,难者不会啊。
看看连接参数的结构体:

typedef struct _WLAN_CONNECTION_PARAMETERS {  WLAN_CONNECTION_MODE wlanConnectionMode;  LPCWSTR              strProfile;  PDOT11_SSID          pDot11Ssid;  PDOT11_BSSID_LIST    pDesiredBssidList;  DOT11_BSS_TYPE       dot11BssType;  DWORD                dwFlags;} WLAN_CONNECTION_PARAMETERS, *PWLAN_CONNECTION_PARAMETERS;

为了实现我的要求,可以这样赋值:
wlanConnectionMode这里设成wlan_connection_mode_profile
strProfile写上你要连接ap的名称(通常是profile名称)
pDot11Ssid用不上,设置NULL
pDesiredBssidList同样置成NULL
dot11BssType我给设成dot11_BSS_type_infrastructure(基础设施?)
dwFlags设置为WLAN_CONNECTION_HIDDEN_NETWORK
确实是工作了,strProfile如何获取呢?参见监听连接信号中对可用AP列表中第一个profile的获取。
完整代码如下:

//#include "stdafx.h"#include <windows.h>#include <wlanapi.h>#include <objbase.h>#include <wtypes.h>#include <string>#include <stdio.h>#include <stdlib.h>// Need to link with Wlanapi.lib and Ole32.lib#pragma comment(lib, "wlanapi.lib")#pragma comment(lib, "ole32.lib")using namespace std;int listenStatus(){ HANDLE hClient = NULL;    DWORD dwMaxClient = 2;           DWORD dwCurVersion = 0;    DWORD dwResult = 0;    DWORD dwRetVal = 0;    int iRet = 0;        WCHAR GuidString[39] = {0}; //Listen the status of the AP you connected. while(1){  Sleep(5000);  PWLAN_INTERFACE_INFO_LIST pIfList = NULL;//I think wlan interface means network card  PWLAN_INTERFACE_INFO pIfInfo = NULL;  DWORD dwFlags = 0;             dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);  if (dwResult != ERROR_SUCCESS) {   wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);   return 1;  }  dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);  if (dwResult != ERROR_SUCCESS) {   wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);   return 1;  } else {   wprintf(L"WLAN_INTERFACE_INFO_LIST for this system\n");   wprintf(L"Num Entries: %lu\n", pIfList->dwNumberOfItems);   wprintf(L"Current Index: %lu\n\n", pIfList->dwIndex);   int i;   for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) {    pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i];    wprintf(L"  Interface Index[%u]:\t %lu\n", i, i);    iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString,      sizeof(GuidString)/sizeof(*GuidString));      if (iRet == 0)     wprintf(L"StringFromGUID2 failed\n");    else {     wprintf(L"  InterfaceGUID[%d]: %ws\n",i, GuidString);    }        wprintf(L"  Interface Description[%d]: %ws", i,      pIfInfo->strInterfaceDescription);    wprintf(L"\n");    wprintf(L"  Interface State[%d]:\t ", i);    switch (pIfInfo->isState) {    case wlan_interface_state_not_ready:     wprintf(L"Not ready\n");     break;    case wlan_interface_state_connected:     wprintf(L"Connected\n");     break;    case wlan_interface_state_ad_hoc_network_formed:     wprintf(L"First node in a ad hoc network\n");     break;    case wlan_interface_state_disconnecting:     wprintf(L"Disconnecting\n");     break;    case wlan_interface_state_disconnected:     wprintf(L"Not connected\n");     break;    case wlan_interface_state_associating:     wprintf(L"Attempting to associate with a network\n");     break;    case wlan_interface_state_discovering:     wprintf(L"Auto configuration is discovering settings for the network\n");     break;    case wlan_interface_state_authenticating:     wprintf(L"In process of authenticating\n");     break;    default:     wprintf(L"Unknown state %ld\n", pIfInfo->isState);     break;    }   }  } }}int _tmain(int argc, _TCHAR* argv[]){    HANDLE hClient = NULL;    DWORD dwMaxClient = 2;           DWORD dwCurVersion = 0;    DWORD dwResult = 0;    DWORD dwRetVal = 0;    int iRet = 0;        /* variables used for WlanEnumInterfaces  */    PWLAN_INTERFACE_INFO_LIST pIfList = NULL;    PWLAN_INTERFACE_INFO pIfInfo = NULL;    LPCWSTR pProfileName = NULL;    LPWSTR pProfileXml = NULL;    DWORD dwFlags = 0;        pProfileName = argv[1];         wprintf(L"Information for profile: %ws\n\n", pProfileName);        dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);    if (dwResult != ERROR_SUCCESS) {        wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);        return 1;    }    dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);    if (dwResult != ERROR_SUCCESS) {        wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);        return 1;    } else {  dwResult = WlanDisconnect(hClient, &pIfList->InterfaceInfo[0].InterfaceGuid,NULL);//DISCONNECT FIRST  if(dwResult != ERROR_SUCCESS)  {   printf("WlanDisconnect failed with error: %u\n",dwResult);            return -1;  }  PWLAN_AVAILABLE_NETWORK_LIST pWLAN_AVAILABLE_NETWORK_LIST = NULL;        dwResult = WlanGetAvailableNetworkList(hClient, &pIfList->InterfaceInfo[0].InterfaceGuid,                WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES,                NULL, &pWLAN_AVAILABLE_NETWORK_LIST);        if (dwResult != ERROR_SUCCESS)        {               printf("WlanGetAvailableNetworkList failed with error: %u\n",dwResult);            WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);            return -1;        }        WLAN_AVAILABLE_NETWORK wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[0];//PLEASE CHECK THIS YOURSELF  if(pProfileName == NULL)   pProfileName = wlanAN.strProfileName;     WLAN_CONNECTION_PARAMETERS wlanConnPara;     wlanConnPara.wlanConnectionMode =wlan_connection_mode_profile ; //YES,WE CONNECT AP VIA THE PROFILE     wlanConnPara.strProfile =pProfileName;       // set the profile name     wlanConnPara.pDot11Ssid = NULL;         // SET SSID NULL     wlanConnPara.dot11BssType = dot11_BSS_type_infrastructure;  //dot11_BSS_type_any,I do not need it this time.          wlanConnPara.pDesiredBssidList = NULL;       // the desired BSSID list is empty     wlanConnPara.dwFlags = WLAN_CONNECTION_HIDDEN_NETWORK;   //it works on my WIN7\8     dwResult=WlanConnect(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid,&wlanConnPara ,NULL);     if (dwResult==ERROR_SUCCESS)     {   printf("WlanConnect success!\n");     }        else        {   printf("WlanConnect failed err is %d\n",dwResult);        }    } listenStatus(); //LISTEN THE STATUS    if (pProfileXml != NULL) {        WlanFreeMemory(pProfileXml);        pProfileXml = NULL;    }    if (pIfList != NULL) {        WlanFreeMemory(pIfList);        pIfList = NULL;    }    return dwRetVal;}

 

5.打开网络设置界面

遇到以前没有连接过的AP,需要输入密码,那么,直接打开配置界面让用户自己来搞吧。

    ShellExecute(      NULL,       L"open",       L"shell:::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{38a98528-6cbf-4ca9-8dc0-b1e1d10f7b1b}",      NULL,      NULL,      SW_SHOWNORMAL);

6.最后

当屏幕上打印出“WlanConnect success!”的时候,别提多高兴了。

就像爱迪生试验灯丝一下,在无数次失败后,终于找到了一种材料可以胜任灯丝的工作。这种喜悦真的令人振奋,往日的阴霾和不爽终于一扫而光。
其实我也尝试过WlanGetProfile和WlanSetProfile,虽然有时结果是能够连上指定AP,但是函数返回结果却总是ERROR_INVALID_PARAMETER。
网上的例子,很多都是抄来抄去的,写的不明不白,虽然有过帮助,但是也有些误导。
今天自己成功的连接到指定AP了(用命令行运行我的例子,输入参数profile name),我一定要把它发表出来,让其他人有个参考。
我认为这是一件诚意的作品,在此也谢谢给过我帮助的朋友。
最后说一下获得的信号。标准信号RSSI是负值,而这里获得的信号都是正值(0~100),在有些需要RSSI的地方,我们需要转换一下:

                   if (pBssEntry->wlanSignalQuality == 0)                        iRSSI = -100;                    else if (pBssEntry->wlanSignalQuality == 100)                           iRSSI = -50;                    else                        iRSSI = -100 + (pBssEntry->wlanSignalQuality/2);                                                wprintf(L"  Signal Quality[%u]:\t %u (RSSI: %i dBm)\n", j,                         pBssEntry->wlanSignalQuality, iRSSI);

本文到此完毕,虽然没有涵盖大部分API,但还是欢迎大家留意讨论。














           

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值