使用C#调用WlanAPI时如何区分SSID相似的WiFi网络?
嘿,我来帮你搞定相似SSID的WiFi网络区分问题!不管是从通用逻辑还是C#代码实现,我都给你梳理得明明白白。
通用区分思路(非代码层面)
首先,不用代码的话,你得抓住这些核心点来区分两个SSID相似的网络:
- 唯一标识符是关键:每个已保存的WiFi配置文件在系统里都有专属的唯一标识——要么是系统自动生成的配置文件名(当SSID重复时,系统会自动加后缀,比如
MyWiFi和MyWiFi 2),要么是底层的GUID,这俩绝对不会重复,是最可靠的区分依据。 - 查额外属性:比如网络的频段(2.4G/5G)、AP的物理地址(MAC)、加密类型(WPA2/WPA3)、连接历史,这些属性大概率不一样,能帮用户快速区分哪个是家里的、哪个是公司的。
- 让用户自定义标签:在你的工具里加个功能,允许用户给每个相似SSID的网络加备注,比如“客厅5G”“卧室2.4G”,展示时直接显示备注,体验感拉满。
C#代码实现步骤
接下来是具体的C#调用WlanAPI的方法,核心是获取每个WiFi配置文件的唯一标识和详细属性:
1. 准备工作:声明API和结构体
首先需要用DllImport引入wlanapi.dll里的关键函数,同时定义对应的结构体(因为WlanAPI是C++写的,需要在C#里映射这些结构):
using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Xml; // 函数声明 [DllImport("wlanapi.dll", SetLastError = true)] private static extern uint WlanOpenHandle(uint dwClientVersion, IntPtr pReserved, out uint pdwNegotiatedVersion, out IntPtr phClientHandle); [DllImport("wlanapi.dll", SetLastError = true)] private static extern uint WlanEnumInterfaces(IntPtr hClientHandle, IntPtr pReserved, out IntPtr ppInterfaceList); [DllImport("wlanapi.dll", SetLastError = true)] private static extern uint WlanGetProfileList(IntPtr hClientHandle, ref Guid pInterfaceGuid, IntPtr pReserved, out IntPtr ppProfileList); [DllImport("wlanapi.dll", SetLastError = true)] private static extern uint WlanGetProfile(IntPtr hClientHandle, ref Guid pInterfaceGuid, string strProfileName, IntPtr pReserved, out IntPtr ppProfileXml, out WlanProfileFlags pdwFlags, IntPtr pReserved2); [DllImport("wlanapi.dll", SetLastError = true)] private static extern uint WlanFreeMemory(IntPtr pMemory); [DllImport("wlanapi.dll", SetLastError = true)] private static extern uint WlanCloseHandle(IntPtr hClientHandle, IntPtr pReserved); // 结构体和枚举 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WlanInterfaceList { public uint dwNumberOfItems; public uint dwIndex; public IntPtr InterfaceInfo; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WlanInterfaceInfo { public Guid InterfaceGuid; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string strInterfaceDescription; public WlanInterfaceState isState; } public enum WlanInterfaceState { NotReady, Connected, AdHocNetworkFormed, Disconnecting, Disconnected, Associating, Discovering, Authenticating } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WlanProfileList { public uint dwNumberOfItems; public uint dwIndex; public IntPtr ProfileInfo; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct WlanProfileInfo { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string strProfileName; public WlanProfileInfoFlags dwFlags; } [Flags] public enum WlanProfileInfoFlags { None = 0, User = 1, GroupPolicy = 2, AllUser = 4 } public class WiFiProfile { public string ProfileName { get; set; } // 系统生成的唯一配置文件名 public string SSID { get; set; } public string AuthenticationType { get; set; } public string BandInfo { get; set; } // 频段信息(2.4G/5G) }
2. 核心逻辑:获取并解析WiFi配置
下面是获取所有已保存WiFi配置的核心代码,会提取每个配置的唯一名称、SSID、加密类型,还能解析频段信息:
public List<WiFiProfile> GetAllSavedWiFiProfiles() { var profiles = new List<WiFiProfile>(); uint negotiatedVersion; IntPtr clientHandle; // 打开WLAN操作句柄 var result = WlanOpenHandle(2, IntPtr.Zero, out negotiatedVersion, out clientHandle); if (result != 0) throw new Win32Exception((int)result); try { IntPtr interfaceListPtr; result = WlanEnumInterfaces(clientHandle, IntPtr.Zero, out interfaceListPtr); if (result != 0) throw new Win32Exception((int)result); var interfaceList = (WlanInterfaceList)Marshal.PtrToStructure(interfaceListPtr, typeof(WlanInterfaceList)); // 遍历每个无线网卡接口 for (int i = 0; i < interfaceList.dwNumberOfItems; i++) { var interfaceInfo = (WlanInterfaceInfo)Marshal.PtrToStructure( IntPtr.Add(interfaceList.InterfaceInfo, i * Marshal.SizeOf(typeof(WlanInterfaceInfo))), typeof(WlanInterfaceInfo)); IntPtr profileListPtr; result = WlanGetProfileList(clientHandle, ref interfaceInfo.InterfaceGuid, IntPtr.Zero, out profileListPtr); if (result != 0) continue; var profileList = (WlanProfileList)Marshal.PtrToStructure(profileListPtr, typeof(WlanProfileList)); // 遍历每个接口下的WiFi配置文件 for (int j = 0; j < profileList.dwNumberOfItems; j++) { var profileInfo = (WlanProfileInfo)Marshal.PtrToStructure( IntPtr.Add(profileList.ProfileInfo, j * Marshal.SizeOf(typeof(WlanProfileInfo))), typeof(WlanProfileInfo)); // 获取配置文件的XML内容 IntPtr profileXmlPtr; WlanProfileFlags flags; result = WlanGetProfile(clientHandle, ref interfaceInfo.InterfaceGuid, profileInfo.strProfileName, IntPtr.Zero, out profileXmlPtr, out flags, IntPtr.Zero); if (result != 0) continue; var profileXml = Marshal.PtrToStringUni(profileXmlPtr); WlanFreeMemory(profileXmlPtr); // 释放内存 // 解析XML提取关键信息 var doc = new XmlDocument(); doc.LoadXml(profileXml); var nsManager = new XmlNamespaceManager(doc.NameTable); nsManager.AddNamespace("wlan", "http://www.microsoft.com/networking/WLAN/profile/v1"); var ssidNode = doc.SelectSingleNode("//wlan:SSID/wlan:name", nsManager); var authNode = doc.SelectSingleNode("//wlan:authentication", nsManager); // 尝试解析频段(有些配置可能没有,需要结合可用网络列表补充) var bandNode = doc.SelectSingleNode("//wlan:band", nsManager); string bandInfo = bandNode?.InnerText switch { "2.4GHz" => "2.4G频段", "5GHz" => "5G频段", _ => "未知频段" }; profiles.Add(new WiFiProfile { ProfileName = profileInfo.strProfileName, SSID = ssidNode?.InnerText ?? "未知SSID", AuthenticationType = authNode?.InnerText ?? "未知加密", BandInfo = bandInfo }); } } } finally { // 务必关闭句柄释放资源 WlanCloseHandle(clientHandle, IntPtr.Zero); } return profiles; }
3. 展示时的区分方式
拿到WiFiProfile列表后,展示的时候可以这样处理:
var wifiProfiles = GetAllSavedWiFiProfiles(); foreach (var profile in wifiProfiles) { // 优先显示配置文件名(唯一),再展示SSID和其他属性 Console.WriteLine($"* {profile.ProfileName} | SSID: {profile.SSID} | {profile.BandInfo} | 加密: {profile.AuthenticationType}"); }
比如输出会是:
* MyWiFi | SSID: MyWiFi | 2.4G频段 | 加密: WPA2PSK * MyWiFi 2 | SSID: MyWiFi | 5G频段 | 加密: WPA3SAE
这样用户一眼就能区分开两个相同SSID的网络。
额外优化建议
- 结合可用网络列表:如果需要获取AP的MAC地址,可以调用
WlanGetAvailableNetworkListAPI,拿到当前可扫描到的网络的BSSID(MAC),然后和已保存的配置文件关联起来,区分更精准。 - 添加用户自定义标签:在你的工具里加个数据库或配置文件,让用户给每个
ProfileName绑定自定义备注,展示时替换成用户熟悉的名称。 - 可视化区分:用不同的图标或颜色标注2.4G/5G网络,或者加密类型,提升用户体验。
内容的提问来源于stack exchange,提问作者RLH
相关产品推荐
相关产品推荐

