從Windows 7開始,微軟在操作系統中加入的Soft AP功能,使用戶能夠通過無線網卡,開啟虛擬AP,從而實現網絡共享。Soft AP又稱HostedNetwork(承載網絡),在Windows SDK中,提供了相應的API,以WlanHostedNetwork***開頭的一系列函數。
要編碼實現Soft AP,首先需要添加相應的頭文件及lib庫
1 #include <wlanapi.h> 2 #include <iphlpapi.h> 3 #include <winsock2.h> 4 #pragma comment(lib, "ws2_32.lib") 5 #pragma comment(lib, "Wlanapi.lib") 6 #pragma comment(lib, "IPHLPAPI.lib"
其中,wlanapi.h是無線網絡API的聲明文件,函數名一般以Wlan開頭。iphlpapi.h用於調用GetAdapterInfo函數,獲取網絡虛擬接口信息。
和winsock套接字編程類似,Wlan庫使用前需獲得句柄,並進行版本協商,只不過都在WlanOpenHandle實現了。使用完句柄后,調用WlanCloseHandle關閉以釋放資源。
WlanOpenHandle原形如下:
1 DWORD WINAPI WlanOpenHandle( 2 _In_ DWORD dwClientVersion, 3 _Reserved_ PVOID pReserved, 4 _Out_ PDWORD pdwNegotiatedVersion, 5 _Out_ PHANDLE phClientHandle 6 );
dwClientVersion指定程序期望使用的Wlan版本,使用宏WLAN_API_VERSION代替。從vista開始,版本號為2,xp系統為1。協商后的版本通過參數pdwNegotiatedVersion返回,通過檢查主版本號來驗證(如下代碼所示)。句柄通過phClient返回。
1 DWORD dwError = 0; 2 DWORD dwServiceVersion = 0; 3 HANDLE hClient = NULL; 4 5 if (ERROR_SUCCESS != (dwError = WlanOpenHandle( 6 WLAN_API_VERSION, 7 NULL, // reserved 8 &dwServiceVersion, 9 &hClient 10 ))) 11 { 12 return -1; 13 } 14 15 // check service version 16 if (WLAN_API_VERSION_MAJOR(dwServiceVersion) < WLAN_API_VERSION_MAJOR(WLAN_API_VERSION_2_0)) 17 { 18 WlanCloseHandle(hClient, NULL); 19 }
啟動承載網絡前,需要將模式配置為allow狀態,並設置SSID和密碼。可以調用WlanHostedNetworkSetProperty進行設置,WlanHostedNetworkSetProperty原型如下:
1 DWORD WINAPI WlanHostedNetworkSetProperty( 2 _In_ HANDLE hClientHandle, 3 _In_ WLAN_HOSTED_NETWORK_OPCODE OpCode, 4 _In_ DWORD dwDataSize, 5 _In_ PVOID pvData, 6 _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, 7 _Reserved_ PVOID pvReserved 8 );
其中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).
示例代碼:
1 // 設置承載網絡模式為允許 2 BOOL bIsAllow = TRUE; 3 WLAN_HOSTED_NETWORK_REASON dwFailedReason; 4 DWORD dwReturnValue = WlanHostedNetworkSetProperty(hWlanClient, 5 wlan_hosted_network_opcode_enable, 6 sizeof(BOOL), 7 &bIsAllow, 8 &dwFailedReason, 9 NULL); 10 11 if(ERROR_SUCCESS != dwReturnValue) 12 { 13 return -1; 14 } 15 16 17 18 19 // 設置承載網絡的SSID和最大連接數 20 WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS wlanConnectionSetting; 21 memset(&wlanConnectionSetting, 0, sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS)); 22 23 // WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS中的SSID字段必須為ANSI類型,因此如果程序使用的是Unicode,則需要做轉換。 24 #ifdef _UNICODE 25 WideCharToMultiByte(CP_ACP, 26 0, 27 strSSID.GetBuffer(0), // 保存SSID的CString類型 28 strSSID.GetLength(), // SSID字符串的長度 29 (LPSTR)wlanConnectionSetting.hostedNetworkSSID.ucSSID, 30 32, 31 NULL, 32 NULL); 33 #else 34 memcpy(wlanConnectionSetting.hostedNetworkSSID.ucSSID, strSSID.GetBuffer(0), strlen(strSSID.GetBuffer(0))); 35 #endif 36 37 wlanConnectionSetting.hostedNetworkSSID.uSSIDLength = strlen((const char*)wlanConnectionSetting.hostedNetworkSSID.ucSSID); 38 wlanConnectionSetting.dwMaxNumberOfPeers = 100; 39 40 dwReturnValue = WlanHostedNetworkSetProperty(m_hWlanClient, 41 wlan_hosted_network_opcode_connection_settings, 42 sizeof(WLAN_HOSTED_NETWORK_CONNECTION_SETTINGS), 43 &wlanConnectionSetting, 44 &dwFailedReason, 45 NULL); 46 if(ERROR_SUCCESS != dwReturnValue) 47 { 48 return -1; 49 }
調用WlanHostedNetworkSetSecondaryKey函數,設置承載網絡的連接密碼,函數原型如下:
1 DWORD WINAPI WlanHostedNetworkSetSecondaryKey( 2 _In_ HANDLE hClientHandle, 3 _In_ DWORD dwKeyLength, 4 _In_ PUCHAR pucKeyData, 5 _In_ BOOL bIsPassPhrase, 6 _In_ BOOL bPersistent, 7 _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, 8 _Reserved_ PVOID pvReserved 9 );
hClientHandle是我們之前調用WlanOpenHnadle獲得的句柄;
bIsPassPhrase表明傳入pucKeyData的密碼是否為口令格式,如果是口令格式,則是8-63位的ASCII字符串,該參數設置為TRUE;如果為16進制的binary,參數設置為FALSE;
dwKeyLength是密碼緩沖區的長度,密碼為口令格式時,必須包括結尾的'\0'
pucKeyData如果字符串,則必須為ANSI類型,因此如果IDE環境將字符串配置為UNICODE,需要做轉換,可使用WideCharToMultiByte,或者T2A,W2A宏。
bPersistent用來指示密碼是否是持久的。如果不是,那么該密碼只在本次啟動有效;否則下次啟動Soft AP依然使用本次設置的密碼。
示例代碼:
1 UCHAR keyBuf[100] = {0}; 2 #ifdef _UNICODE 3 WideCharToMultiByte(CP_ACP, 4 0, 5 strSecondaryKey.GetBuffer(0), 6 strSecondaryKey.GetLength(), 7 (LPSTR)keyBuf, 8 100, 9 NULL, 10 NULL); 11 #else 12 memcpy(keyBuf, strSecondaryKey.GetBuffer(0), strlen(strSecondaryKey.GetBuffer(0))); 13 #endif 14 dwReturnValue = WlanHostedNetworkSetSecondaryKey(m_hWlanClient, 15 strlen((const char*)keyBuf) + 1, 16 keyBuf, 17 TRUE, 18 FALSE, 19 &dwFailedReason, 20 NULL); 21 if(ERROR_SUCCESS != dwReturnValue) 22 { 23 return -1; 24 }
啟動或者停止Soft AP,需要用到如下四個函數:
1 DWORD WINAPI WlanHostedNetworkStartUsing( 2 _In_ HANDLE hClientHandle, 3 _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, 4 _Reserved_ PVOID pvReserved 5 ); 6 7 8 DWORD WINAPI WlanHostedNetworkStopUsing( 9 _In_ HANDLE hClientHandle, 10 _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, 11 _Reserved_ PVOID pvReserved 12 ); 13 14 DWORD WINAPI WlanHostedNetworkForceStart( 15 _In_ HANDLE hClientHandle, 16 _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, 17 _Reserved_ PVOID pvReserved 18 ); 19 20 DWORD WINAPI WlanHostedNetworkForceStop( 21 _In_ HANDLE hClientHandle, 22 _Out_opt_ PWLAN_HOSTED_NETWORK_REASON pFailReason, 23 _Reserved_ PVOID pvReserved 24 );
參數的含義很直觀,這里不再做更多地解釋。值得注意的是,如果用StartUsing或者StopUsing版本的函數時,如果有客戶端連接到了AP,調用WlanHostedNetworkStopUsing並不能立即停止Soft AP,而要等到客戶端主動斷開連接后,Soft AP才會停止。如果調用帶Force的函數版本,則會強制停止Soft AP,不管是否有客戶端正在連接到該AP上。當然,調用帶Force的函數版本需要程序以管理員方式啟動。
示例代碼:
1 dwReturnValue = WlanHostedNetworkStartUsing(m_hWlanClient, &dwFailedReason, NULL); 2 if(ERROR_SUCCESS != dwReturnValue) 3 { 4 if (wlan_hosted_network_reason_interface_unavailable == dwFailedReason) 5 { 6 return 0; 7 } 8 return -1; 9 } 10 11 dwReturnValue = WlanHostedNetworkStopUsing(m_hWlanClient, &dwFailedReason, NULL); 12 if (ERROR_SUCCESS != dwReturnValue) 13 { 14 return -1; 15 }
啟動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
如果本文對你有幫助,可以考慮捐贈以支持作者。
比特幣地址: 1NPXhyv9W1tcqQc8iiSgx4YyPYbfoLSVzf
萊特幣地址: LSXEAZt67sdpBjZ7yhvTpPUjy6hZKivYph