ProjectArcade
846 строк · 28.3 Кб
1using System;2using System.Collections.Generic;3using System.ComponentModel;4using System.Runtime.InteropServices;5using System.Net.NetworkInformation;6using System.Threading;7using System.Text;8
9namespace NativeWifi10{
11/// <summary>12/// Represents a client to the Zeroconf (Native Wifi) service.13/// </summary>14/// <remarks>15/// This class is the entrypoint to Native Wifi management. To manage WiFi settings, create an instance16/// of this class.17/// </remarks>18public class WlanClient : IDisposable19{20/// <summary>21/// Represents a Wifi network interface.22/// </summary>23public class WlanInterface24{25private readonly WlanClient client;26private Wlan.WlanInterfaceInfo info;27
28#region Events29/// <summary>30/// Represents a method that will handle <see cref="WlanNotification"/> events.31/// </summary>32/// <param name="notifyData">The notification data.</param>33public delegate void WlanNotificationEventHandler(Wlan.WlanNotificationData notifyData);34
35/// <summary>36/// Represents a method that will handle <see cref="WlanConnectionNotification"/> events.37/// </summary>38/// <param name="notifyData">The notification data.</param>39/// <param name="connNotifyData">The notification data.</param>40public delegate void WlanConnectionNotificationEventHandler(Wlan.WlanNotificationData notifyData, Wlan.WlanConnectionNotificationData connNotifyData);41
42/// <summary>43/// Represents a method that will handle <see cref="WlanReasonNotification"/> events.44/// </summary>45/// <param name="notifyData">The notification data.</param>46/// <param name="reasonCode">The reason code.</param>47public delegate void WlanReasonNotificationEventHandler(Wlan.WlanNotificationData notifyData, Wlan.WlanReasonCode reasonCode);48
49/// <summary>50/// Occurs when an event of any kind occurs on a WLAN interface.51/// </summary>52public event WlanNotificationEventHandler WlanNotification;53
54/// <summary>55/// Occurs when a WLAN interface changes connection state.56/// </summary>57public event WlanConnectionNotificationEventHandler WlanConnectionNotification;58
59/// <summary>60/// Occurs when a WLAN operation fails due to some reason.61/// </summary>62public event WlanReasonNotificationEventHandler WlanReasonNotification;63
64#endregion65
66#region Event queue67private bool queueEvents;68private readonly AutoResetEvent eventQueueFilled = new AutoResetEvent(false);69private readonly Queue<object> eventQueue = new Queue<object>();70
71private struct WlanConnectionNotificationEventData72{73public Wlan.WlanNotificationData notifyData;74public Wlan.WlanConnectionNotificationData connNotifyData;75}76private struct WlanReasonNotificationData77{78public Wlan.WlanNotificationData notifyData;79public Wlan.WlanReasonCode reasonCode;80}81#endregion82
83internal WlanInterface(WlanClient client, Wlan.WlanInterfaceInfo info)84{85this.client = client;86this.info = info;87}88
89/// <summary>90/// Sets a parameter of the interface whose data type is <see cref="int"/>.91/// </summary>92/// <param name="opCode">The opcode of the parameter.</param>93/// <param name="value">The value to set.</param>94private void SetInterfaceInt(Wlan.WlanIntfOpcode opCode, int value)95{96IntPtr valuePtr = Marshal.AllocHGlobal(sizeof(int));97Marshal.WriteInt32(valuePtr, value);98try99{100Wlan.ThrowIfError(101Wlan.WlanSetInterface(client.clientHandle, info.interfaceGuid, opCode, sizeof(int), valuePtr, IntPtr.Zero));102}103finally104{105Marshal.FreeHGlobal(valuePtr);106}107}108
109/// <summary>110/// Gets a parameter of the interface whose data type is <see cref="int"/>.111/// </summary>112/// <param name="opCode">The opcode of the parameter.</param>113/// <returns>The integer value.</returns>114private int GetInterfaceInt(Wlan.WlanIntfOpcode opCode)115{116IntPtr valuePtr;117int valueSize;118Wlan.WlanOpcodeValueType opcodeValueType;119Wlan.ThrowIfError(120Wlan.WlanQueryInterface(client.clientHandle, info.interfaceGuid, opCode, IntPtr.Zero, out valueSize, out valuePtr, out opcodeValueType));121try122{123return Marshal.ReadInt32(valuePtr);124}125finally126{127Wlan.WlanFreeMemory(valuePtr);128}129}130
131/// <summary>132/// Gets or sets a value indicating whether this <see cref="WlanInterface"/> is automatically configured.133/// </summary>134/// <value><c>true</c> if "autoconf" is enabled; otherwise, <c>false</c>.</value>135public bool Autoconf136{137get138{139return GetInterfaceInt(Wlan.WlanIntfOpcode.AutoconfEnabled) != 0;140}141set142{143SetInterfaceInt(Wlan.WlanIntfOpcode.AutoconfEnabled, value ? 1 : 0);144}145}146
147/// <summary>148/// Gets or sets the BSS type for the indicated interface.149/// </summary>150/// <value>The type of the BSS.</value>151public Wlan.Dot11BssType BssType152{153get154{155return (Wlan.Dot11BssType) GetInterfaceInt(Wlan.WlanIntfOpcode.BssType);156}157set158{159SetInterfaceInt(Wlan.WlanIntfOpcode.BssType, (int)value);160}161}162
163/// <summary>164/// Gets the state of the interface.165/// </summary>166/// <value>The state of the interface.</value>167public Wlan.WlanInterfaceState InterfaceState168{169get170{171return (Wlan.WlanInterfaceState)GetInterfaceInt(Wlan.WlanIntfOpcode.InterfaceState);172}173}174
175/// <summary>176/// Gets the channel.177/// </summary>178/// <value>The channel.</value>179/// <remarks>Not supported on Windows XP SP2.</remarks>180public int Channel181{182get183{184return GetInterfaceInt(Wlan.WlanIntfOpcode.ChannelNumber);185}186}187
188/// <summary>189/// Gets the RSSI.190/// </summary>191/// <value>The RSSI.</value>192/// <remarks>Not supported on Windows XP SP2.</remarks>193public int RSSI194{195get196{197return GetInterfaceInt(Wlan.WlanIntfOpcode.RSSI);198}199}200
201/// <summary>202/// Gets the radio state.203/// </summary>204/// <value>The radio state.</value>205/// <remarks>Not supported on Windows XP.</remarks>206public Wlan.WlanRadioState RadioState207{208get209{210int valueSize;211IntPtr valuePtr;212Wlan.WlanOpcodeValueType opcodeValueType;213Wlan.ThrowIfError(214Wlan.WlanQueryInterface(client.clientHandle, info.interfaceGuid, Wlan.WlanIntfOpcode.RadioState, IntPtr.Zero, out valueSize, out valuePtr, out opcodeValueType));215try216{217return (Wlan.WlanRadioState)Marshal.PtrToStructure(valuePtr, typeof(Wlan.WlanRadioState));218}219finally220{221Wlan.WlanFreeMemory(valuePtr);222}223}224}225
226/// <summary>227/// Gets the current operation mode.228/// </summary>229/// <value>The current operation mode.</value>230/// <remarks>Not supported on Windows XP SP2.</remarks>231public Wlan.Dot11OperationMode CurrentOperationMode232{233get234{235return (Wlan.Dot11OperationMode) GetInterfaceInt(Wlan.WlanIntfOpcode.CurrentOperationMode);236}237}238
239/// <summary>240/// Gets the attributes of the current connection.241/// </summary>242/// <value>The current connection attributes.</value>243/// <exception cref="Win32Exception">An exception with code 0x0000139F (The group or resource is not in the correct state to perform the requested operation.) will be thrown if the interface is not connected to a network.</exception>244public Wlan.WlanConnectionAttributes CurrentConnection245{246get247{248int valueSize;249IntPtr valuePtr;250Wlan.WlanOpcodeValueType opcodeValueType;251Wlan.ThrowIfError(252Wlan.WlanQueryInterface(client.clientHandle, info.interfaceGuid, Wlan.WlanIntfOpcode.CurrentConnection, IntPtr.Zero, out valueSize, out valuePtr, out opcodeValueType));253try254{255return (Wlan.WlanConnectionAttributes)Marshal.PtrToStructure(valuePtr, typeof(Wlan.WlanConnectionAttributes));256}257finally258{259Wlan.WlanFreeMemory(valuePtr);260}261}262}263
264/// <summary>265/// Requests a scan for available networks.266/// </summary>267/// <remarks>268/// The method returns immediately. Progress is reported through the <see cref="WlanNotification"/> event.269/// </remarks>270public void Scan()271{272Wlan.ThrowIfError(273Wlan.WlanScan(client.clientHandle, info.interfaceGuid, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero));274}275
276/// <summary>277/// Converts a pointer to a available networks list (header + entries) to an array of available network entries.278/// </summary>279/// <param name="availNetListPtr">A pointer to an available networks list's header.</param>280/// <returns>An array of available network entries.</returns>281private static Wlan.WlanAvailableNetwork[] ConvertAvailableNetworkListPtr(IntPtr availNetListPtr)282{283Wlan.WlanAvailableNetworkListHeader availNetListHeader = (Wlan.WlanAvailableNetworkListHeader)Marshal.PtrToStructure(availNetListPtr, typeof(Wlan.WlanAvailableNetworkListHeader));284long availNetListIt = availNetListPtr.ToInt64() + Marshal.SizeOf(typeof(Wlan.WlanAvailableNetworkListHeader));285Wlan.WlanAvailableNetwork[] availNets = new Wlan.WlanAvailableNetwork[availNetListHeader.numberOfItems];286for (int i = 0; i < availNetListHeader.numberOfItems; ++i)287{288availNets[i] = (Wlan.WlanAvailableNetwork)Marshal.PtrToStructure(new IntPtr(availNetListIt), typeof(Wlan.WlanAvailableNetwork));289availNetListIt += Marshal.SizeOf(typeof(Wlan.WlanAvailableNetwork));290}291return availNets;292}293
294/// <summary>295/// Retrieves the list of available networks.296/// </summary>297/// <param name="flags">Controls the type of networks returned.</param>298/// <returns>A list of the available networks.</returns>299public Wlan.WlanAvailableNetwork[] GetAvailableNetworkList(Wlan.WlanGetAvailableNetworkFlags flags)300{301IntPtr availNetListPtr;302Wlan.ThrowIfError(303Wlan.WlanGetAvailableNetworkList(client.clientHandle, info.interfaceGuid, flags, IntPtr.Zero, out availNetListPtr));304try305{306return ConvertAvailableNetworkListPtr(availNetListPtr);307}308finally309{310Wlan.WlanFreeMemory(availNetListPtr);311}312}313
314/// <summary>315/// Converts a pointer to a BSS list (header + entries) to an array of BSS entries.316/// </summary>317/// <param name="bssListPtr">A pointer to a BSS list's header.</param>318/// <returns>An array of BSS entries.</returns>319private static Wlan.WlanBssEntry[] ConvertBssListPtr(IntPtr bssListPtr)320{321Wlan.WlanBssListHeader bssListHeader = (Wlan.WlanBssListHeader)Marshal.PtrToStructure(bssListPtr, typeof(Wlan.WlanBssListHeader));322long bssListIt = bssListPtr.ToInt64() + Marshal.SizeOf(typeof(Wlan.WlanBssListHeader));323Wlan.WlanBssEntry[] bssEntries = new Wlan.WlanBssEntry[bssListHeader.numberOfItems];324for (int i=0; i<bssListHeader.numberOfItems; ++i)325{326bssEntries[i] = (Wlan.WlanBssEntry)Marshal.PtrToStructure(new IntPtr(bssListIt), typeof(Wlan.WlanBssEntry));327bssListIt += Marshal.SizeOf(typeof(Wlan.WlanBssEntry));328}329return bssEntries;330}331
332/// <summary>333/// Retrieves the basic service sets (BSS) list of all available networks.334/// </summary>335public Wlan.WlanBssEntry[] GetNetworkBssList()336{337IntPtr bssListPtr;338Wlan.ThrowIfError(339Wlan.WlanGetNetworkBssList(client.clientHandle, info.interfaceGuid, IntPtr.Zero, Wlan.Dot11BssType.Any, false, IntPtr.Zero, out bssListPtr));340try341{342return ConvertBssListPtr(bssListPtr);343}344finally345{346Wlan.WlanFreeMemory(bssListPtr);347}348}349
350/// <summary>351/// Retrieves the basic service sets (BSS) list of the specified network.352/// </summary>353/// <param name="ssid">Specifies the SSID of the network from which the BSS list is requested.</param>354/// <param name="bssType">Indicates the BSS type of the network.</param>355/// <param name="securityEnabled">Indicates whether security is enabled on the network.</param>356public Wlan.WlanBssEntry[] GetNetworkBssList(Wlan.Dot11Ssid ssid, Wlan.Dot11BssType bssType, bool securityEnabled)357{358IntPtr ssidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ssid));359Marshal.StructureToPtr(ssid, ssidPtr, false);360try361{362IntPtr bssListPtr;363Wlan.ThrowIfError(364Wlan.WlanGetNetworkBssList(client.clientHandle, info.interfaceGuid, ssidPtr, bssType, securityEnabled, IntPtr.Zero, out bssListPtr));365try366{367return ConvertBssListPtr(bssListPtr);368}369finally370{371Wlan.WlanFreeMemory(bssListPtr);372}373}374finally375{376Marshal.FreeHGlobal(ssidPtr);377}378}379
380/// <summary>381/// Connects to a network defined by a connection parameters structure.382/// </summary>383/// <param name="connectionParams">The connection paramters.</param>384protected void Connect(Wlan.WlanConnectionParameters connectionParams)385{386Wlan.ThrowIfError(387Wlan.WlanConnect(client.clientHandle, info.interfaceGuid, ref connectionParams, IntPtr.Zero));388}389
390/// <summary>391/// Requests a connection (association) to the specified wireless network.392/// </summary>393/// <remarks>394/// The method returns immediately. Progress is reported through the <see cref="WlanNotification"/> event.395/// </remarks>396public void Connect(Wlan.WlanConnectionMode connectionMode, Wlan.Dot11BssType bssType, string profile)397{398Wlan.WlanConnectionParameters connectionParams = new Wlan.WlanConnectionParameters();399connectionParams.wlanConnectionMode = connectionMode;400connectionParams.profile = profile;401connectionParams.dot11BssType = bssType;402connectionParams.flags = 0;403Connect(connectionParams);404}405
406/// <summary>407/// Connects (associates) to the specified wireless network, returning either on a success to connect408/// or a failure.409/// </summary>410/// <param name="connectionMode"></param>411/// <param name="bssType"></param>412/// <param name="profile"></param>413/// <param name="connectTimeout"></param>414/// <returns></returns>415public bool ConnectSynchronously(Wlan.WlanConnectionMode connectionMode, Wlan.Dot11BssType bssType, string profile, int connectTimeout)416{417queueEvents = true;418try419{420Connect(connectionMode, bssType, profile);421while (queueEvents && eventQueueFilled.WaitOne(connectTimeout, true))422{423lock (eventQueue)424{425while (eventQueue.Count != 0)426{427object e = eventQueue.Dequeue();428if (e is WlanConnectionNotificationEventData)429{430WlanConnectionNotificationEventData wlanConnectionData = (WlanConnectionNotificationEventData)e;431// Check if the conditions are good to indicate either success or failure.432if (wlanConnectionData.notifyData.notificationSource == Wlan.WlanNotificationSource.ACM)433{434switch ((Wlan.WlanNotificationCodeAcm)wlanConnectionData.notifyData.notificationCode)435{436case Wlan.WlanNotificationCodeAcm.ConnectionComplete:437if (wlanConnectionData.connNotifyData.profileName == profile)438return true;439break;440}441}442break;443}444}445}446}447}448finally449{450queueEvents = false;451eventQueue.Clear();452}453return false; // timeout expired and no "connection complete"454}455
456/// <summary>457/// Connects to the specified wireless network.458/// </summary>459/// <remarks>460/// The method returns immediately. Progress is reported through the <see cref="WlanNotification"/> event.461/// </remarks>462public void Connect(Wlan.WlanConnectionMode connectionMode, Wlan.Dot11BssType bssType, Wlan.Dot11Ssid ssid, Wlan.WlanConnectionFlags flags)463{464Wlan.WlanConnectionParameters connectionParams = new Wlan.WlanConnectionParameters();465connectionParams.wlanConnectionMode = connectionMode;466connectionParams.dot11SsidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ssid));467Marshal.StructureToPtr(ssid, connectionParams.dot11SsidPtr, false);468connectionParams.dot11BssType = bssType;469connectionParams.flags = flags;470Connect(connectionParams);471Marshal.DestroyStructure(connectionParams.dot11SsidPtr, ssid.GetType());472Marshal.FreeHGlobal(connectionParams.dot11SsidPtr);473}474
475/// <summary>476/// Deletes a profile.477/// </summary>478/// <param name="profileName">479/// The name of the profile to be deleted. Profile names are case-sensitive.480/// On Windows XP SP2, the supplied name must match the profile name derived automatically from the SSID of the network. For an infrastructure network profile, the SSID must be supplied for the profile name. For an ad hoc network profile, the supplied name must be the SSID of the ad hoc network followed by <c>-adhoc</c>.481/// </param>482public void DeleteProfile(string profileName)483{484Wlan.ThrowIfError(485Wlan.WlanDeleteProfile(client.clientHandle, info.interfaceGuid, profileName, IntPtr.Zero));486}487
488/// <summary>489/// Sets the profile.490/// </summary>491/// <param name="flags">The flags to set on the profile.</param>492/// <param name="profileXml">The XML representation of the profile. On Windows XP SP 2, special care should be taken to adhere to its limitations.</param>493/// <param name="overwrite">If a profile by the given name already exists, then specifies whether to overwrite it (if <c>true</c>) or return an error (if <c>false</c>).</param>494/// <returns>The resulting code indicating a success or the reason why the profile wasn't valid.</returns>495public Wlan.WlanReasonCode SetProfile(Wlan.WlanProfileFlags flags, string profileXml, bool overwrite)496{497Wlan.WlanReasonCode reasonCode;498Wlan.ThrowIfError(499Wlan.WlanSetProfile(client.clientHandle, info.interfaceGuid, flags, profileXml, null, overwrite, IntPtr.Zero, out reasonCode));500return reasonCode;501}502
503/// <summary>504/// Gets the profile's XML specification.505/// </summary>506/// <param name="profileName">The name of the profile.</param>507/// <returns>The XML document.</returns>508public string GetProfileXml(string profileName)509{510IntPtr profileXmlPtr;511Wlan.WlanProfileFlags flags;512Wlan.WlanAccess access;513Wlan.ThrowIfError(514Wlan.WlanGetProfile(client.clientHandle, info.interfaceGuid, profileName, IntPtr.Zero, out profileXmlPtr, out flags,515out access));516try517{518return Marshal.PtrToStringUni(profileXmlPtr);519}520finally521{522Wlan.WlanFreeMemory(profileXmlPtr);523}524}525
526/// <summary>527/// Gets the information of all profiles on this interface.528/// </summary>529/// <returns>The profiles information.</returns>530public Wlan.WlanProfileInfo[] GetProfiles()531{532IntPtr profileListPtr;533Wlan.ThrowIfError(534Wlan.WlanGetProfileList(client.clientHandle, info.interfaceGuid, IntPtr.Zero, out profileListPtr));535try536{537Wlan.WlanProfileInfoListHeader header = (Wlan.WlanProfileInfoListHeader) Marshal.PtrToStructure(profileListPtr, typeof(Wlan.WlanProfileInfoListHeader));538Wlan.WlanProfileInfo[] profileInfos = new Wlan.WlanProfileInfo[header.numberOfItems];539long profileListIterator = profileListPtr.ToInt64() + Marshal.SizeOf(header);540for (int i=0; i<header.numberOfItems; ++i)541{542Wlan.WlanProfileInfo profileInfo = (Wlan.WlanProfileInfo) Marshal.PtrToStructure(new IntPtr(profileListIterator), typeof(Wlan.WlanProfileInfo));543profileInfos[i] = profileInfo;544profileListIterator += Marshal.SizeOf(profileInfo);545}546return profileInfos;547}548finally549{550Wlan.WlanFreeMemory(profileListPtr);551}552}553
554internal void OnWlanConnection(Wlan.WlanNotificationData notifyData, Wlan.WlanConnectionNotificationData connNotifyData)555{556if (WlanConnectionNotification != null)557WlanConnectionNotification(notifyData, connNotifyData);558
559if (queueEvents)560{561WlanConnectionNotificationEventData queuedEvent = new WlanConnectionNotificationEventData();562queuedEvent.notifyData = notifyData;563queuedEvent.connNotifyData = connNotifyData;564EnqueueEvent(queuedEvent);565}566}567
568internal void OnWlanReason(Wlan.WlanNotificationData notifyData, Wlan.WlanReasonCode reasonCode)569{570if (WlanReasonNotification != null)571WlanReasonNotification(notifyData, reasonCode);572if (queueEvents)573{574WlanReasonNotificationData queuedEvent = new WlanReasonNotificationData();575queuedEvent.notifyData = notifyData;576queuedEvent.reasonCode = reasonCode;577EnqueueEvent(queuedEvent);578}579}580
581internal void OnWlanNotification(Wlan.WlanNotificationData notifyData)582{583if (WlanNotification != null)584WlanNotification(notifyData);585}586
587/// <summary>588/// Enqueues a notification event to be processed serially.589/// </summary>590private void EnqueueEvent(object queuedEvent)591{592lock (eventQueue)593eventQueue.Enqueue(queuedEvent);594eventQueueFilled.Set();595}596
597/// <summary>598/// Gets the network interface of this wireless interface.599/// </summary>600/// <remarks>601/// The network interface allows querying of generic network properties such as the interface's IP address.602/// </remarks>603public NetworkInterface NetworkInterface604{605get606{607// Do not cache the NetworkInterface; We need it fresh608// each time cause otherwise it caches the IP information.609foreach (NetworkInterface netIface in NetworkInterface.GetAllNetworkInterfaces())610{611Guid netIfaceGuid = new Guid(netIface.Id);612if (netIfaceGuid.Equals(info.interfaceGuid))613{614return netIface;615}616}617return null;618}619}620
621/// <summary>622/// The GUID of the interface (same content as the <see cref="System.Net.NetworkInformation.NetworkInterface.Id"/> value).623/// </summary>624public Guid InterfaceGuid625{626get { return info.interfaceGuid; }627}628
629/// <summary>630/// The description of the interface.631/// This is a user-immutable string containing the vendor and model name of the adapter.632/// </summary>633public string InterfaceDescription634{635get { return info.interfaceDescription; }636}637
638/// <summary>639/// The friendly name given to the interface by the user (e.g. "Local Area Network Connection").640/// </summary>641public string InterfaceName642{643get { return NetworkInterface.Name; }644}645}646
647private IntPtr clientHandle;648private uint negotiatedVersion;649private readonly Wlan.WlanNotificationCallbackDelegate wlanNotificationCallback;650private readonly Dictionary<Guid,WlanInterface> ifaces = new Dictionary<Guid,WlanInterface>();651
652/// <summary>653/// Creates a new instance of a Native Wifi service client.654/// </summary>655public WlanClient()656{657Wlan.ThrowIfError(658Wlan.WlanOpenHandle(Wlan.WLAN_CLIENT_VERSION_XP_SP2, IntPtr.Zero, out negotiatedVersion, out clientHandle));659try660{661Wlan.WlanNotificationSource prevSrc;662wlanNotificationCallback = OnWlanNotification;663Wlan.ThrowIfError(664Wlan.WlanRegisterNotification(clientHandle, Wlan.WlanNotificationSource.All, false, wlanNotificationCallback, IntPtr.Zero, IntPtr.Zero, out prevSrc));665}666catch667{668Close();669throw;670}671}672
673void IDisposable.Dispose()674{675GC.SuppressFinalize(this);676Close();677}678
679~WlanClient()680{681Close();682}683
684/// <summary>685/// Closes the handle.686/// </summary>687private void Close()688{689if (clientHandle != IntPtr.Zero)690{691Wlan.WlanCloseHandle(clientHandle, IntPtr.Zero);692clientHandle = IntPtr.Zero;693}694}695
696private static Wlan.WlanConnectionNotificationData? ParseWlanConnectionNotification(ref Wlan.WlanNotificationData notifyData)697{698int expectedSize = Marshal.SizeOf(typeof(Wlan.WlanConnectionNotificationData));699if (notifyData.dataSize < expectedSize)700return null;701
702Wlan.WlanConnectionNotificationData connNotifyData =703(Wlan.WlanConnectionNotificationData)704Marshal.PtrToStructure(notifyData.dataPtr, typeof(Wlan.WlanConnectionNotificationData));705if (connNotifyData.wlanReasonCode == Wlan.WlanReasonCode.Success)706{707IntPtr profileXmlPtr = new IntPtr(708notifyData.dataPtr.ToInt64() +709Marshal.OffsetOf(typeof(Wlan.WlanConnectionNotificationData), "profileXml").ToInt64());710connNotifyData.profileXml = Marshal.PtrToStringUni(profileXmlPtr);711}712
713return connNotifyData;714}715
716private void OnWlanNotification(ref Wlan.WlanNotificationData notifyData, IntPtr context)717{718WlanInterface wlanIface;719ifaces.TryGetValue(notifyData.interfaceGuid, out wlanIface);720
721switch(notifyData.notificationSource)722{723case Wlan.WlanNotificationSource.ACM:724switch((Wlan.WlanNotificationCodeAcm)notifyData.notificationCode)725{726case Wlan.WlanNotificationCodeAcm.ConnectionStart:727case Wlan.WlanNotificationCodeAcm.ConnectionComplete:728case Wlan.WlanNotificationCodeAcm.ConnectionAttemptFail:729case Wlan.WlanNotificationCodeAcm.Disconnecting:730case Wlan.WlanNotificationCodeAcm.Disconnected:731Wlan.WlanConnectionNotificationData? connNotifyData = ParseWlanConnectionNotification(ref notifyData);732if (connNotifyData.HasValue)733if (wlanIface != null)734wlanIface.OnWlanConnection(notifyData, connNotifyData.Value);735break;736case Wlan.WlanNotificationCodeAcm.ScanFail:737{738int expectedSize = Marshal.SizeOf(typeof (int));739if (notifyData.dataSize >= expectedSize)740{741Wlan.WlanReasonCode reasonCode = (Wlan.WlanReasonCode) Marshal.ReadInt32(notifyData.dataPtr);742if (wlanIface != null)743wlanIface.OnWlanReason(notifyData, reasonCode);744}745}746break;747}748break;749case Wlan.WlanNotificationSource.MSM:750switch((Wlan.WlanNotificationCodeMsm)notifyData.notificationCode)751{752case Wlan.WlanNotificationCodeMsm.Associating:753case Wlan.WlanNotificationCodeMsm.Associated:754case Wlan.WlanNotificationCodeMsm.Authenticating:755case Wlan.WlanNotificationCodeMsm.Connected:756case Wlan.WlanNotificationCodeMsm.RoamingStart:757case Wlan.WlanNotificationCodeMsm.RoamingEnd:758case Wlan.WlanNotificationCodeMsm.Disassociating:759case Wlan.WlanNotificationCodeMsm.Disconnected:760case Wlan.WlanNotificationCodeMsm.PeerJoin:761case Wlan.WlanNotificationCodeMsm.PeerLeave:762case Wlan.WlanNotificationCodeMsm.AdapterRemoval:763Wlan.WlanConnectionNotificationData? connNotifyData = ParseWlanConnectionNotification(ref notifyData);764if (connNotifyData.HasValue)765if (wlanIface != null)766wlanIface.OnWlanConnection(notifyData, connNotifyData.Value);767break;768}769break;770}771
772if (wlanIface != null)773wlanIface.OnWlanNotification(notifyData);774}775
776/// <summary>777/// Gets the WLAN interfaces.778/// </summary>779/// <value>The WLAN interfaces.</value>780public WlanInterface[] Interfaces781{782get783{784IntPtr ifaceList;785Wlan.ThrowIfError(786Wlan.WlanEnumInterfaces(clientHandle, IntPtr.Zero, out ifaceList));787try788{789Wlan.WlanInterfaceInfoListHeader header =790(Wlan.WlanInterfaceInfoListHeader) Marshal.PtrToStructure(ifaceList, typeof (Wlan.WlanInterfaceInfoListHeader));791Int64 listIterator = ifaceList.ToInt64() + Marshal.SizeOf(header);792WlanInterface[] interfaces = new WlanInterface[header.numberOfItems];793List<Guid> currentIfaceGuids = new List<Guid>();794for (int i = 0; i < header.numberOfItems; ++i)795{796Wlan.WlanInterfaceInfo info =797(Wlan.WlanInterfaceInfo) Marshal.PtrToStructure(new IntPtr(listIterator), typeof (Wlan.WlanInterfaceInfo));798listIterator += Marshal.SizeOf(info);799currentIfaceGuids.Add(info.interfaceGuid);800
801WlanInterface wlanIface;802if (!ifaces.TryGetValue(info.interfaceGuid, out wlanIface))803{804wlanIface = new WlanInterface(this, info);805ifaces[info.interfaceGuid] = wlanIface;806}807
808interfaces[i] = wlanIface;809}810
811// Remove stale interfaces812Queue<Guid> deadIfacesGuids = new Queue<Guid>();813foreach (Guid ifaceGuid in ifaces.Keys)814{815if (!currentIfaceGuids.Contains(ifaceGuid))816deadIfacesGuids.Enqueue(ifaceGuid);817}818while(deadIfacesGuids.Count != 0)819{820Guid deadIfaceGuid = deadIfacesGuids.Dequeue();821ifaces.Remove(deadIfaceGuid);822}823
824return interfaces;825}826finally827{828Wlan.WlanFreeMemory(ifaceList);829}830}831}832
833/// <summary>834/// Gets a string that describes a specified reason code.835/// </summary>836/// <param name="reasonCode">The reason code.</param>837/// <returns>The string.</returns>838public string GetStringForReasonCode(Wlan.WlanReasonCode reasonCode)839{840StringBuilder sb = new StringBuilder(1024); // the 1024 size here is arbitrary; the WlanReasonCodeToString docs fail to specify a recommended size841Wlan.ThrowIfError(842Wlan.WlanReasonCodeToString(reasonCode, sb.Capacity, sb, IntPtr.Zero));843return sb.ToString();844}845}846}
847