Basic tutorial on using Windows system Native Wifi API in C++ programs

  • 2020-05-09 18:59:59
  • OfStack

Windows applications want to connect to wifi, listen to wifi signals, disconnect, etc. Using NativeWifi API is a good choice.

Open MSDN, search NativeWifi Api, find Native Wifi page. Here you are.

There is so much information that if I were in a hurry to implement the above functions, it would be too late for me to see the huge amount of documents. It would be much more efficient to just give me an example of debugging at run time and reading the code.
But I didn't succeed. First of all, Sample is in SDK, see here. I downloaded several times failed, finally gave up the road. Later, my colleague gave me a copy of Sample. I'm not sure if this is it, but the code is also very obscure. My original intention was to simply use these API examples.

I guess you should do it yourself. If you don't understand API, look for examples of people with experience.

After many twists and turns, I finally realized my needs. Let me take my time.
1. Get a list of available AP
See WlanGetAvailableNetworkList's official documentation for an example.


DWORD WINAPI WlanGetAvailableNetworkList( 
 _In_  HANDLE hClientHandle, 
 _In_  const GUID *pInterfaceGuid, 
 _In_  DWORD dwFlags, 
 _Reserved_ PVOID pReserved, 
 _Out_  PWLAN_AVAILABLE_NETWORK_LIST *ppAvailableNetworkList 
); 

From the available list, you can find which AP is currently connecting and display the signal strength.
2. Listen for the current connection
Based on the list of available AP, walk through the current AP to see who is connecting and get its signal. The code snippet is as follows:


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

disconnect
If wifi is in the connected state, disconnect it. WlanDisconnect is still easy to use. The prototype is as follows:


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

The code demo is in the back.
4. Connect 1 AP with profile (saved password)
This is the focus of this article.
Although the connection function WlanConnect prototype is simple:


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

However, the parameter PWLAN_CONNECTION_PARAMETERS is very complicated, as long as there is one mismatching, the connection will fail.
Fortunately, my requirements are quite simple, as long as I connect the existing profile AP. Then my work will be targeted to carry out. Frustration for many days, every time the connection failed, because of ERROR_INVALID_PARAMETER.
Today, I finally made it. It is not difficult to be good at it, but not to be bad at it.
Look at the structure of the connection parameter:

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; 

In order to achieve my requirements, I can assign the value as follows:
wlanConnectionMode, wlan_connection_mode_profile;
strProfile write the name you want to connect ap (usually profile name);
pDot11Ssid is not available, set NULL;
pDesiredBssidList is also NULL;
dot11BssType I'm going to make dot11_BSS_type_infrastructure (infrastructure?) ;
dwFlags is set to WLAN_CONNECTION_HIDDEN_NETWORK.
It does work. How do you get strProfile? See listening for connection signals to get the first profile in the list of available AP.
The complete code is as follows:


// 
#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. Open the network setup interface
If you encounter AP, which you have not connected before, you need to enter your password. Then, open the configuration interface directly and let the user do it by himself.


ShellExecute( 
 NULL, 
 L"open", 
 L"shell:::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{38a98528-6cbf-4ca9-8dc0-b1e1d10f7b1b}", 
 NULL, 
 NULL, 
 SW_SHOWNORMAL); 

6.RSSI
When the screen prints "WlanConnect success!" I couldn't have been happier.
Like Edison test filament 1, after numerous failures, finally found a material can be qualified for the work of the filament. The joy was exhilarating, and the gloom and bitterness of the past were finally swept away.
In fact, I have tried WlanGetProfile and WlanSetProfile, and although the result is sometimes connected to the specified AP, the function always returns ERROR_INVALID_PARAMETER.
The examples on the Internet, many are copied to copy, writing is not clear, although there has been help, but also some misleading.
Today I successfully connected to AP (run my example from the command line, enter profile name) and I will definitely post it for others to refer to.
I think it is a sincere work, and I would like to thank my friends who have helped me.
Finally, say 1 to get the signal. The standard signal RSSI is negative, while the signals obtained here are all positive (0~100). In some places where RSSI is needed, we need to convert 1:


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 and wifi off
The following is to control the wireless card on and off at the software level.
The problem sounds simple and complex to investigate, but it is also simple to solve. The key function is WlanSetInterface in Native wifi api. In fact, this API function is also wrong
Often powerful, I only used it to control wifi radio state functions. The official website documentation is here.
Function prototype:


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

Focus on the following three parameters:
(1) OpCode, specify the parameters to be set. We choose wlan_intf_opcode_radio_state
(2) DwDataSize, pData, size. You get it with sizeof when you pass it in.
(3) pData, radio state corresponding data is WLAN_PHY_RADIO_STATE.
Look at this state structure:


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 to 0.
State Settings are as follows:


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");} 
0

This function is much easier to use than the previous API, such as wlanconnect. The full source code is as follows:


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");} 
1

8. The role of GOTO in releasing resources
The GOTO statement has a bad reputation, and our teachers often tell us not to use it lightly.
There are three C++ jump statements: goto, break, and continue. They're just tools, and I think the problem is not tools, it's people.
Like pointer 1, goto is an unconditional jump statement that can be very powerful and difficult to troubleshoot if abused.
However, sometimes goto is really not a choice. For example, I met that there are multiple exits in the function, and when each exit encounters the release of resources, instead of writing the release statement over and over again,
Not as crisp as an goto statement.
The following example is taken from the previous Native Wifi API article. Since our program often controls wifi on and off, care must be taken to release resources. So WlanOpenHandle, for example,
If you do not pay attention to the symmetry of WlanCloseHandler, the program will report an error after several runs: ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
Too many handles have been issued by the server
So we will confirm the return value after each API call. If there is an error, the program will not continue to run down. Before return, we must release the resource. When we export a lot, we're going to write a lot of the same code,
It's annoying. It's hard to read. However, after using goto, the problem is much easier. Here is a simple example:


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");} 
2

Finally, goto is used to break out of multiple loops. But it's important to note that you can only jump from the inside to the outside, irreversible.

Postscript:
Actually, wifi on and off were implemented on windows a few months ago. I asked a lot of people and made a lot of posts, but nothing happened. Many things happened in the days that followed. The domestic
The fruitless search, combined with the availability of google, made the investigation a little more difficult. We focused on a few of native wifi api methods, as described in the previous playbook. but
That's not what I wanted.
I thought windows would be like android1, because normal applications don't have permission to switch on or off wifi, but that's not the case. It was also a statement of my previous misjudgment.
To this day, several clues have been found through Bing. That is the problem of calling native wifi api via C#, which refers to wlansetinterface which has not been taken seriously before.
Interface, which I think can be interpreted as a wireless network card. A similar function implemented in WlanEnumInterfaces is to list current wireless network CARDS.
Wireless network card Settings, one of which is the state of radio.
And sure enough, all of the 1's are broken.


Related articles: