欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++程序中使用Windows系統(tǒng)Native Wifi API的基本教程

 更新時間:2016年03月19日 17:24:43   作者:全速前行  
這篇文章主要介紹了C++程序中使用Windows系統(tǒng)Native Wifi API的基本教程,包括在程序中控制無線網(wǎng)卡開關(guān)的方法,需要的朋友可以參考下

Windows應用想要實現(xiàn)連接wifi,監(jiān)聽wifi信號,斷開連接等功能,用NativeWifi API是個不錯的選擇。

打開MSDN,搜索NativeWifi Api,找到Native Wifi頁。在這里。

信息量很大,如果像我著急實現(xiàn)上述功能,看海量的文檔有些來不及。如果直接給我例子,在運行中調(diào)試,閱讀代碼,效率會更高。
但是,我并沒有成功。首先,Sample在SDK中,參見這里。我下載幾次都失敗了,最后放棄這條路。后來同事給了我一份Sample,我不敢確定是否就是這個,但是代碼寫的也是很晦澀。我的初衷是簡單的使用這些API的例子。

看來還是自己動手吧??聪嚓P(guān)API,如果不懂,就找有經(jīng)驗人的例子。

幾經(jīng)周折,終于實現(xiàn)我的需求。讓我慢慢道來。
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.監(jiān)聽當前連接
在獲得可用AP列表的基礎(chǔ)上,遍歷當前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處于連接狀態(tài),將其斷開。WlanDisconnect還是容易使用的。原型如下:

DWORD WINAPI WlanDisconnect( 
 _In_  HANDLE hClientHandle, 
 _In_  const GUID *pInterfaceGuid, 
 _Reserved_ PVOID pReserved 
); 

代碼演示在后面。
4.連接一個有profile的AP(已保存過密碼)
這是本文的重點。
雖然連接函數(shù)WlanConnect原型很簡單:

DWORD WINAPI WlanConnect( 
 _In_  HANDLE hClientHandle, 
 _In_  const GUID *pInterfaceGuid, 
 _In_  const PWLAN_CONNECTION_PARAMETERS pConnectionParameters, 
 _Reserved_ PVOID pReserved 
); 

但參數(shù)PWLAN_CONNECTION_PARAMETERS卻是很復雜,只要有一個配錯,連接就會失敗。
還好我的需求還是蠻簡單的,只要連接已有的profile的AP。那么我的工作就會有針對性的開展。挫折了好多天,每次都連接失敗,原因是ERROR_INVALID_PARAMETER。
就在今天,我終于成功了。真是會者不難,難者不會啊。
看看連接參數(shù)的結(jié)構(gòu)體:
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; 

為了實現(xiàn)我的要求,可以這樣賦值:
wlanConnectionMode這里設成wlan_connection_mode_profile;
strProfile寫上你要連接ap的名稱(通常是profile名稱);
pDot11Ssid用不上,設置NULL;
pDesiredBssidList同樣置成NULL;
dot11BssType我給設成dot11_BSS_type_infrastructure(基礎(chǔ)設施?);
dwFlags設置為WLAN_CONNECTION_HIDDEN_NETWORK。
確實是工作了,strProfile如何獲取呢?參見監(jiān)聽連接信號中對可用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.打開網(wǎng)絡設置界面
遇到以前沒有連接過的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!”的時候,別提多高興了。
就像愛迪生試驗燈絲一下,在無數(shù)次失敗后,終于找到了一種材料可以勝任燈絲的工作。這種喜悅真的令人振奮,往日的陰霾和不爽終于一掃而光。
其實我也嘗試過WlanGetProfile和WlanSetProfile,雖然有時結(jié)果是能夠連上指定AP,但是函數(shù)返回結(jié)果卻總是ERROR_INVALID_PARAMETER。
網(wǎng)上的例子,很多都是抄來抄去的,寫的不明不白,雖然有過幫助,但是也有些誤導。
今天自己成功的連接到指定AP了(用命令行運行我的例子,輸入?yún)?shù)profile name),我一定要把它發(fā)表出來,讓其他人有個參考。
我認為這是一件誠意的作品,在此也謝謝給過我?guī)椭呐笥选?br /> 最后說一下獲得的信號。標準信號RSSI是負值,而這里獲得的信號都是正值(0~100),在有些需要RSSI的地方,我們需要轉(zhuǎn)換一下:

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
下面要說的是在軟件層面控制無線網(wǎng)卡的開和關(guān)。
問題聽起來簡單,調(diào)查起來復雜,但解決起來卻也簡單。關(guān)鍵函數(shù)便是Native wifi api中的WlanSetInterface。其實這個API功能也是非
常強大的,我只用到其中控制wifi radio state的功能。官網(wǎng)文檔在此。
函數(shù)原型:

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 
); 

重點說一下三個參數(shù):
(1) OpCode,指定要設置的參數(shù)。我們選擇wlan_intf_opcode_radio_state
(2) DwDataSize,pData的size。傳入時用sizeof得到。
(3) pData,radio state對應的data是WLAN_PHY_RADIO_STATE。
看看這個state結(jié)構(gòu)體:

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)相比,這個函數(shù)的使用簡單多了。全部源碼如下:

// 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語句有著很臭的名聲,我們的老師經(jīng)常教導我們說,不要輕易使用它。
C++跳轉(zhuǎn)語句有三個:goto、break和continue。它們只是工具,我覺得問題不能歸咎于工具,問題在于人。
就像指針一樣,goto這個無條件跳轉(zhuǎn)語句力量還是很強大的,如果濫用,出現(xiàn)問題很難排查。
但有些時候goto確實是不二選擇,例如我遇到的,在函數(shù)中有多個出口,而每個出口都遇到釋放資源的時候,與其都把釋放語句不厭其煩的寫一遍,
不如一個goto語句來的干脆利落。
下面的例子取自上一篇Native Wifi API文章,由于我們的程序經(jīng)常控制的wifi的on和off,必須注意釋放資源。就拿WlanOpenHandle來說,
如果不注意對稱WlanCloseHandler,程序幾次運行后報錯:ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
官網(wǎng)解釋為:Too many handles have been issued by the server.
所以我們會在每個API調(diào)用后,確認返回值,如果錯誤,程序?qū)⒉辉倮^續(xù)向下運行,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還會用來跳出多重循環(huán)。但需要注意的是,只能從內(nèi)層跳到外層,不可逆操作。

后記:
其實幾個月前就要實現(xiàn)windows上的wifi on和off,問了許多人,發(fā)了許多帖子,最后都不了了之。之后的日子里也發(fā)生了許多事。國內(nèi)的
搜索無果,加上google的無法使用,都對調(diào)查增加了些許難度。我們把重點先放到了native wifi api的幾個方法,見上一篇玩轉(zhuǎn)文章。但
那并不是我想要的。
原以為windows也會想android一樣,普通應用沒有權(quán)限來控制wifi的開關(guān)呢,結(jié)果并不是這樣。這也宣告了之前我的判斷失誤。
直到今天,通過Bing發(fā)現(xiàn)了幾條線索。那是通過C#調(diào)用native wifi api的問題,里面提及了之前并沒有重視的wlansetinterface。
Interface,在這里我覺得可以理解成無線網(wǎng)卡。類似的WlanEnumInterfaces中實現(xiàn)的功能是羅列出當前無線網(wǎng)卡。
無線網(wǎng)卡的設置,其中有一項是radio的狀態(tài)。
果然,這一切都有了了斷。

相關(guān)文章

最新評論