1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Net.NetworkInformation;
using System.Threading;
using System.Text;
using Tango.WiFi.Win32.Interop;
using Tango.WiFi.Win32.Helpers;
namespace Tango.WiFi.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.
/// </remarks>
public class WlanClient
{
internal IntPtr clientHandle;
internal uint negotiatedVersion;
internal WlanInterop.WlanNotificationCallbackDelegate wlanNotificationCallback;
private Dictionary<Guid,WlanInterface> ifaces = new Dictionary<Guid,WlanInterface>();
private const int NO_WIFI = 1062;
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_XP_SP2, 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);
}
}
}
}
}
|