Windows Native WIFI 编程

背景:

当应用程序需要管理WIFI连接时,可以利用Windows Native WIFI 进行编程,近期结合QT实现了MSDN上提供的各个接口。


关于具体的Native WIFI 编程参考以下链接:

           https://msdn.microsoft.com/en-us/library/windows/desktop/aa816369(v=vs.85).aspx

毕竟我是拿来主义。


具体的代码实现如下:

头文件

/*****************************************
功能: 本类利用Native wifi 编程,实现wifi连接功能,具体有以下功能:
	 1. 列举当前设备可用的无线接口,即无线网卡
	 2. 列举当前可用的无线网络
	 3. 查询当前连接的网络
	 4. 连接、断开网络
	 5. 实时刷新当前WIFI连接

	 本例中,WIFI名称和WIFI热点指同一个值

******************************************/
#ifndef Q_WINDOW_NATIVE_WIFI_H
#define Q_WINDOW_NATIVE_WIFI_H

#include 
#include 
#include 
#include 
#include 
#include 

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

struct WifiNameAndQuality
{
	WifiNameAndQuality()
	{

	}

	WifiNameAndQuality(QString strName, int nQuality)
	{
		m_strName = strName;
		m_nQuality = nQuality;
	}

	// 比较函数
	bool operator()(const WifiNameAndQuality &wifi1, const WifiNameAndQuality &wifi2)
	{
		if (wifi1.m_nQuality > wifi2.m_nQuality)
		{
			return true;
		}

		return false;
	}

	// WIFI 名称
	QString m_strName;

	// 信号强度
	int m_nQuality;
};


class QWindowNativeWifi: public QObject
{
	Q_OBJECT
public:
	
	// 获取wifi管理类
	static QWindowNativeWifi *instance();


    // 释放内存空间
	static void release();

	// 打开到服务端的连接
	// 返回值: 若成功返回ERROR_SUCCESS,否则返回失败的代码
	DWORD wlanOpenHandle();

	// 列举当前可用的无线网卡
	DWORD wlanEnumInterfaces();

	// 通过WlanQueryInterface函数,查询当前接口连接的无线网络
	DWORD wlanQueryInterface();

	// 对某一无线网卡进行扫描,也就是重新扫描是否有可用无线网络
	DWORD wlanScan();

	// 列举出当前网络接口的可用无线网络
	DWORD wlanGetAvailableNetworkList();

	// 返回当前可用的无线网络
	std::list getNets() const;

	// 获取每一个WIFI配置文件
	// 参数: wifiName 无线网络名称
	DWORD wlanGetProfile(const QString &wifiName);

	// 设置wifi的配置文件
	// 参数:  wifiName 无线网络名称
	//       strPassword 无线网络的密码
	//       wcProfile xml格式的配置文件
	DWORD wlanSetProfile(const QString &wifiName,  const QString &strPassword, const wchar_t * wcProfile = NULL);

	// 删除wifi的配置文件
	// 参数: wifiName 无线网络名称
	DWORD wlanDeleteProfile(const QString &wifiName);

	// 连接无线网络
	// 参数: wifiName 无线网络名称
	DWORD wlanConnect(const QString &wifiName);

	// 当前连接的WIFI
	QString getCurrName() const;
signals:

	// 当前连接的WIFI接口状态及连接的无线名称
	void sigIfStatusAndWifiName(WLAN_INTERFACE_STATE state, const QString &apName);

private slots:
	// 实时监测WIFI连接情况
	void slotQueryWifi();

private:

	QWindowNativeWifi(QObject *pParent = NULL);

	~QWindowNativeWifi();
private:
	
	// 到服务端的连接
	HANDLE m_pHandle;
	
	// 当前的网络接口,即网卡
	GUID m_interfaceGUID;

	// 当前接口是否连接WIFI了
	WLAN_INTERFACE_STATE m_ifState;

	// 当前连接的WIFI名称
	QString m_strAPName;
	
	// 当前连接的WIFI名称
	DOT11_SSID m_currSSID;

	// 当前可用WIFI列表及其强度
	std::list m_lstSSIDToQuality;

	// wifi管理实例
	static QWindowNativeWifi *m_pInstance;

	// 检测WIFI接口
	QTimer m_queryTimer;
};

#endif

实现文件:

#include 
#include "QWindowNativeWifi.h"

using namespace std;

static const QString STR_PROFILE_DEMO = 
" \
\
	Home\
	\
		\
			Home\
		\
	\
	ESS\
	auto\
	\
		\
			\
				WPA2PSK\
				AES\
				false\
			\
			\
				passPhrase\
				false\
				AAAAAA\
			\
		\
	\
";

QWindowNativeWifi * QWindowNativeWifi::m_pInstance = NULL;

QWindowNativeWifi::QWindowNativeWifi(QObject *pParent)
	:QObject(pParent)
{
	m_pHandle = INVALID_HANDLE_VALUE;

	m_queryTimer.setInterval(5 * 1000);
	m_queryTimer.start();
	connect(&m_queryTimer, &QTimer::timeout, this, &QWindowNativeWifi::slotQueryWifi);
}


QWindowNativeWifi::~QWindowNativeWifi()
{
	if (m_pHandle != INVALID_HANDLE_VALUE)
	{
		WlanCloseHandle(m_pHandle, NULL);
	}
}

QWindowNativeWifi * QWindowNativeWifi::instance()
{
	if (NULL == m_pInstance)
	{
		m_pInstance = new QWindowNativeWifi();
	}

	m_pInstance->wlanOpenHandle();
	m_pInstance->wlanEnumInterfaces();
	m_pInstance->wlanScan();
	m_pInstance->wlanQueryInterface();

	return m_pInstance;
}

void QWindowNativeWifi::release()
{
	if (m_pInstance != NULL)
	{
		delete m_pInstance;
		m_pInstance = NULL;
	}
}

DWORD QWindowNativeWifi::wlanOpenHandle()
{
	// 先决条件
	if (INVALID_HANDLE_VALUE != m_pHandle)
	{
		return 0;
	}

	DWORD dwMaxClient = 2;      //    
	DWORD dwCurVersion = 0;
	// 参照:https://msdn.microsoft.com/en-us/library/windows/desktop/ms706759(v=vs.85).aspx
	DWORD dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &m_pHandle);
	
	return dwResult;
}

DWORD QWindowNativeWifi::wlanEnumInterfaces()
{
	// 先决条件判断
	if (INVALID_HANDLE_VALUE  == m_pHandle)
	{
		return -1;
	}

	// 参照:https://msdn.microsoft.com/en-us/library/windows/desktop/ms706716(v=vs.85).aspx
	PWLAN_INTERFACE_INFO_LIST ppIfList = NULL;
	DWORD dwResult = WlanEnumInterfaces(
		m_pHandle,
		NULL,
		&ppIfList
		);

	if (ERROR_SUCCESS == dwResult && ppIfList)
	{
		for (int i = 0; i< ppIfList->dwNumberOfItems; ++i)
		{
			memcpy(&m_interfaceGUID, &(ppIfList->InterfaceInfo[i].InterfaceGuid), sizeof(GUID));
			m_ifState = ppIfList->InterfaceInfo[i].isState;
			break;
		}
	}

	return dwResult;
}

DWORD QWindowNativeWifi::wlanQueryInterface()
{
	// 先决条件判断
	if (INVALID_HANDLE_VALUE == m_pHandle)
	{
		return -1;
	}

	DWORD dwSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
	PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
	WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid;
	// wlan_intf_opcode_current_connection 当前接口的连接状况
	DWORD dwResult = WlanQueryInterface(
		m_pHandle,
		&m_interfaceGUID,
		wlan_intf_opcode_current_connection,
		NULL,
		&dwSize,
		(PVOID *)&pConnectInfo,
		&opCode);


	if (ERROR_SUCCESS == dwResult && pConnectInfo)
	{
		m_currSSID = pConnectInfo->wlanAssociationAttributes.dot11Ssid;
		m_strAPName.clear();
		for (int k = 0; k < m_currSSID.uSSIDLength; k++)
		{
			m_strAPName.append(m_currSSID.ucSSID[k]);
		}
	}

	if (pConnectInfo)
	{
		WlanFreeMemory(pConnectInfo);
		pConnectInfo = NULL;
	}


	emit sigIfStatusAndWifiName(m_ifState, m_strAPName);

	return dwResult;
}

void QWindowNativeWifi::slotQueryWifi()
{
	if (m_pHandle != INVALID_HANDLE_VALUE)
	{
		WlanCloseHandle(m_pHandle, NULL);
	}
	m_pHandle = INVALID_HANDLE_VALUE;
	wlanOpenHandle();
	wlanEnumInterfaces();
	wlanScan();
	wlanQueryInterface();
}

DWORD QWindowNativeWifi::wlanScan()
{
	// 先决条件判断
	if (INVALID_HANDLE_VALUE == m_pHandle || m_ifState != wlan_interface_state_connected)
	{
		return -1;
	}

	PWLAN_RAW_DATA pIeData = new WLAN_RAW_DATA;
	memset(pIeData, 0x00, sizeof(WLAN_RAW_DATA));
	DWORD dwResult = WlanScan(
		m_pHandle,
		&m_interfaceGUID,
		&m_currSSID,
		pIeData,
		NULL
		);

	return dwResult;
}

DWORD QWindowNativeWifi::wlanGetAvailableNetworkList()
{
	// 先决条件判断
	if (INVALID_HANDLE_VALUE == m_pHandle)
	{
		return -1;
	}

	m_lstSSIDToQuality.clear();

	PWLAN_AVAILABLE_NETWORK_LIST pNetList = NULL;
	DWORD dwResult = WlanGetAvailableNetworkList(
		m_pHandle,
		&m_interfaceGUID,
		WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_ADHOC_PROFILES,
		NULL,
		&pNetList
		);


	if (ERROR_SUCCESS == dwResult && pNetList && pNetList->dwNumberOfItems)
	{
		QString strSSID;
		int nQuality = 0;
		
		map hasMap;
		for (int i = 0; i < pNetList->dwNumberOfItems; ++i)
		{
			WLAN_AVAILABLE_NETWORK net = pNetList->Network[i];
			strSSID = QString::fromUtf8(reinterpret_cast(net.dot11Ssid.ucSSID),
				net.dot11Ssid.uSSIDLength);

			// 是否可连接
			if (!net.bNetworkConnectable || hasMap.end() != hasMap.find(strSSID))
			{
				continue;
			}

			WifiNameAndQuality nameQuality(strSSID, net.wlanSignalQuality);
			hasMap[strSSID] = nameQuality.m_nQuality;
			m_lstSSIDToQuality.push_back(nameQuality);
		}

		// 按照信号强度进行排序
		m_lstSSIDToQuality.sort(WifiNameAndQuality());
	}

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

	return dwResult;
}

std::list QWindowNativeWifi::getNets() const
{
	return m_lstSSIDToQuality;
}

// 当前连接的WIFI
QString QWindowNativeWifi::getCurrName() const
{
	return m_strAPName;
}

DWORD QWindowNativeWifi::wlanGetProfile(const QString &wifiName)
{
	wchar_t wifi[MAX_PATH] = {};
	wifiName.toWCharArray(wifi);

	wchar_t *profileXml = NULL;
	DWORD dwFlags = WLAN_PROFILE_GET_PLAINTEXT_KEY;
	DWORD  dwGrantedAccess = WLAN_WRITE_ACCESS;
	DWORD dwResult = WlanGetProfile(
		m_pHandle,
		&m_interfaceGUID,
		wifi,
		NULL,
		&profileXml,
		&dwFlags,
		&dwGrantedAccess
		);

	// 如果成功时,但没有获得profile配置文件,则设置profile
	if (ERROR_SUCCESS == dwResult && NULL == profileXml)
	{
		dwResult = -1;
	}

	return dwResult;
}

DWORD QWindowNativeWifi::wlanSetProfile(const QString &wifiName, const QString &password, const wchar_t * wcProfile)
{
	// 先决条件
	if (wifiName.isEmpty())
	{
		return -1;
	}

	wchar_t profile[1024] = {};
	
	// 生成profile
	QString strProfile = STR_PROFILE_DEMO;
	QRegExp regName(".*");
	regName.setMinimal(true);
	strProfile.replace(regName, QString("%1").arg(wifiName));
	QRegExp regPassword(".*");
	regPassword.setMinimal(true);
	strProfile.replace(regPassword, QString("%1").arg(password));

	strProfile.toWCharArray(profile);

	DWORD dwReasonCode = 0;
	DWORD dwResult  = WlanSetProfile(
		m_pHandle,
		&m_interfaceGUID,
		0,
		profile,
		NULL,
		TRUE,
		NULL,
		&dwReasonCode
		);
	
	// 密码错误返回 ERROR_BAD_PROFILE
	if (ERROR_SUCCESS == dwResult)
	{
	}

	return dwResult;
}

DWORD QWindowNativeWifi::wlanDeleteProfile(const QString &wifiName)
{
	wchar_t wifi[MAX_PATH] = {};
	wifiName.toWCharArray(wifi);
	DWORD dwResult =  WlanDeleteProfile(
		m_pHandle,
		&m_interfaceGUID,
		wifi,
		NULL
		);

	if (ERROR_SUCCESS == dwResult)
	{
	}

	return dwResult;

}

DWORD QWindowNativeWifi::wlanConnect(const QString &wifiName)
{
	wchar_t wifi[MAX_PATH] = {};
	wifiName.toWCharArray(wifi);

	WLAN_CONNECTION_PARAMETERS param;
	memset(¶m, 0x00, sizeof(WLAN_CONNECTION_PARAMETERS));
	param.wlanConnectionMode = wlan_connection_mode_profile;
	param.strProfile = wifi;
	param.pDot11Ssid = NULL;
	//param.pDesiredBssidList = NULL;
	param.dot11BssType = dot11_BSS_type_infrastructure;
	param.dwFlags = WLAN_CONNECTION_HIDDEN_NETWORK;

	DWORD dwResult =  WlanConnect(
		m_pHandle,
		&m_interfaceGUID,
		¶m,
		NULL);

	if (ERROR_SUCCESS == dwResult)
	{
	}

	return dwResult;
}

你可能感兴趣的:(Windows Native WIFI 编程)