SoFunction
Updated on 2025-03-10

Basic tutorial on using the Native Wifi API of Windows System in C++ programs

If Windows applications want to connect to wifi, listen to wifi signals, disconnect and other functions, using the NativeWifi API is a good choice.

Open MSDN, search for the NativeWifi API, and find the Native Wifi page. existhere

The amount of information is very large. If I am anxious to implement the above functions, it is too late to read a large amount of documents. If I give me an example directly, debugging and reading code during operation will be more efficient.
However, I did not succeed. First, Sample is in the SDK, seehere. I failed to download it several times and finally gave up on this path. Later, my colleague gave me a sample, and I was not sure if it was this, but the code was also very obscure. My original intention was to simply use these API examples.

It seems that it's better to do it yourself. Look at the relevant APIs and if you don’t understand them, find examples from experienced people.

After many twists and turns, I finally realized my needs. Let me tell you slowly.
1. Obtain a list of available APs
See WlanGetAvailableNetworkListOfficial Documentation, There are examples below.

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

The available list can find which AP is currently connecting and display the signal strength.
2. Listen to the current connection
Based on obtaining a list of available APs, iterate 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( & WLAN_AVAILABLE_NETWORK_CONNECTED) 
   { 
    Wprintf(WLAN signal is %s:%d\n", , ); 
    isConnect = true;     
   } 
  } 
  if(!isConnect){    
 wprintf("Wifi is disconnected!\n");} 

3. Disconnect
If the wifi is connected, 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 demonstration is later.
4. Connect to an AP with profile (save 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 
); 

But the parameter PWLAN_CONNECTION_PARAMETERS is very complicated. As long as there is an error, the connection will fail.
Fortunately, my requirements are quite simple, just connect to the AP of the existing profile. Then my work will be carried out in a targeted manner. I've been frustrated for many days, and the connection failed every time, because of ERROR_INVALID_PARAMETER.
Just today, I finally succeeded. It’s really not difficult for those who know it, but it won’t be difficult for those who know it.
Take a look at the structure of the 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; 

In order to achieve my requirements, you can assign values ​​like this:
wlanConnectionMode is set to wlan_connection_mode_profile;
strProfile write the name you want to connect to the ap (usually the profile name);
pDot11Ssid cannot be used, set NULL;
pDesiredBssidList is also set to NULL;
I set dot11BssType to dot11_BSS_type_infrastructure (infrastructure?);
dwFlags is set to WLAN_CONNECTION_HIDDEN_NETWORK.
It's really working, how to get strProfile? See the access to the first profile in the available AP list in the listen connection signal.
The complete code is as follows:

// 
#include "" 
#include <> 
#include <> 
#include <> 
#include <> 
#include <string> 
#include <> 
#include <> 
 
// Need to link with  and  
#pragma comment(lib, "") 
#pragma comment(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 = ;  
  WLAN_CONNECTION_PARAMETERS wlanConnPara; 
   =wlan_connection_mode_profile ; //YES,WE CONNECT AP VIA THE PROFILE 
   =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.   
   = NULL;       // the desired BSSID list is empty 
   = 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 settings interface
If you encounter an AP that has not been connected before and need to enter a password, then open the configuration interface and let the user do it themselves.

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


Don't mention being so happy when "WlanConnect success!" is printed on the screen.
Just like Edison experimenting with filament, after countless failures, he finally found a material that could be competent for filament work. This joy is really exciting, and the haze and unhappiness of the past have finally been wiped out.
Actually, I have also tried WlanGetProfile and WlanSetProfile. Although sometimes the result is that the specified AP can be connected, the result returned by the function is always ERROR_INVALID_PARAMETER.
Many of the examples on the Internet are copied over and over again, and they are not clear about it. Although it has been helpful, it is also somewhat misleading.
Today I successfully connected to the specified AP (run my example with the command line and enter the parameter profile name). I must publish it so that others can have a reference.
I think this is a sincere work, and I also thank my friends who have helped me here.
Finally, let’s talk about the obtained signals. The standard signal RSSI is negative, and the signals obtained here are all positive (0~100). In some places where RSSI is needed, we need to convert it:

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

    
on and wifi off
What we want to talk about is controlling the on and off of wireless network cards at the software level.
The problem sounds simple and complicated to investigate, but it is also simple to solve. The key function is WlanSetInterface in the Native wifi API. In fact, this API function is not
Very powerful, I only use the function of controlling wifi radio state.The official website document 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 
); 

Let’s focus on three parameters:
(1) OpCode, specify the parameters to be set. We choose wlan_intf_opcode_radio_state
(2) DwDataSize, pData size. When passing in, use sizeof to get it.
(3) pData, the data corresponding to radio state is WLAN_PHY_RADIO_STATE.
Take a 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; 

Set Index to 0.
State settings are as follows:

typedef enum _DOT11_RADIO_STATE { 
 dot11_radio_state_unknown, 
 dot11_radio_state_on, 
 dot11_radio_state_off 
} DOT11_RADIO_STATE, *PDOT11_RADIO_STATE; 

Compared with the previous APIs (such as wlanconnect), this function is much simpler to use. All source codes are as follows:

//  : Defines the entry point for the console application. 
// 
 
#include "" 
#include <> 
#include <> 
#include <> 
#include <> 
 
// Need to link with  
#pragma comment(lib, "") 
#pragma comment(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; 
  = 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; 
} 

The role of releasing resources
GOTO statements have a very bad reputation, and our teachers often teach us not to use them easily.
There are three C++ jump statements: goto, break and continue. They are just tools, and I don’t think the problem can be attributed to tools, the problem lies in people.
Just like a pointer, the unconditional jump statement goto is still very powerful. If it is abused, it is difficult to troubleshoot problems.
But sometimes goto is indeed the only choice. For example, when I encountered multiple exits in the function, and when each exit encountered the release of resources, instead of writing the release statements tirelessly,
It's not as straightforward as a goto statement.
The following example is taken from the previous Native Wifi API article. Since our programs often control the on and off of wifi, you must pay attention to releasing resources. Take WlanOpenHandle for example.
If you do not pay attention to the symmetric WlanCloseHandler, the program will report an error after several runs: ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
The official website explains: Too many handles have been issued by the server.
So we will confirm the return value after each API call. If the error is wrong, the program will no longer continue to run downwards. Before returning, we must release the resource. When there are a lot of exports, we have to write a lot of the same code.
Very annoying, difficult to read, and the code is rapidly expanding. But after using goto, the problem becomes much easier. Please see a simple example:

//  : Defines the entry point for the console application. 
// 
 
#include "" 
#include <> 
#include <> 
#include <> 
#include <> 
 
// Need to link with  
#pragma comment(lib, "") 
#pragma comment(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; 
   = 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; 
} 

Finally, goto will also be used to break out of multiple loops. But it should be noted that you can only jump from the inner layer to the outer layer and operate irreversibly.

postscript:
In fact, I had to implement wifi on and off on Windows a few months ago. I asked many people and posted many posts, but in the end I was left alone. Many things happened in the days that followed. Domestic
The search was fruitless, and Google's inability to use it all added some difficulty to the investigation. We will focus on several methods of native wifi API first, see the previous article to play around. but
That's not what I want.
I thought Windows would also like Android, and ordinary applications do not have permission to control the switches of Wi-Fi, but the result is not the case. This also declared my previous mistake in judgment.
Until today, several clues have been discovered through Bing. That is the issue of calling the native wifi API through C#, which mentions wlansetinterface that has not been paid attention to before.
Interface, here I think it can be understood as a wireless network card. A similar function implemented in WlanEnumInterfaces is to list the current wireless network card.
The settings of wireless network card, one of which is the state of radio.
Sure enough, all this was broken.