背景:
当应用程序需要管理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 <qt_windows.h> #include <wlanapi.h> #include <QString> #include <QMap> #include <QTimer> #include <qobject.h> #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<WifiNameAndQuality> 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<WifiNameAndQuality> m_lstSSIDToQuality; // wifi管理实例 static QWindowNativeWifi *m_pInstance; // 检测WIFI接口 QTimer m_queryTimer; }; #endif实现文件:
#include <map> #include "QWindowNativeWifi.h" using namespace std; static const QString STR_PROFILE_DEMO = "<?xml version=\"1.0\"?> \ <WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\">\ <name>Home</name>\ <SSIDConfig>\ <SSID>\ <name>Home</name>\ </SSID>\ </SSIDConfig>\ <connectionType>ESS</connectionType>\ <connectionMode>auto</connectionMode>\ <MSM>\ <security>\ <authEncryption>\ <authentication>WPA2PSK</authentication>\ <encryption>AES</encryption>\ <useOneX>false</useOneX>\ </authEncryption>\ <sharedKey>\ <keyType>passPhrase</keyType>\ <protected>false</protected>\ <keyMaterial>AAAAAA</keyMaterial>\ </sharedKey>\ </security>\ </MSM>\ </WLANProfile>"; 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<QString, int> hasMap; for (int i = 0; i < pNetList->dwNumberOfItems; ++i) { WLAN_AVAILABLE_NETWORK net = pNetList->Network[i]; strSSID = QString::fromUtf8(reinterpret_cast<char *>(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<WifiNameAndQuality> 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("<name>.*</name>"); regName.setMinimal(true); strProfile.replace(regName, QString("<name>%1</name>").arg(wifiName)); QRegExp regPassword("<keyMaterial>.*</keyMaterial>"); regPassword.setMinimal(true); strProfile.replace(regPassword, QString("<keyMaterial>%1</keyMaterial>").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; }