C# Windows Forms rilevare le connessioni WiFi in .Net 9

Articolo che fornisce la tecnica per rilevare informazioni sulle rete WIFI utilizzando le funzioni API di Windows.

il
Sviluppatore Microsoft .Net, Collaboratore di IProgrammatori

In questo articolo vedremo come rilevare tutte le connessioni WIFI che sono raggiungibili dal pc in cui viene eseguito il progetto di tipo “Windows Application”.
In particolare, elencheremo il nome della connessione WiFi, la potenza del segnalare e se è protetta (con Password) oppure no.
Per rilevare le varie connessioni WIFI, faremo uso delle funzioni API di Windows, che con le varie funzioni rileviamo le informazioni necessarie.
In questo articolo abbiamo utilizzato il linguaggio di programmazione C#, l’ambiente di sviluppo Visual Studio 2022 Community e l’ultima versione del Framework, che al momento è la versione .Net 9.

Creazione del progetto

Si crea un nuovo progetto di tipo “Windows Application”, selezionando come modello quello con la dicitura “App Windows Forms”.
Una volta visualizzata la Form, inseriamo un controllo di tipo “DataGridView”, impostando la proprietà “Name” con il valore “DtgDati”, ed il valore “Dock” con il valore “Top” . Inseriamo nella parte inferiore della form, un pulsante, con la proprietà “Text” impostata su “Rileva” e la proprietà “Name” impostata con il valore “BtnRileva”.
La form sarà come quella in figura 1.

Figura 1 – La form con i vari controlli

Figura 1 – La form con i vari controlli


Stesura del codice

Terminata la creazione della form, non resta che scrivere il codice. Nel progetto aggiungiamo una classe denominata “Wifi”. Dalla finestra “Esplora soluzioni”, facciamo click con il tasto destro sul nome del progetto, nel menu che viene visualizzato facciamo click sulla voce di menu “Aggiungi” e nel sottomenu selezioniamo la voce “Classe”. Nella finestra che viene visualizzata, digitiamo come nome della classe “WiFi”.
Dopo aver aggiunto la classe, rendiamola di tipo pubblica.

In questa classe dobbiamo aggiungere le funzioni e strutture per la gestione delle API di Windows.
Di seguito si riporta il codice completo della classe “Wifi”.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace WinArtWiFi
{
   public class WiFi
   {
       public WiFi() { }
       //Funzioni API per la gestione WIFI
       [DllImport("wlanapi.dll")]
       public static extern int WlanOpenHandle(
      uint dwClientVersion,
      IntPtr pReserved,
      out uint pdwNegotiatedVersion,
      out IntPtr phClientHandle);
       [DllImport("wlanapi.dll")]
       public static extern int WlanEnumInterfaces(
           IntPtr hClientHandle,
           IntPtr pReserved,
           out IntPtr ppInterfaceList);
       [DllImport("wlanapi.dll")]
       public static extern int WlanGetAvailableNetworkList(
           IntPtr hClientHandle,
           [MarshalAs(UnmanagedType.LPStruct)] Guid pInterfaceGuid,
           uint dwFlags,
           IntPtr pReserved,
           out IntPtr ppAvailableNetworkList);
       //Defizione della struttura per la lista delle reti disponibili
       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
       public struct WLAN_INTERFACE_INFO
       {
           public Guid InterfaceGuid;
           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
           public string strInterfaceDescription;
           public WLAN_INTERFACE_STATE isState;
       }
       public enum WLAN_INTERFACE_STATE
       {
           wlan_interface_state_not_ready = 0,
           wlan_interface_state_connected = 1,
           wlan_interface_state_ad_hoc_network_formed = 2,
           wlan_interface_state_disconnecting = 3,
           wlan_interface_state_disconnected = 4,
           wlan_interface_state_associating = 5,
           wlan_interface_state_discovering = 6,
           wlan_interface_state_authenticating = 7
       }
       [StructLayout(LayoutKind.Sequential)]
       public struct WLAN_INTERFACE_INFO_LIST
       {
           public int dwNumberOfItems;
           public int dwIndex;
           public WLAN_INTERFACE_INFO[] InterfaceInfo;
           public WLAN_INTERFACE_INFO_LIST(IntPtr pList)
           {
               dwNumberOfItems = Marshal.ReadInt32(pList, 0);
               dwIndex = Marshal.ReadInt32(pList, 4);
               InterfaceInfo = new WLAN_INTERFACE_INFO[dwNumberOfItems];
               for (int i = 0; i < dwNumberOfItems; i++)
               {
                   IntPtr pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf(typeof(WLAN_INTERFACE_INFO))) + 8);
                   InterfaceInfo[i] = Marshal.PtrToStructure<WLAN_INTERFACE_INFO>(pItemList);
               }
           }
       }
       //Strutte rete disponibili
       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
       public struct DOT11_SSID
       {
           public uint SSIDLength;
           [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
           public byte[] SSID;
       }
       [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
       public struct WLAN_AVAILABLE_NETWORK
       {
           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
           public string strProfileName;
           public DOT11_SSID dot11Ssid;
           public uint dot11BssType;
           public uint uNumberOfBssids;
           public bool bNetworkConnectable;
           public uint wlanNotConnectableReason;
           public uint uNumberOfPhyTypes;
           [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
           public uint[] dot11PhyTypes;
           public bool bMorePhyTypes;
           public uint wlanSignalQuality;
           public bool bSecurityEnabled;
           public uint dot11DefaultAuthAlgorithm;
           public uint dot11DefaultCipherAlgorithm;
           public uint dwFlags;
           public uint dwReserved;
       }
       [StructLayout(LayoutKind.Sequential)]
       public struct WLAN_AVAILABLE_NETWORK_LIST
       {
           public uint dwNumberOfItems;
           public uint dwIndex;
           public WLAN_AVAILABLE_NETWORK[] Network;
           public WLAN_AVAILABLE_NETWORK_LIST(IntPtr pList)
           {
               dwNumberOfItems = (uint)Marshal.ReadInt32(pList, 0);
               dwIndex = (uint)Marshal.ReadInt32(pList, 4);
               Network = new WLAN_AVAILABLE_NETWORK[dwNumberOfItems];
               for (int i = 0; i < dwNumberOfItems; i++)
               {
                   IntPtr pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf(typeof(WLAN_AVAILABLE_NETWORK))) + 8);
                   Network[i] = Marshal.PtrToStructure<WLAN_AVAILABLE_NETWORK>(pItemList);
               }
           }
       }
   }
}

Ritorniamo nella  form, ed in visualizzazione codice, in alto sopra ad ogni definizione, dobbiamo aggiungere il riferimento a questa classe, in alto dove vengono inseriti i namespace, inseriamo il riferimento a questa classe.
Di seguito si riporta il frammento di codice di tale dichiarazione.

C#
using static WinArtWiFi.WiFi;

Passiamo in visualizzazione grafica, e facciamo doppio click sul pulsante inserito in precedenza, in questo modo passiamo in visualizzazione codice nell’evento click del pulsante.
In questo evento rileviamo tramite le funzioni di Windows, le reti disponibile, e visualizziamo nella griglia le informazioni di nostro interesse.
Di seguito il frammento di codice per visualizzare nella griglia le reti WiFi disponibili.

C#
private void BtnRileva_Click(object sender, EventArgs e)
{
   try
   {
       uint negotiatedVersion;
       IntPtr clientHandle;
       int result = WlanOpenHandle(2, IntPtr.Zero, out negotiatedVersion, out clientHandle);
       if (result != 0) return;
       IntPtr interfaceList;
       result = WlanEnumInterfaces(clientHandle, IntPtr.Zero, out interfaceList);
       if (result != 0) return;
       //Rilevo leinterfacce WLAN disponibili
       var interfaces = new WLAN_INTERFACE_INFO_LIST(interfaceList).InterfaceInfo;
       foreach (var iface in interfaces)
       {
           IntPtr networkListPtr;
           result = WlanGetAvailableNetworkList(clientHandle, iface.InterfaceGuid, 0, IntPtr.Zero, out networkListPtr);
           if (result != 0) continue;
           // Rilevo le reti disponibili per l'interfaccia corrente
           var networkList = new WLAN_AVAILABLE_NETWORK_LIST(networkListPtr);
            var retiTrovate = networkList.Network
            .Select(network => new
            {
                NomeRete = Encoding.ASCII.GetString(network.dot11Ssid.SSID, 0, (int)network.dot11Ssid.SSIDLength),
                Segnale = network.wlanSignalQuality + "%",
                Protetta = network.bSecurityEnabled ? "Sì" : "No"
            })
           .ToList();
           DtgDati.DataSource = retiTrovate;
       }
   }
   catch (Exception ex)
   {
       MessageBox.Show("Errore: " + ex.Message);
   }
}

Il risultato sarà come riportato in figura 2.

Figura 2 – La lista delle reti Wifi

Figura 2 – La lista delle reti Wifi

Conclusioni


L’articolo ha illustrato al lettore l’utilizzo delle funzioni di Windows per rilevare le reti wifi nel pc in cui viene eseguita l’applicazione. L’esempio di codice diviene utili per approfondimenti per la gestione di software di sicurezza e monitoraggio delle reti senza fili.