//#define PRE_V2_4
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Threading;
using InTheHand.Net.Sockets;
namespace InTheHand.Net.Bluetooth{
/// <summary>
/// Provides simple access to asynchronous methods on Bluetooth features, for
/// instance to background device discovery.
/// </summary>
/// -
/// <example>
/// <code lang="Visual Basic">
/// Public Sub DiscoDevicesAsync()
/// Dim bco As New BluetoothComponent()
/// AddHandler bco.DiscoverDevicesComplete, AddressOf HandleDiscoDevicesAsync
/// bco.DiscoverDevicesAsync(255, True, True, True, False, Nothing)
/// End Sub
///
/// Private Sub HandleDiscoDevicesAsync(ByVal sender As Object, ByVal e As DiscoverDevicesEventArgs)
/// If e.Cancelled Then
/// Console.WriteLine("DiscoDevicesAsync cancelled.")
/// ElseIf e.Error IsNot Nothing Then
/// Console.WriteLine("DiscoDevicesAsync error: {0}.", e.Error.Message)
/// Else
/// Console.WriteLine("DiscoDevicesAsync found {0} devices.", e.Devices.Length)
/// End If
/// End Sub
/// </code>
/// </example>
public class BluetoothComponent : Component
{
BluetoothClient m_cli = new BluetoothClient();
//----
/// <summary>
/// Initializes a new instance of the <see cref="T:BluetoothComponent"/> class.
/// </summary>
public BluetoothComponent()
{
}
/// <summary>
/// Optionally disposes of the managed resources used by the
/// <see cref="T:BluetoothComponent"/> class.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged
/// resources; <c>false</c> to release only unmanaged resources.
/// </param>
protected override void Dispose(bool disposing)
{
try {
m_cli.Dispose();
} finally {
base.Dispose(disposing);
}
}
//----
/// <summary>
/// Occurs when an device discovery operation completes.
/// </summary>
public event EventHandler<DiscoverDevicesEventArgs> DiscoverDevicesComplete;
/// <summary>
/// Raises the <see cref="E:DiscoverDevicesComplete"/> event.
/// </summary>
/// <param name="e">A <see cref="T:InTheHand.Net.Bluetooth.DiscoverDevicesEventArgs"/>
/// object that contains event data.
/// </param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers",
Justification = "It it /not/ visible!")]
protected void OnDiscoveryComplete(DiscoverDevicesEventArgs e)
{
EventHandler<DiscoverDevicesEventArgs> eh = DiscoverDevicesComplete;
if (eh != null) {
eh(this, e);
}
}
/// <summary>
/// Discovers accessible Bluetooth devices and returns their names and addresses.
/// This method does not block the calling thread.
/// </summary>
/// -
/// <remarks>
/// <para>See <see cref="M:InTheHand.Net.Sockets.BluetoothClient.DiscoverDevices(int, bool, bool, bool, bool)"/>
/// for more information.
/// </para>
/// </remarks>
/// -
/// <param name="maxDevices">The maximum number of devices to get information about.
/// </param>
/// <param name="authenticated">True to return previously authenticated/paired devices.
/// </param>
/// <param name="remembered">True to return remembered devices.
/// </param>
/// <param name="unknown">True to return previously unknown devices.
/// </param>
/// <param name="discoverableOnly">True to return only the devices that
/// are in range, and in discoverable mode. See the remarks section.
/// </param>
/// <param name="state">A user-defined object that is passed to the method
/// invoked when the asynchronous operation completes.
/// </param>
/// -
/// <returns>An array of BluetoothDeviceInfo objects describing the devices discovered.</returns>
public void DiscoverDevicesAsync(int maxDevices,
bool authenticated, bool remembered, bool unknown, bool discoverableOnly,
object state)
{
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(state);
#if PRE_V2_4
if (discoverableOnly)
throw new ArgumentException("Flag 'discoverableOnly' is not supported in this version.", "discoverableOnly");
FuncDiscoDevs dlgt = new FuncDiscoDevs(m_cli.DiscoverDevices);
FuncDiscoDevs exist = Interlocked.CompareExchange(ref m_dlgt, dlgt, null);
if (exist != null)
throw new InvalidOperationException("Only support one concurrent operation.");
dlgt.BeginInvoke(maxDevices,
authenticated, remembered, unknown, //discoverableOnly,
HandleDiscoComplete, asyncOp);
#else
m_cli.BeginDiscoverDevices(maxDevices,
authenticated, remembered, unknown, discoverableOnly,
HandleDiscoComplete, asyncOp);
#endif
}
#if PRE_V2_4
delegate BluetoothDeviceInfo[] FuncDiscoDevs(int maxDevices,
bool authenticated, bool remembered, bool unknown/*, bool discoverableOnly*/);
FuncDiscoDevs m_dlgt;
#endif
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
private void HandleDiscoComplete(IAsyncResult ar)
{
AsyncOperation asyncOp = (AsyncOperation)ar.AsyncState;
DiscoverDevicesEventArgs e;
try {
#if PRE_V2_4
FuncDiscoDevs dlgt = Interlocked.Exchange(ref m_dlgt, null);
BluetoothDeviceInfo[] arr = dlgt.EndInvoke(ar);
#else
BluetoothDeviceInfo[] arr = m_cli.EndDiscoverDevices(ar);
#endif
e = new DiscoverDevicesEventArgs(arr, asyncOp.UserSuppliedState);
} catch (Exception ex) {
e = new DiscoverDevicesEventArgs(ex, asyncOp.UserSuppliedState);
// TO-DO ?? Set Cancelled if disposed?
}
//
SendOrPostCallback cb = delegate(object args) {
OnDiscoveryComplete((DiscoverDevicesEventArgs)args);
};
asyncOp.PostOperationCompleted(cb, e);
}
}
/// <summary>
/// Provides data for the <see cref="E:InTheHand.Net.Bluetooth.BluetoothComponent.DiscoverDevicesComplete"/>
/// event.
/// </summary>
public class DiscoverDevicesEventArgs : AsyncCompletedEventArgs
{
BluetoothDeviceInfo[] m_devices;
internal DiscoverDevicesEventArgs(BluetoothDeviceInfo[] devices, object userState)
: base(null, false, userState)
{
m_devices = devices;
}
internal DiscoverDevicesEventArgs(Exception exception, object userState)
: base(exception, false, userState)
{
}
/// <summary>
/// Gets the list of discovered Bluetooth devices.
/// </summary>
public BluetoothDeviceInfo[] Devices
{
get
{
base.RaiseExceptionIfNecessary();
return m_devices;
}
}
}
}
|