文章目录
- 前言
- 一、代码
- 二、补充知识
- 三、遇到的问题
- 字符集转换
- 四、剩余问题
- 总结
前言
出于项目需要,需要用C++开发一个wifi界面,实现wifi扫描、wifi连接与断开、wifi密码记住
的基础功能。
一、代码
话不多说,直接上代码。
#pragma once
#include <wlanapi.h>
#include <vector>
#include <string>
#include <shared_mutex>
#include "Utility/EncodingFormat/EncodingConversion.h"
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib")
/// <summary>
/// brief Record the wifi info that could be used
///
/// author Canliang Wu
/// Day 2023/12/20
/// </summary>
struct WifiInfo
{
GUID m_guid; // GUID(全局唯一标识符)是一个128位的唯一标识符,通常表示为32个十六进制数字的字符串。用于标识无线网络接口。每个接口都有一个唯一的 GUID,它可以用来区分计算机上的不同无线网络接口。
DOT11_BSS_TYPE m_dot11BssType; // WiFi网络的基本服务集类型
DOT11_AUTH_ALGORITHM m_authAlgo; // 默认的身份验证算法
DOT11_CIPHER_ALGORITHM m_cipherAlgo; // 默认的加密算法
std::wstring m_wifiName; // Wifi名称(Unicode 编码)
std::string m_wifiSSID; // 无线网络的 SSID (OEM 编码页)
int m_wifiIntensity = 0; // 信号强度,0 ~ 100
bool m_wifiConnected = false; // 目前是否连接
bool m_bHaveProfile = false; // 是否存在profile
};
enum class WifiMsg : char
{
Default = 0,
ScanComplete,
ScanFailed,
ConnectionSuccessful,
ConnectionFailed,
DisconnectionSuccessful,
DisconnectionFailed
};
class WifiManager
{
public:
WifiManager(){}
~WifiManager() { CloseWLAN(); }
public:
/*
* @brief Open the WLAN for getting client handle and registering notification
* @param hwnd - the parent handle for posting the message
* @param msgID - the message ID which parent window wants to receive
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool OpenWLAN(HWND hwnd, UINT msgID)
{
// 1. Prepare the parent info
m_parentHwnd = hwnd;
m_msgID = msgID;
// 2. Get WLAN client handle
DWORD dwNegotiatedVersion;
m_dwResult = WlanOpenHandle(1, nullptr, &dwNegotiatedVersion, &m_clientHandle);
if (m_dwResult != ERROR_SUCCESS)
{
CloseWLAN();
return false;
}
// 3. Register the message notification
if ((m_dwResult = WlanRegisterNotification(m_clientHandle, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, WLAN_NOTIFICATION_CALLBACK(onNotificationCallback), this, nullptr, nullptr)) != ERROR_SUCCESS)
{
CloseWLAN();
return false;
}
// 4. First scanning
if (!ScanWLAN())
return false;
return true;
}
/*
* @brief Close the WLAN
* @param hwnd - the parent handle for posting the message
* @param msgID - the message ID which parent window wants to receive
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool CloseWLAN()
{
if (m_clientHandle)
{
m_dwResult = WlanCloseHandle(m_clientHandle, nullptr);
if (m_dwResult == ERROR_SUCCESS)
{
m_clientHandle = NULL;
return true;
}
else
{
return false;
}
}
return true;
}
/*
* @brief Just scan the PC card and start scanning the avilable wifi list (We will receive the 'wlan_notification_acm_scan_complete' message in the next four seconds)
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool ScanWLAN()
{
#pragma region 1. Scan the PC card
PWLAN_INTERFACE_INFO_LIST pInterfaceList = NULL;
m_dwResult = WlanEnumInterfaces(m_clientHandle, nullptr, &pInterfaceList);
if (m_dwResult != ERROR_SUCCESS)
{
WlanFreeMemory(pInterfaceList);
CloseWLAN();
return false;
}
m_vGuid.clear();
for (unsigned int i = 0; i < (int)pInterfaceList->dwNumberOfItems; i++)
{
auto pIfInfo = (WLAN_INTERFACE_INFO*)&pInterfaceList->InterfaceInfo[i];
m_vGuid.push_back(pIfInfo->InterfaceGuid);
}
WlanFreeMemory(pInterfaceList);
#pragma endregion
#pragma region 2. Scan the avilable wifi list for each PC card
for (auto& guid : m_vGuid)
{
m_dwResult = WlanScan(m_clientHandle, &guid, NULL, NULL, NULL);
if (m_dwResult != ERROR_SUCCESS)
{
return false;
}
}
#pragma endregion
return true;
}
/*
* @brief Connect the wifi without password
* @param wifiInfo - current wifi info
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool ConnectWLANWithoutPassword(const WifiInfo& wifiInfo)
{
m_curWifiInfo = wifiInfo;
WLAN_CONNECTION_PARAMETERS wlanConnPara;
/*wlan_connection_mode_profile 将使用配置文件进行连接。
wlan_connection_mode_temporary_profile 将使用临时配置文件进行连接。
wlan_connection_mode_discovery_secure 安全发现将用于建立连接。
wlan_connection_mode_discovery_unsecure 将使用不安全的发现来建立连接。
wlan_connection_mode_auto 无线服务使用持久性配置文件自动启动连接。
wlan_connection_mode_invalid*/
wlanConnPara.wlanConnectionMode = wlan_connection_mode_profile;
wlanConnPara.strProfile = wifiInfo.m_wifiName.c_str();
wlanConnPara.pDot11Ssid = NULL; //设置为NULL时,会去配置有的ssid
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
m_dwResult = WlanConnect(m_clientHandle, &wifiInfo.m_guid, &wlanConnPara, NULL);
return m_dwResult == ERROR_SUCCESS;
}
/*
* @brief Connect the wifi with password
* @param wifiInfo - current wifi info
* @param password - the password
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool ConnectWLANWithPassword(const WifiInfo& wifiInfo, const std::wstring password)
{
// 1. Set the profile into system
if (!setProfile(wifiInfo, password))
return false;
// 2. Connect wifi
if (!ConnectWLANWithoutPassword(wifiInfo))
return false;
return true;
}
/*
* @brief Disconnect the wifi
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool Disconnect(const WifiInfo& wifiInfo)
{
m_dwResult = WlanDisconnect(m_clientHandle, &wifiInfo.m_guid, NULL);
return m_dwResult == ERROR_SUCCESS;
}
/*
* @brief Called from paranet window to get the wifi info list when it received the 'wlan_notification_acm_scan_complete' message
*
* @author Canliang Wu
* @day 2023/12/19
*/
void GetWifiInfoVec(std::vector<WifiInfo>& vWlanInfo)
{
std::shared_lock<std::shared_mutex> lock(m_mutex);
vWlanInfo = m_vWlanInfo;
}
/*
* @brief Get the error info
*
* @author Canliang Wu
* @day 2023/12/19
*/
std::string GetError()
{
std::string str_error = "Various error codes.";
switch (m_dwResult)
{
case ERROR_SUCCESS:
str_error = "SUCCESS.";
break;
case ERROR_INVALID_PARAMETER:
str_error = "One of the following conditions occurred:\n"
"hClientHandle is NULL or invalid.\n"
"pInterfaceGuid is NULL.\n"
"pConnectionParameters is NULL.\n"
"more:https://docs.microsoft.com/zh-cn/windows/win32/api/wlanapi/nf-wlanapi-wlanconnect.";
break;
case ERROR_NOT_ENOUGH_MEMORY:
str_error = "Failed to allocate memory to create the client context.";
break;
case ERROR_REMOTE_SESSION_LIMIT_EXCEEDED:
str_error = "Too many handles have been issued by the server.";
break;
case ERROR_INVALID_HANDLE:
str_error = "The handle hClientHandle was not found in the handle table.";
break;
case ERROR_NDIS_DOT11_POWER_STATE_INVALID:
str_error = "The radio associated with the interface is turned off. There are no available networks when the radio is off.";
break;
case ERROR_ACCESS_DENIED:
str_error = "The caller does not have sufficient permissions.";
break;
case ERROR_ALREADY_EXISTS:
str_error = "strProfileXml specifies a network that already exists.";
break;
case ERROR_BAD_PROFILE:
str_error = "The profile specified by strProfileXml is not valid. If this value is returned, pdwReasonCode specifies the reason the profile is invalid.";
break;
case ERROR_NO_MATCH:
str_error = "The interface does not support one or more of the capabilities specified in the profile.";
break;
default:
str_error = "Various error codes.";
break;
}
return str_error;
}
private:
/*
* @brief 消息回调,获取WLAN连接的各种状态提示
* @param data - NotificationSource 字段 对WLAN系统消息进行分类,NotificationCode表示系统消息的具体消息类型
* @param context - the param passed from the dialog register this function
*
* @author Canliang Wu
* @day 2023/12/19
*/
static void onNotificationCallback(PWLAN_NOTIFICATION_DATA data, PVOID context)
{
if (data != NULL && data->NotificationSource == WLAN_NOTIFICATION_SOURCE_ACM)
{
WifiManager* pWifiContext = reinterpret_cast<WifiManager*>(context);
if (!pWifiContext) return;
switch (data->NotificationCode)
{
case wlan_notification_acm_scan_complete:
{
pWifiContext->getAvailableNetworkList();
PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::ScanComplete), 0);
OutputDebugString(_T("Scan Successful\n"));
break;
}
case wlan_notification_acm_scan_fail:
{
DWORD* pScanFailReason = reinterpret_cast<DWORD*>(data->pData);
OutputDebugString(_T("Scan Failed\n"));
PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::ScanFailed), 0);
break;
}
case wlan_notification_acm_connection_start: break;
case wlan_notification_acm_connection_complete:
{
pWifiContext->ScanWLAN();
if (pWifiContext->queryConnectionStatus(pWifiContext->m_curWifiInfo.m_guid))
{
OutputDebugString(_T("Connection Successful\n"));
PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::ConnectionSuccessful), 0);
}
else
{
OutputDebugString(_T("Connection Failed\n"));
PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::ConnectionFailed), 0);
}
break;
}
case wlan_notification_acm_connection_attempt_fail:
{
//PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::ConnectionFailed), 0);
OutputDebugString(_T("Connection Attemp Failed\n"));
break;
}
case wlan_notification_acm_disconnecting: break;
case wlan_notification_acm_disconnected:
{
pWifiContext->ScanWLAN();
if (pWifiContext->queryConnectionStatus(pWifiContext->m_curWifiInfo.m_guid))
{
OutputDebugString(_T("Disconnection Failed\n"));
PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::DisconnectionFailed), 0);
}
else
{
OutputDebugString(_T("Disconnection Successful\n"));
PostMessage(pWifiContext->m_parentHwnd, pWifiContext->m_msgID, WPARAM(WifiMsg::DisconnectionSuccessful), 0);
}
break;
}
default:
break;
}
}
}
/*
* @brief Get avaliable network list after receiving the 'wlan_notification_acm_scan_complete' message
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool getAvailableNetworkList()
{
std::unique_lock<std::shared_mutex> lock(m_mutex);
m_vWlanInfo.clear();
for (auto& guid : m_vGuid)
{
PWLAN_AVAILABLE_NETWORK_LIST pWLAN_AVAILABLE_NETWORK_LIST = nullptr;
m_dwResult = WlanGetAvailableNetworkList(m_clientHandle, &guid, 2, nullptr, &pWLAN_AVAILABLE_NETWORK_LIST);
if (m_dwResult != ERROR_SUCCESS)
{
WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
CloseWLAN();
return false;
}
for (DWORD i = 0; i < pWLAN_AVAILABLE_NETWORK_LIST->dwNumberOfItems; i++)
{
WLAN_AVAILABLE_NETWORK& network = pWLAN_AVAILABLE_NETWORK_LIST->Network[i];
if (network.dot11Ssid.uSSIDLength != 0 )
{
std::string str_ssid((char*)network.dot11Ssid.ucSSID);
WifiInfo info;
info.m_guid = guid;
info.m_wifiSSID = str_ssid;
info.m_wifiName = EncodingConversion::UTF8ToUnicode(str_ssid);
info.m_wifiIntensity = (int)network.wlanSignalQuality;
info.m_wifiConnected = network.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED;
info.m_bHaveProfile = network.dwFlags & WLAN_AVAILABLE_NETWORK_HAS_PROFILE;
info.m_dot11BssType = network.dot11BssType;
info.m_authAlgo = network.dot11DefaultAuthAlgorithm;
info.m_cipherAlgo = network.dot11DefaultCipherAlgorithm;
// To fix the problem that have two same SSID when this wifi have profile temporarily(Canliang Wu, 2023/12/20)
std::wstring targetWifiName = info.m_wifiName;
auto it = std::find_if(m_vWlanInfo.begin(), m_vWlanInfo.end(), [targetWifiName](const WifiInfo& wifi) {
return wifi.m_wifiName == targetWifiName;
});
if (it == m_vWlanInfo.end())
{
m_vWlanInfo.push_back(info);
}
else
{
if (!it->m_bHaveProfile && info.m_bHaveProfile)
{
m_vWlanInfo.erase(it);
m_vWlanInfo.push_back(info);
}
}
}
}
WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
CString guidStr = guidToWstring(guid).c_str();
CString sizeStr;
sizeStr.Format(L"size = %d\n", m_vWlanInfo.size());
OutputDebugString(guidStr + _T(", ") + sizeStr);
}
return true;
}
/*
* @brief Convert to guid into wstring
*
* @author Canliang Wu
* @day 2023/12/19
*/
std::wstring guidToWstring(const GUID& guid) {
WCHAR buffer[39];
swprintf(buffer, L"%08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
return buffer;
}
/*
* @brief Set the new wifi profile into system
* @param wifiInfo - wifi info
* @param password - the password
*
* @author Canliang Wu
* @day 2023/12/19
*/
bool setProfile(const WifiInfo& wifiInfo, const std::wstring& password)
{
auto connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES);
auto opCode = wlan_opcode_value_type_invalid;
auto STR_NAME = L"WIFINAME";
auto STR_SSID = L"WIFISSID";
auto STR_PASSWORD = L"PASSWORD";
auto STR_CONNECTIONTYPE = L"CONNECTIONTYPE";
auto STR_AUTHENTICATION = L"AUTHENTICATION";
auto STR_ENCRYPTION = L"ENCRYPTION";
auto STR_PROFILE_DEMO =
L"<?xml version=\"1.0\"?> \
<WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\">\
<name>WIFINAME</name>\
<SSIDConfig>\
<SSID>\
<name>WIFISSID</name>\
</SSID>\
</SSIDConfig>\
<connectionType>CONNECTIONTYPE</connectionType>\
<connectionMode>auto</connectionMode>\
<MSM>\
<security>\
<authEncryption>\
<authentication>AUTHENTICATION</authentication>\
<encryption>ENCRYPTION</encryption>\
<useOneX>false</useOneX>\
</authEncryption>\
<sharedKey>\
<keyType>passPhrase</keyType>\
<protected>false</protected>\
<keyMaterial>PASSWORD</keyMaterial>\
</sharedKey>\
</security>\
</MSM>\
</WLANProfile>";
std::wstring strProfile = STR_PROFILE_DEMO;
stringReplace(strProfile, STR_NAME, wifiInfo.m_wifiName);
stringReplace(strProfile, STR_SSID, stringToWideChar(wifiInfo.m_wifiSSID));
stringReplace(strProfile, STR_PASSWORD, password);
switch (wifiInfo.m_dot11BssType)
{
case dot11_BSS_type_infrastructure:
stringReplace(strProfile, STR_CONNECTIONTYPE, L"ESS");
break;
case dot11_BSS_type_independent:
stringReplace(strProfile, STR_CONNECTIONTYPE, L"IBSS");
break;
case dot11_BSS_type_any:
stringReplace(strProfile, STR_CONNECTIONTYPE, L"ANY");
break;
default:
OutputDebugString(L"Unknown BSS Type");
return false;
}
switch (wifiInfo.m_authAlgo)
{
case DOT11_AUTH_ALGO_80211_OPEN:
stringReplace(strProfile, STR_AUTHENTICATION, L"open");
OutputDebugString(L"Open 802.11 authentication\n");
break;
case DOT11_AUTH_ALGO_80211_SHARED_KEY:
stringReplace(strProfile, STR_AUTHENTICATION, L"shared");
OutputDebugString(L"Shared 802.11 authentication");
break;
case DOT11_AUTH_ALGO_WPA:
stringReplace(strProfile, STR_AUTHENTICATION, L"WPA");
OutputDebugString(L"WPA-Enterprise 802.11 authentication\n");
break;
case DOT11_AUTH_ALGO_WPA_PSK:
stringReplace(strProfile, STR_AUTHENTICATION, L"WPAPSK");
OutputDebugString(L"WPA-Personal 802.11 authentication\n");
break;
case DOT11_AUTH_ALGO_WPA_NONE:
stringReplace(strProfile, STR_AUTHENTICATION, L"none");
OutputDebugString(L"WPA-NONE,not exist in MSDN\n");
break;
case DOT11_AUTH_ALGO_RSNA:
stringReplace(strProfile, STR_AUTHENTICATION, L"WPA2");
OutputDebugString(L"WPA2-Enterprise 802.11 authentication\n");
break;
case DOT11_AUTH_ALGO_RSNA_PSK:
stringReplace(strProfile, STR_AUTHENTICATION, L"WPA2PSK");
OutputDebugString(L"WPA2-Personal 802.11 authentication\n");
break;
case DOT11_AUTH_ALGO_WPA3:
stringReplace(strProfile, STR_AUTHENTICATION, L"WPA3");
break;
case DOT11_AUTH_ALGO_WPA3_SAE:
stringReplace(strProfile, STR_AUTHENTICATION, L"WPA3SAE");
break;
default:
OutputDebugString(L"Unknown authentication");
return false;
}
switch (wifiInfo.m_cipherAlgo)
{
case DOT11_CIPHER_ALGO_NONE:
stringReplace(strProfile, STR_ENCRYPTION, L"none");
break;
case DOT11_CIPHER_ALGO_WEP40:
stringReplace(strProfile, STR_ENCRYPTION, L"WEP");
break;
case DOT11_CIPHER_ALGO_TKIP:
stringReplace(strProfile, STR_ENCRYPTION, L"TKIP");
break;
case DOT11_CIPHER_ALGO_CCMP:
stringReplace(strProfile, STR_ENCRYPTION, L"AES");
break;
case DOT11_CIPHER_ALGO_WEP104:
stringReplace(strProfile, STR_ENCRYPTION, L"WEP");
break;
case DOT11_CIPHER_ALGO_WEP:
stringReplace(strProfile, STR_ENCRYPTION, L"WEP");
break;
case DOT11_CIPHER_ALGO_WPA_USE_GROUP:
OutputDebugString(L"USE-GROUP not exist in MSDN");
break;
default:
OutputDebugString(L"Unknown encryption");
return false;
}
WLAN_REASON_CODE Wlanreason;
m_dwResult = WlanSetProfile(m_clientHandle, &wifiInfo.m_guid, 0, strProfile.c_str(), NULL, true, NULL, &Wlanreason);
return m_dwResult == ERROR_SUCCESS;
}
/*
* @brief Replace specified characters in the string
* @param inputoutopt - the whole string
* @param oldStr - the characters in inputoutopt to be replaced
* @param newStr - the characters for replacing
*
* @author Canliang Wu
* @day 2023/12/19
*/
void stringReplace(std::wstring& inputoutopt, const std::wstring oldStr, const std::wstring newStr)
{
std::wstring::size_type pos = 0;
std::wstring::size_type a = oldStr.size();
std::wstring::size_type b = newStr.size();
while ((pos = inputoutopt.find(oldStr, pos)) != std::string::npos)
{
inputoutopt.replace(pos, a, newStr);
pos += b;
}
}
/*
* @brief Query the wifi connection state after receive the 'wlan_notification_acm_connection_complete ' message
* @param interfaceGuid - guid
*
* @author Canliang Wu
* @day 2023/12/20
*/
bool queryConnectionStatus(const GUID& interfaceGuid)
{
PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL;
DWORD connectInfoSize;
WLAN_OPCODE_VALUE_TYPE opCode;
m_dwResult = WlanQueryInterface(m_clientHandle, &interfaceGuid, wlan_intf_opcode_current_connection, nullptr, &connectInfoSize, (PVOID*)&pConnectInfo, &opCode);
bool bConnected = false;
if (m_dwResult == ERROR_SUCCESS)
{
if (pConnectInfo->isState == wlan_interface_state_connected)
{
bConnected = true;
}
}
if (pConnectInfo)
{
WlanFreeMemory(pConnectInfo);
}
return bConnected;
}
/*
* @brief Convert the multi byte string to wide byte string
* @note CP_OEMCP means keeping the string same code page with the system
*
* @author Canliang Wu
* @day 2023/12/21
*/
std::wstring stringToWideChar(const std::string pKey)
{
char* pCStrKey = const_cast<char*>(pKey.c_str());
//第一次调用返回转换后的字符串长度,用于确认为wchar_t*开辟多大的内存空间
int pSize = MultiByteToWideChar(CP_OEMCP, 0, pCStrKey, strlen(pCStrKey) + 1, NULL, 0);
wchar_t* pWCStrKey = new wchar_t[pSize];
//第二次调用将单字节字符串转换成双字节字符串
MultiByteToWideChar(CP_OEMCP, 0, pCStrKey, strlen(pCStrKey) + 1, pWCStrKey, pSize);
std::wstring res(pWCStrKey);
delete[] pWCStrKey;
pWCStrKey = nullptr;
return res;
}
private:
/// Client handle
HANDLE m_clientHandle = NULL;
/// Error code
DWORD m_dwResult = 0;
/// GUID vector
std::vector<GUID> m_vGuid;
/// Mutex for locking m_vWlanInfo
std::shared_mutex m_mutex;
/// Wifi info vector
std::vector<WifiInfo> m_vWlanInfo;
/// Current wifi info
WifiInfo m_curWifiInfo;
/// Post message
HWND m_parentHwnd;
UINT m_msgID;
};
二、补充知识
- 对于未连接过的wifi,系统的做法是,
先写入配置文件,然后再根据配置文件去连接
。这也是我代码中的做法。 - 配置文件路径在:
C:\ProgramData\Microsoft\Wlansvc\Profiles\Interfaces\{网卡GUID}\{Wifi GUID}.xml
,再通过Notepad++
打开可以看到明文信息。 - 通过管理员权限打开cmd,输入下面命令可以查看相关信息。
netsh wlan show profile // 列出所有的wifi profile
netsh wlan delete profile name="xxx" // 删除wifi名=xxx的profile
netsh wlan show profile name="xxx" key=clear // 显示wifi名=xxx的profile详细信息
三、遇到的问题
字符集转换
- 我们通过
std::string str_ssid((char*)network.dot11Ssid.ucSSID)
得到wifi名称,但此时是多字节字符串,项目需要的是宽字节字符串,所以通过EncodingConversion::UTF8ToUnicode(str_ssid)
转换为Unicode编码。 - 重新写到配置文件中,因为系统API需要的是宽字节字符串,但是如果直接使用
wifiInfo.m_wifiSSID
是错误的。因为它现在虽然是宽字节,但是却是Unicode字符集。而系统API需要的字符集则不确定,所以使用CP_OEMCP
将从系统出来的ssid转回系统需要的宽字节字符串。(说实话,这里我也不太理解,有更懂的小伙伴欢迎留言区评论!)
四、剩余问题
目前代码还剩下这些问题:
- Wifi连接时间要比直接通过系统连接来的长;
- 存在wifi名全为空白的现象(但是SSID len肯定不为0,因为上面有筛选。但是由于无法稳定找到那个空白wifi,所以也没去调试);
- 对于iphone手机热点,需要开启“最大兼容性”才可以连接成功,安卓手机则不需要。
- Wifi的总开关仍在系统,也就是需要桌面右下角开启WLAN才可以扫描wifi等操作。
总结
总之,我还是希望有人能够在我的基础上,修改存在的问题,并通知我!感谢!