无线网编程之获取无线网列表

找了很久,终于找到怎么控制无线网卡了,也是走了不少弯路啊-_-||| WINDOWS SDK中有一系列用来WINDOWS编程的接口,其中有一个叫Native Wifi API ,来看下Windows Dev Center中Native Wifi的介绍(当下搬运工,简单翻一下~)

目的

本机WiFi自动配置组件配置,连接,以及从无线网络断开连接。本地无线上网的可以在其上与在XML文档的形式进行交互的网络的存储配置文件。

面向的开发者对象

Native Wifi API是专为C / C ++开发人员。程序员应该熟悉无线网络的概念和术语。

运行要求

Native Wifi的组件需要客户端(最低)是Windows Visita,Windows XP with Service Pack 3 (SP3)或Wireless LAN API for Windows XP with Service Pack 2 (SP2)。(原谅翻译之后还是满满的英文><)   Ok,先要下载WindwosSDK,我用的是WIN8.1+VS2010+.NET4,所以我下载的是Microsoft Windows SDK for Windows 7 and .NET Framework 4 版本主要应该是跟.NET的版本相关,如果是 .NET3.5 Windows SDK for Windows Server 2008 and .NET Framework 3.5     Windows Software Development Kit (SDK) for Windows 8 安装之前最好确认一下自己安装的Microsoft Visual C++ 2010 Redistributable的版本是不是10.0.40219,是的话就卸载,因为SDK要求的版本是10.0.30319,详情见当您安装 Windows 7 的 Windows SDK 和.NET Framework 4 时发生错误  卸载VC++2010版本不对的组件 安装好了之后,可以参考一下Native Wifi API Sample,文件在C:Program FilesMicrosoft SDKsWindows<version number>SamplesNetDsWlan目录下,像在我的电脑上次目录是C:Program FilesMicrosoft SDKsWindowsv7.1Samplesnetdswlan,还有很多其他的SDK示例哦~不过,由于结构太复杂,看了好半天就放弃了TT 直接去研究函数→→

第一个函数WlanEnumInterfaces

DWORD WINAPI WlanEnumInterfaces(
  _In_        HANDLE hClientHandle,
  _Reserved_  PVOID pReserved,
  _Out_       PWLAN_INTERFACE_INFO_LIST *ppInterfaceList
);

这个函数的作用是枚举可用的wlan的网络接口,简单说就是能把无线网卡枚举出来。 简单介绍一下参数:(继续做搬用工~)

hClientHandle [in]:一个客户会话句柄(通俗理解就是操作网卡所要用到的对象),用WlanOpenHandle函数获取。

pReserved [in]:保留用,设置为NULL

ppInterfaceList [out]:这个就是用来存放网卡的列表了,类型为WLAN_INTERFACE_INFO_LIST结构体,当然,如果WlanEnumlnterfaces函数调用成功的话。

简单讲一下,参数后面中括号里的in 和 out是传入值还是传出值的意思。在windows编程里,函数的返回值一般返回错误码,而需要的结果要预先申明(一般是结构体)变量,再传到函数里面,函数结束后,传入的变量就保存了需要的值。

返回值

函数调用成功,返回值是 ERROR_SUCCESS. 如果函数调用失败,可能是以下的枚举值:

Return code Description
ERROR_INVALID_PARAMETER
A parameter is incorrect. This error is returned if the hClientHandle or ppInterfaceList parameter is NULL. This error is returned if the pReserved is not NULL. This error is also returned if the hClientHandle parameter is not valid.  参数错误,有以下可能情况:hClientHandler是NULL(ppInterfaceList传入的时候就是NULL吧);pReserved不是NULL;hClientHandle是无效的。
ERROR_INVALID_HANDLE
The handle hClientHandle was not found in the handle table.  hClientHandle不存在(赋值不正确?调用WlanOpenHandle正确的话,感觉应该不会出这个错误吧~)
RPC_STATUS
Various error codes.  (这个不明白)
ERROR_NOT_ENOUGH_MEMORY
Not enough memory is available to process this request and allocate memory for the query results.  内存不够~~~ 

后面附了一段代码很重要,之后的操作基本上都是这个代码基础上改的

#ifndef UNICODE
#define UNICODE
#endif

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

#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")

int wmain()
{

    // Declare and initialize variables.

    HANDLE hClient = NULL;
    DWORD dwMaxClient = 2;   //    
    DWORD dwCurVersion = 0;
    DWORD dwResult = 0;
    int iRet = 0;

    WCHAR GuidString[40] = {0};

    int i;

    /* variables used for WlanEnumInterfaces  */

    PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
    PWLAN_INTERFACE_INFO pIfInfo = NULL;

    dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient); 
    if (dwResult != ERROR_SUCCESS)  {
        wprintf(L"WlanOpenHandle failed with error: %un", dwResult);
        // FormatMessage can be used to find out why the function failed
        return 1;
    }

    dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); 
    if (dwResult != ERROR_SUCCESS)  {
        wprintf(L"WlanEnumInterfaces failed with error: %un", dwResult);
        // FormatMessage can be used to find out why the function failed
        return 1;
    }
    else {
        wprintf(L"Num Entries: %lun", pIfList->dwNumberOfItems);
        wprintf(L"Current Index: %lun", pIfList->dwIndex);
        for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) {
            pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i];
            wprintf(L"  Interface Index[%d]:t %lun", i, i);
            iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, 39); 
            // For c rather than C++ source code, the above line needs to be
            // iRet = StringFromGUID2(&pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, 39); 
            if (iRet == 0)
                wprintf(L"StringFromGUID2 failedn");
            else {
                wprintf(L"  InterfaceGUID[%d]: %wsn",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 readyn");
                break;
            case wlan_interface_state_connected:
                wprintf(L"Connectedn");
                break;
            case wlan_interface_state_ad_hoc_network_formed:
                wprintf(L"First node in a ad hoc networkn");
                break;
            case wlan_interface_state_disconnecting:
                wprintf(L"Disconnectingn");
                break;
            case wlan_interface_state_disconnected:
                wprintf(L"Not connectedn");
                break;
            case wlan_interface_state_associating:
                wprintf(L"Attempting to associate with a networkn");
                break;
            case wlan_interface_state_discovering:
                wprintf(L"Auto configuration is discovering settings for the networkn");
                break;
            case wlan_interface_state_authenticating:
                wprintf(L"In process of authenticatingn");
                break;
            default:
                wprintf(L"Unknown state %ldn", pIfInfo->isState);
                break;
            }
            wprintf(L"n");
        }
    }

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

可以在VS里跑一下,输出的时候会出现中文无法显示的现象,这个include “locale.h”,然后在main里用setlocale( LC_ALL, “chs” )函数设置语言环境就OK了,后面还有更蛋疼的编码问题~~ 为了能获取到所有的无线网列表,开始以为是WlanScan函数(这个函数以后可能会有用),后来才发现应该是WlanGetAvailableNetworkList函数,还有一个很像的函数WlanGetNetworkBssList,不过不太懂basic service set (BSS)是什么意思。

来看下WlanGetAvailableNetworkList函数

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

这个函数的功能是检索可获取到的无线网列表,应该隐藏的就无法显示了。 看下参数→→

hClientHandle [in] :同WlanEnumInterfaces函数中的hClientHandle参数。

pInterfaceGuid [in]:百科说GUID是全局统一标识符的意思,这个值是从WlanEnumInterfaces函数返回的ppInterfaceList中获取的,详见WLAN_INTERFACE_INFO_LIST 结构体中的WLAN_INTERFACE_INFO结构体的InterfaceGUID变量。

dwFlags [in] :这个标志用来控制返回列表中网络的类型,有以下值

Value Meaning
WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES
0x00000001
Include all ad hoc network profiles in the available network list, including profiles that are not visible.  Note  If this flag is specified on Windows XP with SP3 and Wireless LAN API for Windows XP with SP2, it is consider considered an invalid parameter.
WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES
0x00000002
Include all hidden network profiles in the available network list, including profiles that are not visible.  Note  If this flag is specified on Windows XP with SP3 and Wireless LAN API for Windows XP with SP2, it is consider considered an invalid parameter. 

两个值都试过了,不知道区别。。大概意思是设置第一个值会返回所有Ad Hoc网络,包括隐藏简介(profiles配置?),而第二值会返回所有隐藏网络,包括隐藏简介(配置?)。

pReserved :保留,设置为NULL

ppAvailableNetworkList [out] :嘿嘿,这个就是我们需要的返回值了,WLAN_AVAILABLE_NETWORK_LIST结构体类型。 获取无线网的SSID我们要用到WLAN_AVAILABLE_NETWORK_LIST结构体中的WLAN_AVAILABLE_NETWORK结构体中的DOT11_SSID结构体中的ucSSID变量。嘿嘿(→_→)这是一个UCHAR类型的,想输出它的中文花了不少时间~~~

直接上代码,WIN32 CONSOLE APPLICATION

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>

#ifndef UNICODE
#define UNICODE
#endif

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

#include <stdlib.h>

// TODO: 在此处引用程序需要的其他头文件

#include "locale.h"//中文支持

// Need to link with Wlanapi.lib and Ole32.lib
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
// GetWlanList.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

//CHAR TO WCHAR把char转换成WCHAR的函数
WCHAR* ToWChar(char * str)
{ 
	static WCHAR buffer[1024];
	wcsset(buffer,0); 
	MultiByteToWideChar(CP_UTF8,0,str,strlen(str),buffer,1024); //CP_ACP是系统默认的Windows ANSI 编码,CP_UTF8是utf-8编码了,因为无线网编码是utf-8吧,编码折腾了好久啊~~
	return buffer;
} 

int wmain()
{
	setlocale( LC_ALL, "chs" );//设置语言环境
    // Declare and initialize variables.

    HANDLE hClient = NULL;
    DWORD dwMaxClient = 2;   //    支持的最高wlan api 版本//=2 Windows Vista and Windows Server 2008;=1 Windows XP with SP3 and Wireless LAN API for Windows XP with SP2.
    DWORD dwCurVersion = 0;
    DWORD dwResult = 0;
    int iRet = 0;

    WCHAR GuidString[40] = {0};//GUID 全局标识符

    int i;

    /* variables used for WlanEnumInterfaces  */

    PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
    PWLAN_INTERFACE_INFO pIfInfo = NULL;

	PWLAN_AVAILABLE_NETWORK_LIST ppAvailableNetworkList;//扫描结果列表
	PWLAN_AVAILABLE_NETWORK pNetwork;//网络信息

	UCHAR wlanSsid[256]={0};//网络名称

	//打开无线网客户端句柄
    dwResult = WlanOpenHandle(dwMaxClient, 
												NULL,
												&dwCurVersion, 
												&hClient); 
    if (dwResult != ERROR_SUCCESS)  {
        wprintf(L"WlanOpenHandle failed with error: %un", dwResult);
        // FormatMessage can be used to find out why the function failed
        return 1;
    }

	//枚举网卡
    dwResult = WlanEnumInterfaces(hClient, 
														NULL, 
														&pIfList); 
    if (dwResult != ERROR_SUCCESS)  {
        wprintf(L"WlanEnumInterfaces failed with error: %un", dwResult);
        // FormatMessage can be used to find out why the function failed
        return 1;
    }
    else {
        wprintf(L"Num Entries: %lun", pIfList->dwNumberOfItems);
        wprintf(L"Current Index: %lun", pIfList->dwIndex);
        for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) {//有几个无线网卡就循环几次
            pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i];
            wprintf(L"  Interface Index[%d]:t %lun", i, i);
            iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, 39); 
            // For c rather than C++ source code, the above line needs to be
            // iRet = StringFromGUID2(&pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, 39); 
            if (iRet == 0)
                wprintf(L"StringFromGUID2 failedn");
            else {
                wprintf(L"  InterfaceGUID[%d]: %wsn",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 readyn");
					break;
				case wlan_interface_state_connected:
					wprintf(L"Connectedn");
					break;
				case wlan_interface_state_ad_hoc_network_formed:
					wprintf(L"First node in a ad hoc networkn");
					break;
				case wlan_interface_state_disconnecting:
					wprintf(L"Disconnectingn");
					break;
				case wlan_interface_state_disconnected:
					wprintf(L"Not connectedn");
					break;
				case wlan_interface_state_associating:
					wprintf(L"Attempting to associate with a networkn");
					break;
				case wlan_interface_state_discovering:
					wprintf(L"Auto configuration is discovering settings for the networkn");
					break;
				case wlan_interface_state_authenticating:
					wprintf(L"In process of authenticatingn");
					break;
				default:
					wprintf(L"Unknown state %ldn", pIfInfo->isState);
					break;
            }
            wprintf(L"n");
        }
    }

	//扫描无线网
	dwResult= WlanGetAvailableNetworkList(hClient,
																	&pIfInfo->InterfaceGuid,
																	//WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,
																	WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES,
																	NULL,//保留
																	&ppAvailableNetworkList//返回列表
	);
    if (dwResult != ERROR_SUCCESS)  {
        wprintf(L"WlanGetAvailableNetworkList failed with error: %un", dwResult);
        // FormatMessage can be used to find out why the function failed
        return 1;
    }
    else {
        wprintf(L"Num Network: %lun", ppAvailableNetworkList->dwNumberOfItems);
        wprintf(L"Current Index: %lun", ppAvailableNetworkList->dwIndex);
        for (i = 0; i < (int) ppAvailableNetworkList->dwNumberOfItems; i++) {//有几个无线网卡就循环几次
            pNetwork = (WLAN_AVAILABLE_NETWORK *) &ppAvailableNetworkList->Network[i];
            wprintf(L"  Network Index[%d]:t %lun", i, i);
			wprintf(L"  Network SSID:t ");//貌似必须用循环??
			ZeroMemory( wlanSsid,sizeof(wlanSsid));
			for(int j=0;j<pNetwork->dot11Ssid.uSSIDLength;++j)
			{
				wlanSsid[j]+=pNetwork->dot11Ssid.ucSSID[j];
				//wprintf(L"%c",pNetwork->dot11Ssid.ucSSID[j]);
			}

			wprintf(L"%wsn",ToWChar((char *)wlanSsid));
			wprintf(L"  n");
		}
	}
    if (ppAvailableNetworkList!= NULL) {
        WlanFreeMemory(ppAvailableNetworkList);
        ppAvailableNetworkList= NULL;
    }
    if (pIfList != NULL) {
        WlanFreeMemory(pIfList);
        pIfList = NULL;
    }
	getchar();
    return 0;
}

运行结果 无线网络列表 最后简单讲一下编码问题,WINDOWS编程用UICODE编码。c++字符类型:UCHAR = usigned char=CHAR=char都是一个字节的,而WCHAR=wchar_t是两个字节的。用MultiByteToWideChar函数和WideCharToMultiByte 

《无线网编程之获取无线网列表》上有1条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据