123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- using System;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using Vinno.FIS.Sonopost.Wireless.Win32.Helpers;
- using Vinno.FIS.Sonopost.Wireless.Win32.Interop;
- namespace Vinno.FIS.Sonopost.Wireless.Win32
- {
- /// <summary>
- /// Represents a client to the Zeroconf (Native Wifi) service.
- /// </summary>
- /// <remarks>
- /// This class is the entrypoint to Native Wifi management. To manage WiFi settings, create an instance
- /// of this class.11
- /// </remarks>
- public class WlanClient
- {
- private const int NO_WIFI = 1062;
- private readonly Dictionary<Guid, WlanInterface> ifaces = new Dictionary<Guid, WlanInterface>();
- internal IntPtr clientHandle;
- internal uint negotiatedVersion;
- internal WlanInterop.WlanNotificationCallbackDelegate wlanNotificationCallback;
- public bool NoWifiAvailable = false;
- /// <summary>
- /// Creates a new instance of a Native Wifi service client.
- /// Throws Win32 errors: ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY, RPC_STATUS, ERROR_REMOTE_SESSION_LIMIT_EXCEEDED.
- /// </summary>
- public WlanClient()
- {
- int errorCode = 0;
- OperatingSystem osInfo = Environment.OSVersion;
- bool isWinXP =
- osInfo.Platform == PlatformID.Win32NT &&
- osInfo.Version.Major == 5 &&
- osInfo.Version.Minor != 0;
- if (isWinXP && osInfo.ServicePack == "Service Pack 1") // wlanapi not supported in sp1 (or sp2 without hotfix)
- {
- errorCode = NO_WIFI;
- }
- else
- {
- // Perform exception safe init
- // It can be SP2 without hotfix which would generate exception
- try
- {
- errorCode = WlanInterop.WlanOpenHandle(WlanInterop.WLAN_CLIENT_VERSION_LONGHORN, IntPtr.Zero, out negotiatedVersion, out clientHandle);
- }
- catch
- {
- errorCode = NO_WIFI;
- }
- }
- if (errorCode != 0)
- {
- NoWifiAvailable = true;
- return;
- }
- // 1062 = no wifi
- // OK!
- // WlanInterop.ThrowIfError(errorCode);
- try
- {
- // Interop callback
- wlanNotificationCallback = new WlanInterop.WlanNotificationCallbackDelegate(OnWlanNotification);
- WlanNotificationSource prevSrc;
- WlanInterop.ThrowIfError(WlanInterop.WlanRegisterNotification(clientHandle, WlanNotificationSource.All, false, wlanNotificationCallback, IntPtr.Zero, IntPtr.Zero, out prevSrc));
- }
- catch
- {
- WlanInterop.WlanCloseHandle(clientHandle, IntPtr.Zero);
- throw;
- }
- }
- ~WlanClient()
- {
- // Free the handle when deconstructing the client. There won't be a handle if its xp sp 2 without wlanapi installed
- try
- {
- WlanInterop.WlanCloseHandle(clientHandle, IntPtr.Zero);
- }
- catch
- { }
- }
- // Called from interop
- private void OnWlanNotification(ref WlanNotificationData notifyData, IntPtr context)
- {
- if (NoWifiAvailable)
- return;
- WlanInterface wlanIface = ifaces.ContainsKey(notifyData.interfaceGuid) ? ifaces[notifyData.interfaceGuid] : null;
- switch (notifyData.notificationSource)
- {
- case WlanNotificationSource.ACM:
- switch ((WlanNotificationCodeAcm)notifyData.notificationCode)
- {
- case WlanNotificationCodeAcm.ConnectionStart:
- case WlanNotificationCodeAcm.ConnectionComplete:
- case WlanNotificationCodeAcm.ConnectionAttemptFail:
- case WlanNotificationCodeAcm.Disconnecting:
- case WlanNotificationCodeAcm.Disconnected:
- WlanConnectionNotificationData? connNotifyData = WlanHelpers.ParseWlanConnectionNotification(ref notifyData);
- if (connNotifyData.HasValue && wlanIface != null)
- wlanIface.OnWlanConnection(notifyData, connNotifyData.Value);
- break;
- case WlanNotificationCodeAcm.ScanFail:
- int expectedSize = Marshal.SizeOf(typeof(int));
- if (notifyData.dataSize >= expectedSize)
- {
- int reasonInt = Marshal.ReadInt32(notifyData.dataPtr);
- // Want to make sure this doesn't crash if windows sends a reasoncode not defined in the enum.
- if (Enum.IsDefined(typeof(WlanReasonCode), reasonInt))
- {
- WlanReasonCode reasonCode = (WlanReasonCode)reasonInt;
- if (wlanIface != null)
- wlanIface.OnWlanReason(notifyData, reasonCode);
- }
- }
- break;
- }
- break;
- case WlanNotificationSource.MSM:
- switch ((WlanNotificationCodeMsm)notifyData.notificationCode)
- {
- case WlanNotificationCodeMsm.Associating:
- case WlanNotificationCodeMsm.Associated:
- case WlanNotificationCodeMsm.Authenticating:
- case WlanNotificationCodeMsm.Connected:
- case WlanNotificationCodeMsm.RoamingStart:
- case WlanNotificationCodeMsm.RoamingEnd:
- case WlanNotificationCodeMsm.Disassociating:
- case WlanNotificationCodeMsm.Disconnected:
- case WlanNotificationCodeMsm.PeerJoin:
- case WlanNotificationCodeMsm.PeerLeave:
- case WlanNotificationCodeMsm.AdapterRemoval:
- WlanConnectionNotificationData? connNotifyData = WlanHelpers.ParseWlanConnectionNotification(ref notifyData);
- if (connNotifyData.HasValue && wlanIface != null)
- wlanIface.OnWlanConnection(notifyData, connNotifyData.Value);
- break;
- }
- break;
- }
- if (wlanIface != null)
- wlanIface.OnWlanNotification(notifyData);
- }
- /// <summary>
- /// Gets the WLAN interfaces.
- ///
- /// Possible Win32 exceptions:
- ///
- /// ERROR_INVALID_PARAMETER: A parameter is incorrect. This error is returned if the hClientHandle or ppInterfaceList parameter is NULL. This error is returned if the pReserved is not NULL. This error is also returned if the hClientHandle parameter is not valid.
- /// ERROR_INVALID_HANDLE: The handle hClientHandle was not found in the handle table.
- /// RPC_STATUS: Various error codes.
- /// ERROR_NOT_ENOUGH_MEMORY: Not enough memory is available to process this request and allocate memory for the query results.
- /// </summary>
- /// <value>The WLAN interfaces.</value>
- public WlanInterface[] Interfaces
- {
- get
- {
- if (NoWifiAvailable)
- return null;
- IntPtr ifaceList;
- WlanInterop.ThrowIfError(WlanInterop.WlanEnumInterfaces(clientHandle, IntPtr.Zero, out ifaceList));
- try
- {
- WlanInterfaceInfoListHeader header = (WlanInterfaceInfoListHeader)Marshal.PtrToStructure(ifaceList, typeof(WlanInterfaceInfoListHeader));
- Int64 listIterator = ifaceList.ToInt64() + Marshal.SizeOf(header);
- WlanInterface[] interfaces = new WlanInterface[header.numberOfItems];
- List<Guid> currentIfaceGuids = new List<Guid>();
- for (int i = 0; i < header.numberOfItems; ++i)
- {
- WlanInterfaceInfo info = (WlanInterfaceInfo)Marshal.PtrToStructure(new IntPtr(listIterator), typeof(WlanInterfaceInfo));
- listIterator += Marshal.SizeOf(info);
- currentIfaceGuids.Add(info.interfaceGuid);
- WlanInterface wlanIface;
- if (ifaces.ContainsKey(info.interfaceGuid))
- wlanIface = ifaces[info.interfaceGuid];
- else
- wlanIface = new WlanInterface(this, info);
- interfaces[i] = wlanIface;
- ifaces[info.interfaceGuid] = wlanIface;
- }
- // Remove stale interfaces
- Queue<Guid> deadIfacesGuids = new Queue<Guid>();
- foreach (Guid ifaceGuid in ifaces.Keys)
- {
- if (!currentIfaceGuids.Contains(ifaceGuid))
- deadIfacesGuids.Enqueue(ifaceGuid);
- }
- while (deadIfacesGuids.Count != 0)
- {
- Guid deadIfaceGuid = deadIfacesGuids.Dequeue();
- ifaces.Remove(deadIfaceGuid);
- }
- return interfaces;
- }
- finally
- {
- WlanInterop.WlanFreeMemory(ifaceList);
- }
- }
- }
- }
- }
|