How do I get the available wifi APs and their signal strength in .net?
Asked Answered
A

8

29

Is there any way to access all WiFi access points and their respective RSSI values using .NET? It would be really nice if I could do it without using unmanaged code or even better if it worked in mono as well as .NET.

If it is possible i would appriciate a code sample. Thanks


Here are a few similiar stackoverflow questions i found:

-Get SSID of the wireless network I am connected to with C# .Net on Windows Vista

-Managing wireless network connection in C#

-Get BSSID (MAC address) of wireless access point from C#

Abridgment answered 30/1, 2009 at 18:15 Comment(0)
M
19

It is a wrapper project with managed code in c# at http://www.codeplex.com/managedwifi

It supports Windows Vista and XP SP2 (or later version).

sample code:

using NativeWifi;
using System;
using System.Text;

namespace WifiExample
{
    class Program
    {
        /// <summary>
        /// Converts a 802.11 SSID to a string.
        /// </summary>
        static string GetStringForSSID(Wlan.Dot11Ssid ssid)
        {
            return Encoding.ASCII.GetString( ssid.SSID, 0, (int) ssid.SSIDLength );
        }

        static void Main( string[] args )
        {
            WlanClient client = new WlanClient();
            foreach ( WlanClient.WlanInterface wlanIface in client.Interfaces )
            {
                // Lists all networks with WEP security
                Wlan.WlanAvailableNetwork[] networks = wlanIface.GetAvailableNetworkList( 0 );
                foreach ( Wlan.WlanAvailableNetwork network in networks )
                {
                    if ( network.dot11DefaultCipherAlgorithm == Wlan.Dot11CipherAlgorithm.WEP )
                    {
                        Console.WriteLine( "Found WEP network with SSID {0}.", GetStringForSSID(network.dot11Ssid));
                    }
                }

                // Retrieves XML configurations of existing profiles.
                // This can assist you in constructing your own XML configuration
                // (that is, it will give you an example to follow).
                foreach ( Wlan.WlanProfileInfo profileInfo in wlanIface.GetProfiles() )
                {
                    string name = profileInfo.profileName; // this is typically the network's SSID

                    string xml = wlanIface.GetProfileXml( profileInfo.profileName );
                }

                // Connects to a known network with WEP security
                string profileName = "Cheesecake"; // this is also the SSID
                string mac = "52544131303235572D454137443638";
                string key = "hello";
                string profileXml = string.Format("<?xml version=\"1.0\"?><WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\"><name>{0}</name><SSIDConfig><SSID><hex>{1}</hex><name>{0}</name></SSID></SSIDConfig><connectionType>ESS</connectionType><MSM><security><authEncryption><authentication>open</authentication><encryption>WEP</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>networkKey</keyType><protected>false</protected><keyMaterial>{2}</keyMaterial></sharedKey><keyIndex>0</keyIndex></security></MSM></WLANProfile>", profileName, mac, key);

                wlanIface.SetProfile( Wlan.WlanProfileFlags.AllUser, profileXml, true );
                wlanIface.Connect( Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any, profileName );
            }
        }
    }
}
Maraschino answered 31/1, 2009 at 4:7 Comment(2)
Thank you for this. But it's not working for me. I'm using windows 8.1 and I'm getting this exception "An unhandled exception of type 'System.ComponentModel.Win32Exception' occurred in ManagedWifi.dll". Any idea?Cytokinesis
I am too getting thiis error in one of my machines though I am running it on windows 10 and VS 2015. Any clues ? were you able to sort it out ?Iterative
I
9

If the platform is Windows10, you can use Microsoft.Windows.SDK.Contracts package to access all available wifis.

First, install Microsoft.Windows.SDK.Contracts package from nuget.

Then, you can use next code to get ssid and signal strength.

var adapters = await WiFiAdapter.FindAllAdaptersAsync();
foreach (var adapter in adapters)
{
    foreach (var network in adapter.NetworkReport.AvailableNetworks)
    {
        Console.WriteLine($"ssid: {network.Ssid}");
        Console.WriteLine($"signal strength: {network.SignalBars}");
    }
}
Imposture answered 11/9, 2020 at 7:32 Comment(1)
This doesn't work. There isn't any WifiAdapter class under that packagePrichard
T
3

Use Native Wifi APIs, present on all Vista and XP SP3 systems. XP SP2 has a different API with which you can do the same thing.

How to enumerate networks

How to get signal strength

Thursby answered 31/1, 2009 at 2:12 Comment(1)
signal strength can not be used in windows XP. not even with every SP :(Abridgment
C
3

I am doing it running a command netsh wlan show networks mode=bssid from C# code.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class AccessPoint
    {
        public string SSID { get; set; }
        public string BSSID { get; set; }
        public byte Signal { get; set; }
    }

    class Program
    {
        private static async Task Main(string[] args)
        {
            var apList = await GetSignalOfNetworks();

            foreach (var ap in apList)
            {
                WriteLine($"{ap.BSSID} - {ap.Signal} - {ap.SSID}");
            }

            Console.ReadKey();
        }

        private static async Task<AccessPoint[]> GetSignalOfNetworks()
        {
            string result = await ExecuteProcessAsync(@"C:\Windows\System32\netsh.exe", "wlan show networks mode=bssid");

            return Regex.Split(result, @"[^B]SSID \d+").Skip(1).SelectMany(network => GetAccessPointFromNetwork(network)).ToArray();
        }

        private static AccessPoint[] GetAccessPointFromNetwork(string network)
        {
            string withoutLineBreaks = Regex.Replace(network, @"[\r\n]+", " ").Trim();
            string ssid = Regex.Replace(withoutLineBreaks, @"^:\s+(\S+).*$", "$1").Trim();

            return Regex.Split(withoutLineBreaks, @"\s{4}BSSID \d+").Skip(1).Select(ap => GetAccessPoint(ssid, ap)).ToArray();
        }

        private static AccessPoint GetAccessPoint(string ssid, string ap)
        {
            string withoutLineBreaks = Regex.Replace(ap, @"[\r\n]+", " ").Trim();
            string bssid = Regex.Replace(withoutLineBreaks, @"^:\s+([a-f0-9]{2}(:[a-f0-9]{2}){5}).*$", "$1").Trim();
            byte signal = byte.Parse(Regex.Replace(withoutLineBreaks, @"^.*(Signal|Sinal)\s+:\s+(\d+)%.*$", "$2").Trim());

            return new AccessPoint
            {
                SSID = ssid,
                BSSID = bssid,
                Signal = signal,
            };
        }

        private static async Task<string> ExecuteProcessAsync(string cmd, string args = null)
        {
            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = cmd,
                    Arguments = args,
                    RedirectStandardInput = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    StandardOutputEncoding = Encoding.UTF8,
                }
            };

            process.Start();

            string result = await process.StandardOutput.ReadToEndAsync();

            process.WaitForExit();

#if DEBUG
            if (result.Trim().Contains("The Wireless AutoConfig Service (wlansvc) is not running."))
            {
                return await GetFakeData();
            }
#endif

            return result;
        }

        private static async Task<string> GetFakeData()
        {
            var assembly = Assembly.GetExecutingAssembly();
            var resourceName = "ConsoleApp2.FakeData.txt";

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            using (StreamReader reader = new StreamReader(stream))
            {
                return await reader.ReadToEndAsync();
            }
        }

        private static void WriteLine(string str)
        {
            Console.WriteLine(str);
        }
    }
}
Chrysotile answered 21/2, 2019 at 16:48 Comment(0)
M
0

You might be able to achieve it using WMI queries. Take a look at this thread.

Ministerial answered 30/1, 2009 at 18:20 Comment(1)
It does actually seem feasible, though the WMI MSNdis_80211_BSSIList description says that you need to perform a survey before anything gets populated. No idea how to perform a survey.Complot
M
0

If you are using vista wmi does not work with all network adapters, another alternative for vista is to use the netsh command. Have a look at this codeproject article.

Morehouse answered 30/1, 2009 at 18:28 Comment(1)
thx for the link. the problem with netsh is that it doesnt give me all the information i need (rssi) and is kind of buggy sometimesAbridgment
D
0

I found the other answers very useful and wanted to see how they compared with each other. Here's some LINQ code which gets the data from each and joins them. Here's a LINQPad script which contains all the nuget dependencies and usings: http://share.linqpad.net/7pxls3.linq

var adapters = await WiFiAdapter.FindAllAdaptersAsync();

var wifiAdapterResults = adapters
.SelectMany(a => a.NetworkReport.AvailableNetworks.Select(a => new
{
    a.Ssid,
    a.Bssid,
    Ghz = Math.Round(a.ChannelCenterFrequencyInKilohertz / 1000000.0, 1),
    a.NetworkRssiInDecibelMilliwatts,
    a.SignalBars,
    a.PhyKind,
}))
.Where(n => n.Ssid != null)
.OrderByDescending(n => n.NetworkRssiInDecibelMilliwatts);

WlanClient client = new WlanClient();

var wlanResults = client.Interfaces.SelectMany(i => i.GetNetworkBssList().Select(n => new
{
    SSID = new string(Encoding.ASCII.GetChars(n.dot11Ssid.SSID, 0, (int)n.dot11Ssid.SSIDLength)),
    n.linkQuality,
    n.rssi,
    MAC = BitConverter.ToString(n.dot11Bssid).Replace('-', ':').ToLowerInvariant(),
}))
.OrderByDescending(n => n.rssi);

wifiAdapterResults.Join(wlanResults, r => r.Bssid, r => r.MAC, (r1, r2) => Util.Merge(r1, r2)).Dump();

The Util.Merge function is a LINQPad concept, if you want to run outside of LINQPad you'll have to create the merged object yourself.

The built-in WinRT WifiAdapter is easier to call, but doesn't have a nice link quality value, only the very granular SignalBars and the rssi. The ManagedWifi library on the other hand has a 1-100 linkQuality value which seems more useful.

Hope someone else finds this useful!

Dillon answered 1/6, 2022 at 0:0 Comment(0)
A
-3

I found another way to do it, although it does cost some money.

There is a .NET lib available at rawether.net that lets you get at the ethernet drivers.

Abridgment answered 1/2, 2009 at 15:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.