C++法式中應用Windows體系Native Wifi API的根本教程。本站提示廣大學習愛好者:(C++法式中應用Windows體系Native Wifi API的根本教程)文章只能為提供參考,不一定能成為您想要的結果。以下是C++法式中應用Windows體系Native Wifi API的根本教程正文
Windows運用想要完成銜接wifi,監聽wifi旌旗燈號,斷開銜接等功效,用NativeWifi API是個不錯的選擇。
翻開MSDN,搜刮NativeWifi Api,找到Native Wifi頁。在這裡。
信息量很年夜,假如像我焦急完成上述功效,看海量的文檔有些來不及。假如直接給我例子,在運轉中調試,浏覽代碼,效力會更高。
然則,我並沒有勝利。起首,Sample在SDK中,拜見這裡。我下載幾回都掉敗了,最初廢棄這條路。後來同事給了我一份Sample,我不敢肯定能否就是這個,然則代碼寫的也是很艱澀。我的初志是簡略的應用這些API的例子。
看來照樣本身著手吧。看相干API,假如不懂,就找有經歷人的例子。
幾經周折,終究完成我的需求。讓我漸漸道來。
1.取得可用AP列表
拜見WlanGetAvailableNetworkList的官方文檔,上面有例子。
DWORD WINAPI WlanGetAvailableNetworkList( _In_ HANDLE hClientHandle, _In_ const GUID *pInterfaceGuid, _In_ DWORD dwFlags, _Reserved_ PVOID pReserved, _Out_ PWLAN_AVAILABLE_NETWORK_LIST *ppAvailableNetworkList );
由可用列表即可以找到以後哪一個AP正在銜接,並顯示旌旗燈號強度。
2.監聽以後銜接
在取得可用AP列表的基本上,遍歷以後AP,看誰正在銜接,並獲得它的旌旗燈號。代碼片斷以下:
bool isConnect = false; int numberOfItems = pWLAN_AVAILABLE_NETWORK_LIST->dwNumberOfItems; for(int i = 0; i <= numberOfItems; i++) { WLAN_AVAILABLE_NETWORK wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[i]; if(wlanAN.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { Wprintf(WLAN signal is %s:%d\n", wlanAN.strProfileName, wlanAN.wlanSignalQuality); isConnect = true; } } if(!isConnect){ wprintf("Wifi is disconnected!\n");}
3.斷開銜接
假如wifi處於銜接狀況,將其斷開。WlanDisconnect照樣輕易應用的。原型以下:
DWORD WINAPI WlanDisconnect( _In_ HANDLE hClientHandle, _In_ const GUID *pInterfaceGuid, _Reserved_ PVOID pReserved );
代碼演示在前面。
4.銜接一個有profile的AP(已保留過暗碼)
這是本文的重點。
固然銜接函數WlanConnect原型很簡略:
DWORD WINAPI WlanConnect( _In_ HANDLE hClientHandle, _In_ const GUID *pInterfaceGuid, _In_ const PWLAN_CONNECTION_PARAMETERS pConnectionParameters, _Reserved_ PVOID pReserved );但參數PWLAN_CONNECTION_PARAMETERS倒是很龐雜,只需有一個配錯,銜接就會掉敗。
typedef struct _WLAN_CONNECTION_PARAMETERS { WLAN_CONNECTION_MODE wlanConnectionMode; LPCWSTR strProfile; PDOT11_SSID pDot11Ssid; PDOT11_BSSID_LIST pDesiredBssidList; DOT11_BSS_TYPE dot11BssType; DWORD dwFlags; } WLAN_CONNECTION_PARAMETERS, *PWLAN_CONNECTION_PARAMETERS;
為了完成我的請求,可以如許賦值:
wlanConnectionMode這裡設成wlan_connection_mode_profile;
strProfile寫上你要銜接ap的稱號(平日是profile稱號);
pDot11Ssid用不上,設置NULL;
pDesiredBssidList異樣置成NULL;
dot11BssType我給設成dot11_BSS_type_infrastructure(基本舉措措施?);
dwFlags設置為WLAN_CONNECTION_HIDDEN_NETWORK。
確切是任務了,strProfile若何獲得呢?拜見監聽銜接旌旗燈號中對可用AP列表中第一個profile的獲得。
完全代碼以下:
// #include "stdafx.h" #include <windows.h> #include <wlanapi.h> #include <objbase.h> #include <wtypes.h> #include <string> #include <stdio.h> #include <stdlib.h> // Need to link with Wlanapi.lib and Ole32.lib #pragma comment(lib, "wlanapi.lib") #pragma comment(lib, "ole32.lib") using namespace std; int listenStatus() { HANDLE hClient = NULL; DWORD dwMaxClient = 2; DWORD dwCurVersion = 0; DWORD dwResult = 0; DWORD dwRetVal = 0; int iRet = 0; WCHAR GuidString[39] = {0}; //Listen the status of the AP you connected. while(1){ Sleep(5000); PWLAN_INTERFACE_INFO_LIST pIfList = NULL;//I think wlan interface means network card PWLAN_INTERFACE_INFO pIfInfo = NULL; DWORD dwFlags = 0; dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult); return 1; } dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult); return 1; } else { wprintf(L"WLAN_INTERFACE_INFO_LIST for this system\n"); wprintf(L"Num Entries: %lu\n", pIfList->dwNumberOfItems); wprintf(L"Current Index: %lu\n\n", pIfList->dwIndex); int i; for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) { pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i]; wprintf(L" Interface Index[%u]:\t %lu\n", i, i); iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString, sizeof(GuidString)/sizeof(*GuidString)); if (iRet == 0) wprintf(L"StringFromGUID2 failed\n"); else { wprintf(L" InterfaceGUID[%d]: %ws\n",i, GuidString); } wprintf(L" Interface Description[%d]: %ws", i, pIfInfo->strInterfaceDescription); wprintf(L"\n"); wprintf(L" Interface State[%d]:\t ", i); switch (pIfInfo->isState) { case wlan_interface_state_not_ready: wprintf(L"Not ready\n"); break; case wlan_interface_state_connected: wprintf(L"Connected\n"); break; case wlan_interface_state_ad_hoc_network_formed: wprintf(L"First node in a ad hoc network\n"); break; case wlan_interface_state_disconnecting: wprintf(L"Disconnecting\n"); break; case wlan_interface_state_disconnected: wprintf(L"Not connected\n"); break; case wlan_interface_state_associating: wprintf(L"Attempting to associate with a network\n"); break; case wlan_interface_state_discovering: wprintf(L"Auto configuration is discovering settings for the network\n"); break; case wlan_interface_state_authenticating: wprintf(L"In process of authenticating\n"); break; default: wprintf(L"Unknown state %ld\n", pIfInfo->isState); break; } } } } } int _tmain(int argc, _TCHAR* argv[]) { HANDLE hClient = NULL; DWORD dwMaxClient = 2; DWORD dwCurVersion = 0; DWORD dwResult = 0; DWORD dwRetVal = 0; int iRet = 0; /* variables used for WlanEnumInterfaces */ PWLAN_INTERFACE_INFO_LIST pIfList = NULL; PWLAN_INTERFACE_INFO pIfInfo = NULL; LPCWSTR pProfileName = NULL; LPWSTR pProfileXml = NULL; DWORD dwFlags = 0; pProfileName = argv[1]; wprintf(L"Information for profile: %ws\n\n", pProfileName); dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult); return 1; } dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult); return 1; } else { dwResult = WlanDisconnect(hClient, &pIfList->InterfaceInfo[0].InterfaceGuid,NULL);//DISCONNECT FIRST if(dwResult != ERROR_SUCCESS) { printf("WlanDisconnect failed with error: %u\n",dwResult); return -1; } PWLAN_AVAILABLE_NETWORK_LIST pWLAN_AVAILABLE_NETWORK_LIST = NULL; dwResult = WlanGetAvailableNetworkList(hClient, &pIfList->InterfaceInfo[0].InterfaceGuid, WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES, NULL, &pWLAN_AVAILABLE_NETWORK_LIST); if (dwResult != ERROR_SUCCESS) { printf("WlanGetAvailableNetworkList failed with error: %u\n",dwResult); WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST); return -1; } WLAN_AVAILABLE_NETWORK wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[0];//PLEASE CHECK THIS YOURSELF if(pProfileName == NULL) pProfileName = wlanAN.strProfileName; WLAN_CONNECTION_PARAMETERS wlanConnPara; wlanConnPara.wlanConnectionMode =wlan_connection_mode_profile ; //YES,WE CONNECT AP VIA THE PROFILE wlanConnPara.strProfile =pProfileName; // set the profile name wlanConnPara.pDot11Ssid = NULL; // SET SSID NULL 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 dwResult=WlanConnect(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid,&wlanConnPara ,NULL); if (dwResult==ERROR_SUCCESS) { printf("WlanConnect success!\n"); } else { printf("WlanConnect failed err is %d\n",dwResult); } } listenStatus(); //LISTEN THE STATUS if (pProfileXml != NULL) { WlanFreeMemory(pProfileXml); pProfileXml = NULL; } if (pIfList != NULL) { WlanFreeMemory(pIfList); pIfList = NULL; } return dwRetVal; }
5.翻開收集設置界面
碰到之前沒有銜接過的AP,須要輸出暗碼,那末,直接翻開設置裝備擺設界面讓用戶本身來弄吧。
ShellExecute( NULL, L"open", L"shell:::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{38a98528-6cbf-4ca9-8dc0-b1e1d10f7b1b}", NULL, NULL, SW_SHOWNORMAL);
6.RSSI
當屏幕上打印出“WlanConnect success!”的時刻,別提多愉快了。
就像愛迪生實驗燈絲一下,在有數次掉敗後,終究找到了一種資料可以勝任燈絲的任務。這類喜悅真的使人振奮,昔日的陰霾和不爽終究一掃而空。
其實我也測驗考試過WlanGetProfile和WlanSetProfile,固然有時成果是可以或許連上指定AP,然則函數前往成果卻老是ERROR_INVALID_PARAMETER。
網上的例子,許多都是抄來抄去的,寫的不明不白,固然有過贊助,然則也有些誤導。
明天本身勝利的銜接到指定AP了(用敕令交運行我的例子,輸出參數profile name),我必定要把它揭橥出來,讓其別人有個參考。
我以為這是一件誠意的作品,在此也感謝給過我贊助的同伙。
最初說一下取得的旌旗燈號。尺度旌旗燈號RSSI是負值,而這裡取得的旌旗燈號都是正值(0~100),在有些須要RSSI的處所,我們須要轉換一下:
if (pBssEntry->wlanSignalQuality == 0) iRSSI = -100; else if (pBssEntry->wlanSignalQuality == 100) iRSSI = -50; else iRSSI = -100 + (pBssEntry->wlanSignalQuality/2); wprintf(L" Signal Quality[%u]:\t %u (RSSI: %i dBm)\n", j, pBssEntry->wlanSignalQuality, iRSSI);
7.Wifi on與wifi off
上面要說的是在軟件層面掌握無線網卡的開和關。
成績聽起來簡略,查詢拜訪起來龐雜,但處理起來卻也簡略。症結函數就是Native wifi api中的WlanSetInterface。其實這個API功效也長短
常壯大的,我只用到個中掌握wifi radio state的功效。官網文檔在此。
函數原型:
DWORD WINAPI WlanSetInterface( _In_ HANDLE hClientHandle, _In_ const GUID *pInterfaceGuid, _In_ WLAN_INTF_OPCODE OpCode, _In_ DWORD dwDataSize, _In_ const PVOID pData, _Reserved_ PVOID pReserved );
重點說一下三個參數:
(1) OpCode,指定要設置的參數。我們選擇wlan_intf_opcode_radio_state
(2) DwDataSize,pData的size。傳入時用sizeof獲得。
(3) pData,radio state對應的data是WLAN_PHY_RADIO_STATE。
看看這個state構造體:
typedef struct _WLAN_PHY_RADIO_STATE { DWORD dwPhyIndex; DOT11_RADIO_STATE dot11SoftwareRadioState; DOT11_RADIO_STATE dot11HardwareRadioState; } WLAN_PHY_RADIO_STATE, *PWLAN_PHY_RADIO_STATE;
Index設為0.
State設置以下:
typedef enum _DOT11_RADIO_STATE { dot11_radio_state_unknown, dot11_radio_state_on, dot11_radio_state_off } DOT11_RADIO_STATE, *PDOT11_RADIO_STATE;
與前幾個API(好比wlanconnect)比擬,這個函數的應用簡略多了。全體源碼以下:
// ManageWirelessNetwork.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <stdio.h> #include <windows.h> #include <shellapi.h> #include <wlanapi.h> // Need to link with shell32.lib #pragma comment(lib, "shell32.lib") #pragma comment(lib, "wlanapi.lib") int _tmain(int argc, _TCHAR* argv[]) { DWORD dwResult = 0; DWORD dwMaxClient = 2; DWORD dwCurVersion = 0; HANDLE hClient = NULL; PWLAN_INTERFACE_INFO_LIST pIfList = NULL; PWLAN_INTERFACE_INFO pIfInfo = NULL; dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult); return false; } dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult); return false; } WLAN_PHY_RADIO_STATE state; state.dwPhyIndex = 0; state.dot11SoftwareRadioState = dot11_radio_state_on; PVOID pData = &state; dwResult = WlanSetInterface(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid, wlan_intf_opcode_radio_state,sizeof(WLAN_PHY_RADIO_STATE),pData,NULL); if(dwResult == ERROR_SUCCESS) { wprintf(L"set state success!\n"); } else { wprintf(L"set state failed!err is %d\n",dwResult); } return 0; }
8.GOTO在釋放資本時的感化
GOTO語句有著很臭的名聲,我們的先生常常教誨我們說,不要隨意馬虎應用它。
C++跳轉語句有三個:goto、break和continue。它們只是對象,我認為成績不克不及歸罪於對象,成績在於人。
就像指針一樣,goto這個無前提跳轉語句力氣照樣很壯大的,假如濫用,湧現成績很難排查。
但有些時刻goto確切是不貳選擇,例如我碰到的,在函數中有多個出口,而每一個出口都碰到釋放資本的時刻,與其都把釋放語句誨人不倦的寫一遍,
不如一個goto語句來的爽性拖拉。
上面的例子取自上一篇Native Wifi API文章,因為我們的法式常常掌握的wifi的on和off,必需留意釋放資本。就拿WlanOpenHandle來講,
假如不留意對稱WlanCloseHandler,法式幾回運轉後報錯:ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
官網說明為:Too many handles have been issued by the server.
所以我們會在每一個API挪用後,確認前往值,假如毛病,法式將不再持續向下運轉,return之前,我們必需釋放資本。當出口許多時,我們要寫許多異樣的代碼,
很焦躁,難讀,代碼急速收縮。但應用goto後,成績便輕松了很多,請看簡略例子:
// ManageWirelessNetwork.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <stdio.h> #include <windows.h> #include <shellapi.h> #include <wlanapi.h> // Need to link with shell32.lib #pragma comment(lib, "shell32.lib") #pragma comment(lib, "wlanapi.lib") int _tmain(int argc, _TCHAR* argv[]) { DWORD dwResult = 0; DWORD dwMaxClient = 2; DWORD dwCurVersion = 0; HANDLE hClient = NULL; PWLAN_INTERFACE_INFO_LIST pIfList = NULL; PWLAN_INTERFACE_INFO pIfInfo = NULL; dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult); return false; } dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList); if (dwResult != ERROR_SUCCESS) { wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult); goto RELEASE_RESOURCE; } WLAN_PHY_RADIO_STATE state; state.dwPhyIndex = 0; state.dot11SoftwareRadioState = dot11_radio_state_on;//off here too. PVOID pData = &state; dwResult = WlanSetInterface(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid, wlan_intf_opcode_radio_state,sizeof(WLAN_PHY_RADIO_STATE),pData,NULL); if(dwResult == ERROR_SUCCESS) { wprintf(L"set state success!\n"); } else { wprintf(L"set state failed!err is %d\n",dwResult); } RELEASE_RESOURCE: if(hClient) { WlanCloseHandle(hClient,NULL); hClient = NULL; } if(pIfList) { WlanFreeMemory(pIfList); pIfList = NULL; } if(pIfInfo) { WlanFreeMemory(pIfInfo); pIfInfo = NULL; } return 0; }
最初,goto還會用來跳出多重輪回。但須要留意的是,只能從內層跳到外層,弗成逆操作。
跋文:
其實幾個月前就要完成windows上的wifi on和off,問了很多人,發了很多帖子,最初都不了了之。以後的日子裡也產生了很多事。國際的
搜刮無果,加上谷歌的沒法應用,都對換查增長了些許難度。我們把重點先放到了native wifi api的幾個辦法,見上一篇玩轉文章。但
那其實不是我想要的。
原認為windows也會想android一樣,通俗運用沒有權限來掌握wifi的開關呢,成果其實不是如許。這也宣布了之前我的斷定掉誤。
直到明天,經由過程Bing發明了幾條線索。那是經由過程C#挪用native wifi api的成績,外面說起了之前並沒有看重的wlansetinterface。
Interface,在這裡我認為可以懂得成無線網卡。相似的WlanEnumInterfaces中完成的功效是枚舉出以後無線網卡。
無線網卡的設置,個中有一項是radio的狀況。
果真,這一切都有了了斷。