ProjectArcade

Форк
0
846 строк · 28.3 Кб
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Runtime.InteropServices;
5
using System.Net.NetworkInformation;
6
using System.Threading;
7
using System.Text;
8

9
namespace NativeWifi
10
{
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 instance
16
	/// of this class.
17
	/// </remarks>
18
	public class WlanClient : IDisposable
19
	{
20
		/// <summary>
21
		/// Represents a Wifi network interface.
22
		/// </summary>
23
		public class WlanInterface
24
		{
25
			private readonly WlanClient client;
26
			private Wlan.WlanInterfaceInfo info;
27

28
			#region Events
29
			/// <summary>
30
			/// Represents a method that will handle <see cref="WlanNotification"/> events.
31
			/// </summary>
32
			/// <param name="notifyData">The notification data.</param>
33
			public 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>
40
			public 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>
47
			public 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>
52
			public event WlanNotificationEventHandler WlanNotification;
53

54
			/// <summary>
55
			/// Occurs when a WLAN interface changes connection state.
56
			/// </summary>
57
			public event WlanConnectionNotificationEventHandler WlanConnectionNotification;
58

59
			/// <summary>
60
			/// Occurs when a WLAN operation fails due to some reason.
61
			/// </summary>
62
			public event WlanReasonNotificationEventHandler WlanReasonNotification;
63

64
			#endregion
65

66
			#region Event queue
67
			private bool queueEvents;
68
			private readonly AutoResetEvent eventQueueFilled = new AutoResetEvent(false);
69
			private readonly Queue<object> eventQueue = new Queue<object>();
70

71
			private struct WlanConnectionNotificationEventData
72
			{
73
				public Wlan.WlanNotificationData notifyData;
74
				public Wlan.WlanConnectionNotificationData connNotifyData;
75
			}
76
			private struct WlanReasonNotificationData
77
			{
78
				public Wlan.WlanNotificationData notifyData;
79
				public Wlan.WlanReasonCode reasonCode;
80
			}
81
			#endregion
82

83
			internal WlanInterface(WlanClient client, Wlan.WlanInterfaceInfo info)
84
			{
85
				this.client = client;
86
				this.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>
94
			private void SetInterfaceInt(Wlan.WlanIntfOpcode opCode, int value)
95
			{
96
				IntPtr valuePtr = Marshal.AllocHGlobal(sizeof(int));
97
				Marshal.WriteInt32(valuePtr, value);
98
				try
99
				{
100
					Wlan.ThrowIfError(
101
						Wlan.WlanSetInterface(client.clientHandle, info.interfaceGuid, opCode, sizeof(int), valuePtr, IntPtr.Zero));
102
				}
103
				finally
104
				{
105
					Marshal.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>
114
			private int GetInterfaceInt(Wlan.WlanIntfOpcode opCode)
115
			{
116
				IntPtr valuePtr;
117
				int valueSize;
118
				Wlan.WlanOpcodeValueType opcodeValueType;
119
				Wlan.ThrowIfError(
120
					Wlan.WlanQueryInterface(client.clientHandle, info.interfaceGuid, opCode, IntPtr.Zero, out valueSize, out valuePtr, out opcodeValueType));
121
				try
122
				{
123
					return Marshal.ReadInt32(valuePtr);
124
				}
125
				finally
126
				{
127
					Wlan.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>
135
			public bool Autoconf
136
			{
137
				get
138
				{
139
					return GetInterfaceInt(Wlan.WlanIntfOpcode.AutoconfEnabled) != 0;
140
				}
141
				set
142
				{
143
					SetInterfaceInt(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>
151
			public Wlan.Dot11BssType BssType
152
			{
153
				get
154
				{
155
					return (Wlan.Dot11BssType) GetInterfaceInt(Wlan.WlanIntfOpcode.BssType);
156
				}
157
				set
158
				{
159
					SetInterfaceInt(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>
167
			public Wlan.WlanInterfaceState InterfaceState
168
			{
169
				get
170
				{
171
					return (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>
180
			public int Channel
181
			{
182
				get
183
				{
184
					return 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>
193
			public int RSSI
194
			{
195
				get
196
				{
197
					return 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>
206
			public Wlan.WlanRadioState RadioState
207
			{
208
				get
209
				{
210
					int valueSize;
211
					IntPtr valuePtr;
212
					Wlan.WlanOpcodeValueType opcodeValueType;
213
					Wlan.ThrowIfError(
214
						Wlan.WlanQueryInterface(client.clientHandle, info.interfaceGuid, Wlan.WlanIntfOpcode.RadioState, IntPtr.Zero, out valueSize, out valuePtr, out opcodeValueType));
215
					try
216
					{
217
						return (Wlan.WlanRadioState)Marshal.PtrToStructure(valuePtr, typeof(Wlan.WlanRadioState));
218
					}
219
					finally
220
					{
221
						Wlan.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>
231
			public Wlan.Dot11OperationMode CurrentOperationMode
232
			{
233
				get
234
				{
235
					return (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>
244
			public Wlan.WlanConnectionAttributes CurrentConnection
245
			{
246
				get
247
				{
248
					int valueSize;
249
					IntPtr valuePtr;
250
					Wlan.WlanOpcodeValueType opcodeValueType;
251
					Wlan.ThrowIfError(
252
						Wlan.WlanQueryInterface(client.clientHandle, info.interfaceGuid, Wlan.WlanIntfOpcode.CurrentConnection, IntPtr.Zero, out valueSize, out valuePtr, out opcodeValueType));
253
					try
254
					{
255
							return (Wlan.WlanConnectionAttributes)Marshal.PtrToStructure(valuePtr, typeof(Wlan.WlanConnectionAttributes));
256
					}
257
					finally
258
					{
259
						Wlan.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>
270
			public void Scan()
271
			{
272
				Wlan.ThrowIfError(
273
					Wlan.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>
281
			private static Wlan.WlanAvailableNetwork[] ConvertAvailableNetworkListPtr(IntPtr availNetListPtr)
282
			{
283
				Wlan.WlanAvailableNetworkListHeader availNetListHeader = (Wlan.WlanAvailableNetworkListHeader)Marshal.PtrToStructure(availNetListPtr, typeof(Wlan.WlanAvailableNetworkListHeader));
284
				long availNetListIt = availNetListPtr.ToInt64() + Marshal.SizeOf(typeof(Wlan.WlanAvailableNetworkListHeader));
285
				Wlan.WlanAvailableNetwork[] availNets = new Wlan.WlanAvailableNetwork[availNetListHeader.numberOfItems];
286
				for (int i = 0; i < availNetListHeader.numberOfItems; ++i)
287
				{
288
					availNets[i] = (Wlan.WlanAvailableNetwork)Marshal.PtrToStructure(new IntPtr(availNetListIt), typeof(Wlan.WlanAvailableNetwork));
289
					availNetListIt += Marshal.SizeOf(typeof(Wlan.WlanAvailableNetwork));
290
				}
291
				return 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>
299
			public Wlan.WlanAvailableNetwork[] GetAvailableNetworkList(Wlan.WlanGetAvailableNetworkFlags flags)
300
			{
301
				IntPtr availNetListPtr;
302
				Wlan.ThrowIfError(
303
					Wlan.WlanGetAvailableNetworkList(client.clientHandle, info.interfaceGuid, flags, IntPtr.Zero, out availNetListPtr));
304
				try
305
				{
306
					return ConvertAvailableNetworkListPtr(availNetListPtr);
307
				}
308
				finally
309
				{
310
					Wlan.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>
319
			private static Wlan.WlanBssEntry[] ConvertBssListPtr(IntPtr bssListPtr)
320
			{
321
				Wlan.WlanBssListHeader bssListHeader = (Wlan.WlanBssListHeader)Marshal.PtrToStructure(bssListPtr, typeof(Wlan.WlanBssListHeader));
322
				long bssListIt = bssListPtr.ToInt64() + Marshal.SizeOf(typeof(Wlan.WlanBssListHeader));
323
				Wlan.WlanBssEntry[] bssEntries = new Wlan.WlanBssEntry[bssListHeader.numberOfItems];
324
				for (int i=0; i<bssListHeader.numberOfItems; ++i)
325
				{
326
					bssEntries[i] = (Wlan.WlanBssEntry)Marshal.PtrToStructure(new IntPtr(bssListIt), typeof(Wlan.WlanBssEntry));
327
					bssListIt += Marshal.SizeOf(typeof(Wlan.WlanBssEntry));
328
				}
329
				return bssEntries;
330
			}
331

332
			/// <summary>
333
			/// Retrieves the basic service sets (BSS) list of all available networks.
334
			/// </summary>
335
			public Wlan.WlanBssEntry[] GetNetworkBssList()
336
			{
337
				IntPtr bssListPtr;
338
				Wlan.ThrowIfError(
339
					Wlan.WlanGetNetworkBssList(client.clientHandle, info.interfaceGuid, IntPtr.Zero, Wlan.Dot11BssType.Any, false, IntPtr.Zero, out bssListPtr));
340
				try
341
				{
342
					return ConvertBssListPtr(bssListPtr);
343
				}
344
				finally
345
				{
346
					Wlan.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>
356
			public Wlan.WlanBssEntry[] GetNetworkBssList(Wlan.Dot11Ssid ssid, Wlan.Dot11BssType bssType, bool securityEnabled)
357
			{
358
				IntPtr ssidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ssid));
359
				Marshal.StructureToPtr(ssid, ssidPtr, false);
360
				try
361
				{
362
					IntPtr bssListPtr;
363
					Wlan.ThrowIfError(
364
						Wlan.WlanGetNetworkBssList(client.clientHandle, info.interfaceGuid, ssidPtr, bssType, securityEnabled, IntPtr.Zero, out bssListPtr));
365
					try
366
					{
367
						return ConvertBssListPtr(bssListPtr);
368
					}
369
					finally
370
					{
371
						Wlan.WlanFreeMemory(bssListPtr);
372
					}
373
				}
374
				finally
375
				{
376
					Marshal.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>
384
			protected void Connect(Wlan.WlanConnectionParameters connectionParams)
385
			{
386
				Wlan.ThrowIfError(
387
					Wlan.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>
396
			public void Connect(Wlan.WlanConnectionMode connectionMode, Wlan.Dot11BssType bssType, string profile)
397
			{
398
				Wlan.WlanConnectionParameters connectionParams = new Wlan.WlanConnectionParameters();
399
				connectionParams.wlanConnectionMode = connectionMode;
400
				connectionParams.profile = profile;
401
				connectionParams.dot11BssType = bssType;
402
				connectionParams.flags = 0;
403
				Connect(connectionParams);
404
			}
405
			
406
			/// <summary>
407
			/// Connects (associates) to the specified wireless network, returning either on a success to connect
408
			/// 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>
415
			public bool ConnectSynchronously(Wlan.WlanConnectionMode connectionMode, Wlan.Dot11BssType bssType, string profile, int connectTimeout)
416
			{
417
				queueEvents = true;
418
				try
419
				{
420
					Connect(connectionMode, bssType, profile);
421
					while (queueEvents && eventQueueFilled.WaitOne(connectTimeout, true))
422
					{
423
						lock (eventQueue)
424
						{
425
							while (eventQueue.Count != 0)
426
							{
427
								object e = eventQueue.Dequeue();
428
								if (e is WlanConnectionNotificationEventData)
429
								{
430
									WlanConnectionNotificationEventData wlanConnectionData = (WlanConnectionNotificationEventData)e;
431
									// Check if the conditions are good to indicate either success or failure.
432
									if (wlanConnectionData.notifyData.notificationSource == Wlan.WlanNotificationSource.ACM)
433
									{
434
										switch ((Wlan.WlanNotificationCodeAcm)wlanConnectionData.notifyData.notificationCode)
435
										{
436
											case Wlan.WlanNotificationCodeAcm.ConnectionComplete:
437
												if (wlanConnectionData.connNotifyData.profileName == profile)
438
													return true;
439
												break;
440
										}
441
									}
442
									break;
443
								}
444
							}
445
						}
446
					}
447
				}
448
				finally
449
				{
450
					queueEvents = false;
451
					eventQueue.Clear();
452
				}
453
				return 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>
462
			public void Connect(Wlan.WlanConnectionMode connectionMode, Wlan.Dot11BssType bssType, Wlan.Dot11Ssid ssid, Wlan.WlanConnectionFlags flags)
463
			{
464
				Wlan.WlanConnectionParameters connectionParams = new Wlan.WlanConnectionParameters();
465
				connectionParams.wlanConnectionMode = connectionMode;
466
				connectionParams.dot11SsidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(ssid));
467
				Marshal.StructureToPtr(ssid, connectionParams.dot11SsidPtr, false);
468
				connectionParams.dot11BssType = bssType;
469
				connectionParams.flags = flags;
470
				Connect(connectionParams);
471
				Marshal.DestroyStructure(connectionParams.dot11SsidPtr, ssid.GetType());
472
				Marshal.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>
482
			public void DeleteProfile(string profileName)
483
			{
484
				Wlan.ThrowIfError(
485
					Wlan.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>
495
			public Wlan.WlanReasonCode SetProfile(Wlan.WlanProfileFlags flags, string profileXml, bool overwrite)
496
			{
497
				Wlan.WlanReasonCode reasonCode;
498
				Wlan.ThrowIfError(
499
						Wlan.WlanSetProfile(client.clientHandle, info.interfaceGuid, flags, profileXml, null, overwrite, IntPtr.Zero, out reasonCode));
500
				return 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>
508
			public string GetProfileXml(string profileName)
509
			{
510
				IntPtr profileXmlPtr;
511
				Wlan.WlanProfileFlags flags;
512
				Wlan.WlanAccess access;
513
				Wlan.ThrowIfError(
514
					Wlan.WlanGetProfile(client.clientHandle, info.interfaceGuid, profileName, IntPtr.Zero, out profileXmlPtr, out flags,
515
								   out access));
516
				try
517
				{
518
					return Marshal.PtrToStringUni(profileXmlPtr);
519
				}
520
				finally
521
				{
522
					Wlan.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>
530
			public Wlan.WlanProfileInfo[] GetProfiles()
531
			{
532
				IntPtr profileListPtr;
533
				Wlan.ThrowIfError(
534
					Wlan.WlanGetProfileList(client.clientHandle, info.interfaceGuid, IntPtr.Zero, out profileListPtr));
535
				try
536
				{
537
					Wlan.WlanProfileInfoListHeader header = (Wlan.WlanProfileInfoListHeader) Marshal.PtrToStructure(profileListPtr, typeof(Wlan.WlanProfileInfoListHeader));
538
					Wlan.WlanProfileInfo[] profileInfos = new Wlan.WlanProfileInfo[header.numberOfItems];
539
					long profileListIterator = profileListPtr.ToInt64() + Marshal.SizeOf(header);
540
					for (int i=0; i<header.numberOfItems; ++i)
541
					{
542
						Wlan.WlanProfileInfo profileInfo = (Wlan.WlanProfileInfo) Marshal.PtrToStructure(new IntPtr(profileListIterator), typeof(Wlan.WlanProfileInfo));
543
						profileInfos[i] = profileInfo;
544
						profileListIterator += Marshal.SizeOf(profileInfo);
545
					}
546
					return profileInfos;
547
				}
548
				finally
549
				{
550
					Wlan.WlanFreeMemory(profileListPtr);
551
				}
552
			}
553

554
			internal void OnWlanConnection(Wlan.WlanNotificationData notifyData, Wlan.WlanConnectionNotificationData connNotifyData)
555
			{
556
				if (WlanConnectionNotification != null)
557
					WlanConnectionNotification(notifyData, connNotifyData);
558

559
				if (queueEvents)
560
				{
561
					WlanConnectionNotificationEventData queuedEvent = new WlanConnectionNotificationEventData();
562
					queuedEvent.notifyData = notifyData;
563
					queuedEvent.connNotifyData = connNotifyData;
564
					EnqueueEvent(queuedEvent);
565
				}
566
			}
567

568
			internal void OnWlanReason(Wlan.WlanNotificationData notifyData, Wlan.WlanReasonCode reasonCode)
569
			{
570
				if (WlanReasonNotification != null)
571
					WlanReasonNotification(notifyData, reasonCode);
572
				if (queueEvents)
573
				{
574
					WlanReasonNotificationData queuedEvent = new WlanReasonNotificationData();
575
					queuedEvent.notifyData = notifyData;
576
					queuedEvent.reasonCode = reasonCode;
577
					EnqueueEvent(queuedEvent);
578
				}
579
			}
580

581
			internal void OnWlanNotification(Wlan.WlanNotificationData notifyData)
582
			{
583
				if (WlanNotification != null)
584
					WlanNotification(notifyData);
585
			}
586

587
			/// <summary>
588
			/// Enqueues a notification event to be processed serially.
589
			/// </summary>
590
			private void EnqueueEvent(object queuedEvent)
591
			{
592
				lock (eventQueue)
593
					eventQueue.Enqueue(queuedEvent);
594
				eventQueueFilled.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>
603
			public NetworkInterface NetworkInterface
604
			{
605
				get
606
				{
607
					// Do not cache the NetworkInterface; We need it fresh
608
					// each time cause otherwise it caches the IP information.
609
					foreach (NetworkInterface netIface in NetworkInterface.GetAllNetworkInterfaces())
610
					{
611
						Guid netIfaceGuid = new Guid(netIface.Id);
612
						if (netIfaceGuid.Equals(info.interfaceGuid))
613
						{
614
							return netIface;
615
						}
616
					}
617
					return 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>
624
			public Guid InterfaceGuid
625
			{
626
				get { 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>
633
			public string InterfaceDescription
634
			{
635
				get { 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>
641
			public string InterfaceName
642
			{
643
				get { return NetworkInterface.Name; }
644
			}
645
		}
646

647
		private IntPtr clientHandle;
648
		private uint negotiatedVersion;
649
		private readonly Wlan.WlanNotificationCallbackDelegate wlanNotificationCallback;
650
		private 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>
655
		public WlanClient()
656
		{
657
			Wlan.ThrowIfError(
658
				Wlan.WlanOpenHandle(Wlan.WLAN_CLIENT_VERSION_XP_SP2, IntPtr.Zero, out negotiatedVersion, out clientHandle));
659
			try
660
			{
661
				Wlan.WlanNotificationSource prevSrc;
662
				wlanNotificationCallback = OnWlanNotification;
663
				Wlan.ThrowIfError(
664
					Wlan.WlanRegisterNotification(clientHandle, Wlan.WlanNotificationSource.All, false, wlanNotificationCallback, IntPtr.Zero, IntPtr.Zero, out prevSrc));
665
			}
666
			catch
667
			{
668
				Close();
669
				throw;
670
			}
671
		}
672

673
		void IDisposable.Dispose()
674
		{
675
			GC.SuppressFinalize(this);
676
			Close();
677
		}
678

679
		~WlanClient()
680
		{
681
			Close();
682
		}
683

684
		/// <summary>
685
		/// Closes the handle.
686
		/// </summary>
687
		private void Close()
688
		{
689
			if (clientHandle != IntPtr.Zero)
690
			{
691
				Wlan.WlanCloseHandle(clientHandle, IntPtr.Zero);
692
				clientHandle = IntPtr.Zero;
693
			}
694
		}
695

696
		private static Wlan.WlanConnectionNotificationData? ParseWlanConnectionNotification(ref Wlan.WlanNotificationData notifyData)
697
		{
698
			int expectedSize = Marshal.SizeOf(typeof(Wlan.WlanConnectionNotificationData));
699
			if (notifyData.dataSize < expectedSize)
700
				return null;
701

702
			Wlan.WlanConnectionNotificationData connNotifyData =
703
				(Wlan.WlanConnectionNotificationData)
704
				Marshal.PtrToStructure(notifyData.dataPtr, typeof(Wlan.WlanConnectionNotificationData));
705
			if (connNotifyData.wlanReasonCode == Wlan.WlanReasonCode.Success)
706
			{
707
				IntPtr profileXmlPtr = new IntPtr(
708
					notifyData.dataPtr.ToInt64() +
709
					Marshal.OffsetOf(typeof(Wlan.WlanConnectionNotificationData), "profileXml").ToInt64());
710
				connNotifyData.profileXml = Marshal.PtrToStringUni(profileXmlPtr);
711
			}
712

713
			return connNotifyData;
714
		}
715

716
		private void OnWlanNotification(ref Wlan.WlanNotificationData notifyData, IntPtr context)
717
		{
718
			WlanInterface wlanIface;
719
			ifaces.TryGetValue(notifyData.interfaceGuid, out wlanIface);
720

721
			switch(notifyData.notificationSource)
722
			{
723
				case Wlan.WlanNotificationSource.ACM:
724
					switch((Wlan.WlanNotificationCodeAcm)notifyData.notificationCode)
725
					{
726
						case Wlan.WlanNotificationCodeAcm.ConnectionStart:
727
						case Wlan.WlanNotificationCodeAcm.ConnectionComplete:
728
						case Wlan.WlanNotificationCodeAcm.ConnectionAttemptFail:
729
						case Wlan.WlanNotificationCodeAcm.Disconnecting:
730
						case Wlan.WlanNotificationCodeAcm.Disconnected:
731
							Wlan.WlanConnectionNotificationData? connNotifyData = ParseWlanConnectionNotification(ref notifyData);
732
							if (connNotifyData.HasValue)
733
								if (wlanIface != null)
734
									wlanIface.OnWlanConnection(notifyData, connNotifyData.Value);
735
							break;
736
						case Wlan.WlanNotificationCodeAcm.ScanFail:
737
							{
738
								int expectedSize = Marshal.SizeOf(typeof (int));
739
								if (notifyData.dataSize >= expectedSize)
740
								{
741
									Wlan.WlanReasonCode reasonCode = (Wlan.WlanReasonCode) Marshal.ReadInt32(notifyData.dataPtr);
742
									if (wlanIface != null)
743
										wlanIface.OnWlanReason(notifyData, reasonCode);
744
								}
745
							}
746
							break;
747
					}
748
					break;
749
				case Wlan.WlanNotificationSource.MSM:
750
					switch((Wlan.WlanNotificationCodeMsm)notifyData.notificationCode)
751
					{
752
						case Wlan.WlanNotificationCodeMsm.Associating:
753
						case Wlan.WlanNotificationCodeMsm.Associated:
754
						case Wlan.WlanNotificationCodeMsm.Authenticating:
755
						case Wlan.WlanNotificationCodeMsm.Connected:
756
						case Wlan.WlanNotificationCodeMsm.RoamingStart:
757
						case Wlan.WlanNotificationCodeMsm.RoamingEnd:
758
						case Wlan.WlanNotificationCodeMsm.Disassociating:
759
						case Wlan.WlanNotificationCodeMsm.Disconnected:
760
						case Wlan.WlanNotificationCodeMsm.PeerJoin:
761
						case Wlan.WlanNotificationCodeMsm.PeerLeave:
762
						case Wlan.WlanNotificationCodeMsm.AdapterRemoval:
763
							Wlan.WlanConnectionNotificationData? connNotifyData = ParseWlanConnectionNotification(ref notifyData);
764
							if (connNotifyData.HasValue)
765
								if (wlanIface != null)
766
									wlanIface.OnWlanConnection(notifyData, connNotifyData.Value);
767
							break;
768
					}
769
					break;
770
			}
771
			
772
			if (wlanIface != null)
773
				wlanIface.OnWlanNotification(notifyData);
774
		}
775

776
		/// <summary>
777
		/// Gets the WLAN interfaces.
778
		/// </summary>
779
		/// <value>The WLAN interfaces.</value>
780
		public WlanInterface[] Interfaces
781
		{
782
			get
783
			{
784
				IntPtr ifaceList;
785
				Wlan.ThrowIfError(
786
					Wlan.WlanEnumInterfaces(clientHandle, IntPtr.Zero, out ifaceList));
787
				try
788
				{
789
					Wlan.WlanInterfaceInfoListHeader header =
790
						(Wlan.WlanInterfaceInfoListHeader) Marshal.PtrToStructure(ifaceList, typeof (Wlan.WlanInterfaceInfoListHeader));
791
					Int64 listIterator = ifaceList.ToInt64() + Marshal.SizeOf(header);
792
					WlanInterface[] interfaces = new WlanInterface[header.numberOfItems];
793
					List<Guid> currentIfaceGuids = new List<Guid>();
794
					for (int i = 0; i < header.numberOfItems; ++i)
795
					{
796
						Wlan.WlanInterfaceInfo info =
797
							(Wlan.WlanInterfaceInfo) Marshal.PtrToStructure(new IntPtr(listIterator), typeof (Wlan.WlanInterfaceInfo));
798
						listIterator += Marshal.SizeOf(info);
799
						currentIfaceGuids.Add(info.interfaceGuid);
800

801
						WlanInterface wlanIface;
802
						if (!ifaces.TryGetValue(info.interfaceGuid, out wlanIface))
803
						{
804
							wlanIface = new WlanInterface(this, info);
805
							ifaces[info.interfaceGuid] = wlanIface;
806
						}
807

808
						interfaces[i] = wlanIface;
809
					}
810

811
					// Remove stale interfaces
812
					Queue<Guid> deadIfacesGuids = new Queue<Guid>();
813
					foreach (Guid ifaceGuid in ifaces.Keys)
814
					{
815
						if (!currentIfaceGuids.Contains(ifaceGuid))
816
							deadIfacesGuids.Enqueue(ifaceGuid);
817
					}
818
					while(deadIfacesGuids.Count != 0)
819
					{
820
						Guid deadIfaceGuid = deadIfacesGuids.Dequeue();
821
						ifaces.Remove(deadIfaceGuid);
822
					}
823

824
					return interfaces;
825
				}
826
				finally
827
				{
828
					Wlan.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>
838
		public string GetStringForReasonCode(Wlan.WlanReasonCode reasonCode)
839
		{
840
			StringBuilder sb = new StringBuilder(1024); // the 1024 size here is arbitrary; the WlanReasonCodeToString docs fail to specify a recommended size
841
			Wlan.ThrowIfError(
842
				Wlan.WlanReasonCodeToString(reasonCode, sb.Capacity, sb, IntPtr.Zero));
843
			return sb.ToString();
844
		}
845
	}
846
}
847

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.