VC++玩转Native Wifi API



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

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

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

但是,我并没有成功。首先,Sample在SDK

中,参见这里。我下载几次都失败了,最后放弃这条路。后来同事给了我一份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,但还是欢迎大家留意讨论。



VC++玩转Native Wifi API

时间: 2024-08-10 15:53:53

VC++玩转Native Wifi API的相关文章

VC++玩转Native Wifi API 3---GOTO在释放资源时的作用

GOTO语句有着很臭的名声,我们的老师经常教导我们说,不要轻易使用它. C++跳转语句有三个:goto.break和continue.它们只是工具,我觉得问题不能归咎于工具,问题在于人. 就像指针一样,goto这个无条件跳转语句力量还是很强大的,如果滥用,出现问题很难排查. 但有些时候goto确实是不二选择,例如我遇到的,在函数中有多个出口,而每个出口都遇到释放资源的时候,与其都把释放语句不厌其烦的写一遍, 不如一个goto语句来的干脆利落. 下面的例子取自上一篇Native Wifi API文

漫谈可视化Prefuse(四)---被玩坏的Prefuse API

这个双12,别人都在抢红包.逛淘宝.上京东,我选择再续我的“漫谈可视化”系列(好了,不装了,其实是郎中羞涩...) 上篇<漫谈可视化Prefuse(三)---Prefuse API数据结构阅读有感>主要介绍了可视化工具Prefuse API中主要解读的是prefuse.data包中的主要接口,并利用<漫谈可视化Prefuse(一)---从SQL Server数据库读取数据>中例子,将参数配置模块剥离出来,实现界面传值,绘制图形. 本篇决定不再贴API,实在没啥意思,还占篇幅(但是不

如何使用Native Messaging API 打开window程序

问 如何使用Native Messaging API 打开window程序 cmd javascript terminal chrome Tychio 2013年03月26日提问 关注 1 关注 收藏 1 收藏,5.6k 浏览 问题对人有帮助,内容完整,我也想知道答案0问题没有实际价值,缺少关键内容,没有改进余地 我参照Fran?ois Beaufort的视频写了一个打开CMD程序的chrome应用,但是没效果,应该已调用到用于打开程序的本地应用了,但是似乎terminal.bat没有执行.视频

Java JVM、JNI、Native Function Interface、Create New Process Native Function API Analysis

目录 1. JAVA JVM 2. Java JNI: Java Native Interface 3. Java Create New Process Native Function API Analysis In Linux 4. Java Create New Process Native Function API Analysis In Windows 1. JAVA JVM 0x1: JVM架构简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种

Jboss EAP:native management API学习

上一节已经学习了CLI命令行来控制JBOSS,如果想在程序中以编码方式来控制JBOSS,可以参考下面的代码,实际上在前面的文章,用代码控制Jboss上的DataSource,已经有所接触了,API与CLI是完全等价的,一个是人工敲指令,一个是代码控制,二者最终的效果一致. import com.sun.javafx.sg.PGShape; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.a

VC++玩转炫酷悬浮窗1---悬浮窗的实现

?? 目标实现像迅雷那样炫酷的悬浮窗.计划&方案首先第一步要实现一个悬浮窗,窗体无边框,能够随意拖动.对于一个窗体来说,只有我们把鼠标放到标题栏中才进入到拖拽模式.由于是无边框的窗体,默认是不能够移动的.我们尝试用两种办法使其跟随鼠标移动.一个是用OnNcHitTest函数,另一个是在OnLButtonDown时发消息.实践一. OnNcHitTest方案这个CWnd类的一个方法,我们可以捕捉鼠标点击的坐标,然后将其HTCLIENT结果偷换成HTCAPTION,这样就可以让系统误以为鼠标左键点击

React Native Networking API

p.p1 { margin: 0.0px 0.0px 2.0px 0.0px; font: 14.0px "Helvetica Neue"; color: #454545 } p.p2 { margin: 0.0px 0.0px 2.0px 0.0px; font: 14.0px ".PingFang SC"; color: #454545 } p.p3 { margin: 0.0px 0.0px 2.0px 0.0px; font: 14.0px "He

Android wifi无线调试App新玩法ADB WIFI

Wifi 调试App已经不是什么新鲜的事情了,之前也看过不少,不是使用麻烦就是需要root权限,今个我给大家介绍一款好用的android studio 插件--ADB WIFI. 安装 settings->plugins->Browse repositories 搜索框输入ADB WIFI找到插件,安装,重启android Studio后可以看到 导航菜单下Tools->Android->ADB WIFI就算安装成功了. 使用 第一步:首先还是需要用数据线连接电脑,如下图: 第二步

linux - native task api 测试

#include <stdio.h>#include <signal.h>#include <unistd.h>#include <sys/mman.h> #include <native/task.h>#include <native/timer.h> RT_TASK demo_task; /* NOTE: error handling omitted. */ void demo(void *arg){    RTIME now,