要编码实现Soft AP,首先需要添加相应的头文件及lib库
代码如下 | 复制代码 |
#include #include #include #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "Wlanapi.lib") #pragma comment(lib, "IPHLPAPI.lib") |
其中,wlanapi.h是无线网络API的声明文件,函数名一般以Wlan开头。iphlpapi.h用于调用GetAdapterInfo函数,获取网络虚拟接口信息。
和winsock套接字编程类似,Wlan库使用前需获得句柄,并进行版本协商,只不过都在WlanOpenHandle实现了。使用完句柄后,调用WlanCloseHandle关闭以释放资源。
WlanOpenHandle原形如下:
代码如下 | 复制代码 |
DWORD WINAPI WlanOpenHandle( _In_ DWORD dwClientVersion, _Reserved_ PVOID pReserved, _Out_ PDWORD pdwNegotiatedVersion, _Out_ PHANDLE phClientHandle ); |
dwClientVersion指定程序期望使用的Wlan版本,使用宏WLAN_API_VERSION代替。从vista开始,版本号为2,xp系统为1。协商后的版本通过参数pdwNegotiatedVersion返回,通过检查主版本号来验证(如下代码所示)。句柄通过phClient返回。
代码如下 | 复制代码 |
DWORD dwError = 0; DWORD dwServiceVersion = 0; HANDLE hClient = NULL; if (ERROR_SUCCESS != (dwError = WlanOpenHandle( WLAN_API_VERSION, NULL, // reserved &dwServiceVersion, &hClient ))) { return -1; } // check service version if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0)) { WlanCloseHandle(hClient, NULL); } |
启动承载网络前,需要将模式配置为allow状态,并设置SSID和密码。可以调用WlanHostedNetworkSetProperty进行设置,WlanHostedNetworkSetProperty原型如下:
代码如下 | 复制代码 |
DWORD WINAPI WlanHostedNetworkSetProperty( _In_ HANDLE hClientHandle, _In_ WLAN_HOSTED_NETWORK_OPCODE OpCode, _In_ DWORD dwDataSize, _In_ PVOID pvData, _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, _Reserved_ PVOID pvReserved ); |
其中hClientHandle是我们之前调用WlanOpenHnadle获得的句柄;dwDataSize指定了pvData缓冲区的大小,而pvData指向的变量类型取决与OpCode的取值。OpCode为WLAN_HOSTED_NETWORK_OPCODE枚举,如果指定为wlan_hosted_network_opcode_enable,那么pvData传入一个BOOL型的变量指针,用于指示承载网络模式为允许还是禁止(allow/disallow);如果OpCode为wlan_hosted_network_opcode_connection_settings,那么pvData指向WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS结构体,指定承载网络的SSID和最大连接数目(peer count).
示例代码:
代码如下 | 复制代码 |
// 设置承载网络模式为允许 BOOL bIsAllow = TRUE; WLAN_HOSTED_NETWORK_REASON dwFailedReason; DWORD dwReturnValue = WlanHostedNetworkSetProperty(hWlanClient, wlan_hosted_network_opcode_enable, sizeof(BOOL), &bIsAllow, &dwFailedReason, NULL); if(ERROR_SUCCESS != dwReturnValue) { return -1; } // 设置承载网络的SSID和最大连接数 WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS wlanConnectionSetting; memset(&wlanConnectionSetting, 0, sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS)); // WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS中的SSID字段必须为ANSI类型,因此如果程序使用的是Unicode,则需要做转换。 #ifdef _UNICODE WideCharToMultiByte(CP_ACP, 0, strSSID.GetBuffer(0), // 保存SSID的CString类型 strSSID.GetLength(), // SSID字符串的长度 (LPSTR)wlanConnectionSetting.hostedNetworkSSID.ucSSID, 32, NULL, NULL); #else memcpy(wlanConnectionSetting.hostedNetworkSSID.ucSSID, strSSID.GetBuffer(0), strlen(strSSID.GetBuffer(0))); #endif wlanConnectionSetting.hostedNetworkSSID.uSSIDLength = strlen((const char*)wlanConnectionSetting.hostedNetworkSSID.ucSSID); wlanConnectionSetting.dwMaxNumberOfPeers = 100; dwReturnValue = WlanHostedNetworkSetProperty(m_hWlanClient, wlan_hosted_network_opcode_connection_settings, sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS), &wlanConnectionSetting, &dwFailedReason, NULL); if(ERROR_SUCCESS != dwReturnValue) { return -1; } |
调用WlanHostedNetworkSetSecondaryKey函数,设置承载网络的连接密码,函数原型如下:
代码如下 | 复制代码 |
DWORD WINAPI WlanHostedNetworkSetSecondaryKey( _In_ HANDLE hClientHandle, _In_ DWORD dwKeyLength, _In_ PUCHAR pucKeyData, _In_ BOOL bIsPassPhrase, _In_ BOOL bPersistent, _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, _Reserved_ PVOID pvReserved ); |
hClientHandle是我们之前调用WlanOpenHnadle获得的句柄;
bIsPassPhrase表明传入pucKeyData的密码是否为口令格式,如果是口令格式,则是8-63位的ASCII字符串,该参数设置为TRUE;如果为16进制的binary,参数设置为FALSE;
dwKeyLength是密码缓冲区的长度,密码为口令格式时,必须包括结尾的''
pucKeyData如果字符串,则必须为ANSI类型,因此如果IDE环境将字符串配置为UNICODE,需要做转换,可使用WideCharToMultiByte,或者T2A,W2A宏。
bPersistent用来指示密码是否是持久的。如果不是,那么该密码只在本次启动有效;否则下次启动Soft AP依然使用本次设置的密码。
示例代码:
代码如下 | 复制代码 |
UCHAR keyBuf[100] = {0}; #ifdef _UNICODE WideCharToMultiByte(CP_ACP, 0, strSecondaryKey.GetBuffer(0), strSecondaryKey.GetLength(), (LPSTR)keyBuf, 100, NULL, NULL); #else memcpy(keyBuf, strSecondaryKey.GetBuffer(0), strlen(strSecondaryKey.GetBuffer(0))); #endif dwReturnValue = WlanHostedNetworkSetSecondaryKey(m_hWlanClient, strlen((const char*)keyBuf) + 1, keyBuf, TRUE, FALSE, &dwFailedReason, NULL); if(ERROR_SUCCESS != dwReturnValue) { return -1; } |
启动或者停止Soft AP,需要用到如下四个函数:
代码如下 | 复制代码 |
DWORD WINAPI WlanHostedNetworkStartUsing( DWORD WINAPI WlanHostedNetworkStopUsing( |
参数的含义很直观,这里不再做更多地解释。值得注意的是,如果用StartUsing或者StopUsing版本的函数时,如果有客户端连接到了AP,调用WlanHostedNetworkStopUsing并不能立即停止Soft AP,而要等到客户端主动断开连接后,Soft AP才会停止。如果调用带Force的函数版本,则会强制停止Soft AP,不管是否有客户端正在连接到该AP上。当然,调用带Force的函数版本需要程序以管理员方式启动。
示例代码:
代码如下 | 复制代码 |
dwReturnValue = WlanHostedNetworkStartUsing(m_hWlanClient, &dwFailedReason, NULL); if(ERROR_SUCCESS != dwReturnValue) { if (wlan_hosted_network_reason_interface_unavailable == dwFailedReason) { return 0; } return -1; } dwReturnValue = WlanHostedNetworkStopUsing(m_hWlanClient, &dwFailedReason, NULL); if (ERROR_SUCCESS != dwReturnValue) { return -1; } |
启动Soft AP后,绑定Ip需要一定的时间,一般为2-3秒。Ip地址一般为192.168.173.1(也有可能是192.168.137.1).
调试程序时,可使用命令行方式使用Soft AP(管理员方式打开cmd):
查看当前承载网络状态 - netsh wlan show hostednetwork
配置承载网络属性,如SSID,密码等 - netsh wlan set hostednetwork ssid=***** key=***** mode=allow|disallow (星号部分为ascii字符,key必须在8-63个字符之间)
启动承载网络 - netsh wlan start hostednetwork
关闭承载网络 - netsh wlan stop hostednetwork