// 32feet.NET - Personal Area Networking for .NET
//
// InTheHand.Net.Widcomm.WidcommSocketExceptions
//
// Copyright (c) 2008-2010 In The Hand Ltd, All rights reserved.
// Copyright (c) 2008-2010 Alan J. McFarlane, All rights reserved.
// This source code is licensed under the In The Hand Community License - see License.txt
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using InTheHand.Net.Sockets;
using System.Diagnostics;
using Microsoft.Win32;
using System.Diagnostics.CodeAnalysis;
using InTheHand.Net.Bluetooth.Factory;
using List_IBluetoothDeviceInfoSystem.Collections.Generic.ListInTheHand.Net.Bluetooth.Factory.IBluetoothDeviceInfo;
using AR_InquiryInTheHand.Net.AsyncResultSystem.Collections.Generic.ListInTheHand.Net.Bluetooth.Factory.IBluetoothDeviceInfo;
using System.Threading;
namespace InTheHand.Net.Bluetooth.Widcomm{
internal sealed class WidcommBtInterface : IDisposable
{
readonly WidcommBluetoothFactoryBase m_factory;
readonly IBtIf m_btIf;
//
#if WIDCOMM_SINGLE_THREADING
// The Win32 Widcomm documentation says 'don't call back into the API on a
// thread where the API raised a callback'. So we have to detect this situation
// and launch the API call on a new thread.
// This is apparently not the case on CE/WM,
// and here they don't support ThreadStatic anyway.
// Note because this is ThreadStatic it obviously doesn't need thread-safe access.
#if !NETCF
[ThreadStatic]
static int _InWidcommCallbackThreadCount;
[ThreadStatic]
public static bool _IsWidcommSingleThread;
#endif
static readonly LocalDataStoreSlot _slotIsWidcommSingleThread, _slotInWidcommCallbackThreadCount;
#endif
static WidcommBtInterface()
{
#if WIDCOMM_SINGLE_THREADING
_slotIsWidcommSingleThread = Thread.AllocateNamedDataSlot("_IsWidcommSingleThread");
_slotInWidcommCallbackThreadCount = Thread.AllocateNamedDataSlot("_InWidcommCallbackThreadCount");
#endif
}
internal WidcommBtInterface(IBtIf btIf, WidcommBluetoothFactoryBase factory)
{
m_factory = factory;
bool created = false;
try {
m_btIf = btIf;
m_btIf.SetParent(this);
// "An object of this class must be instantiated before any other DK classes are used"
m_btIf.Create();
created = true;
} finally {
if (!created) { GC.SuppressFinalize(this); }
}
}
//----
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~WidcommBtInterface()
{
Dispose(false);
}
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")]
void Dispose(bool disposing)
{
m_btIf.Destroy(disposing);
}
//-----------------------------
object lockInquiry = new object();
AR_Inquiry m_arInquiry;
List_IBluetoothDeviceInfo m_inquiryDevices;
List<AR_Inquiry> m_arInquiryFollowers;
//----------
internal IAsyncResult BeginInquiry(int maxDevices, bool authenticated, bool remembered, bool unknown,
TimeSpan inquiryLength,
AsyncCallback asyncCallback, Object state)
{
int fakeUseI = maxDevices;
bool fackUseB = authenticated = remembered = unknown;
AR_Inquiry ar;
AR_Inquiry sacAr = null;
List_IBluetoothDeviceInfo sacResult = null;
lock (lockInquiry) {
if (m_arInquiry != null) {
Debug.Fail("This use of multiple concurrent DiscoverDevices calls on Widcomm is COMPLETELY untested!");
// Just give any new request the same results as the outstanding Inquiry.
ar = new AR_Inquiry(asyncCallback, state);
if (m_arInquiry.IsCompleted) {
// This can never occur (is nulled before SAC'd), but leave in anyway...
sacAr = ar;
sacResult = m_inquiryDevices;
} else {
if (m_arInquiryFollowers == null)
m_arInquiryFollowers = new List<AR_Inquiry>();
m_arInquiryFollowers.Add(ar);
}
} else { // New inquiry process.
ar = new AR_Inquiry(asyncCallback, state);
m_arInquiry = ar;
m_arInquiryFollowers = null;
m_inquiryDevices = new List_IBluetoothDeviceInfo();
bool siSuccess=false;
try {
StartInquiry();
siSuccess = true;
} finally {
if (!siSuccess) { m_arInquiry = null; }
}
if (inquiryLength.CompareTo(TimeSpan.Zero) > 0) {
System.Threading.ThreadPool.QueueUserWorkItem(_InquiryTimeoutRunner,
new InquiryTimeoutParams(ar, inquiryLength));
}
}
}//lock
if (sacAr != null) {
sacAr.SetAsCompleted(sacResult, true);
}
return ar;
}
private void StartInquiry() // We are inside the lock.
{
// TO-DO Need to use the InquiryLength property and then return whatever devices
// we've got by that point.
//
bool success = m_btIf.StartInquiry();
if (!success)
throw WidcommSocketExceptions.Create_StartInquiry("StartInquiry");
}
internal void HandleDeviceResponded(byte[] bdAddr, byte[] devClass,
byte[] deviceName, bool connected)
{
EntryIsWidcommThread();
WidcommUtils.Trace_WriteLine("HandleDeviceResponded");
lock (lockInquiry) {
WidcommUtils.Trace_WriteLine("HDR: {0} {1} {2} {3}",
ToStringQuotedOrNull(bdAddr), ToStringQuotedOrNull(devClass),
ToStringQuotedOrNull(deviceName), connected);
if (m_inquiryDevices == null) {
Debug.Assert(TestUtilities.IsUnderTestHarness(), "HandleDeviceResponded without DD i.e. m_inquiryDevices == null.");
goto exit;
}
IBluetoothDeviceInfo bdi = WidcommBluetoothDeviceInfo.CreateFromHandleDeviceResponded(
bdAddr, deviceName, devClass, connected, m_factory);
int idx = BluetoothDeviceInfo.ListIndexOf(m_inquiryDevices, bdi);
AssertManualExistsIf(idx, m_inquiryDevices, bdi);
if (idx == -1) {
m_inquiryDevices.Add(bdi);
} else {
WidcommUtils.Trace_WriteLine("Replace.");
// Check the new info versus the previously discovered device.
IBluetoothDeviceInfo bdiOld = m_inquiryDevices[idx];
Debug.Assert(bdiOld.DeviceAddress.Equals(bdi.DeviceAddress));
Debug.Assert(deviceName != null);
Debug.Assert(deviceName.Length != 0);
//Debug.Assert(bdiOld.ClassOfDevice.Equals(bdi.ClassOfDevice));
// Replace
m_inquiryDevices[idx] = bdi;
}
}
exit:
WidcommUtils.Trace_WriteLine("exit HDR");
ExitIsWidcommThread();
}
[Conditional("DEBUG")]
private void AssertManualExistsIf(int index, List_IBluetoothDeviceInfo list, IBluetoothDeviceInfo item)
{
bool found = false;
foreach (IBluetoothDeviceInfo cur in list) {
if (cur.DeviceAddress == item.DeviceAddress)
found = true;
}
Debug.Assert(found == (index != -1), "manual found != list->object found");
}
private static string ToStringQuotedOrNull(byte[] array)
{
if (array == null)
return "(null)";
else
return "\"" + BitConverter.ToString(array) + "\"";
}
internal void HandleInquiryComplete(bool success, UInt16 numResponses)
{
EntryIsWidcommThread();
WidcommUtils.Trace_WriteLine("HandleInquiryComplete");
HandleInquiryComplete_Internal(success, numResponses);
WidcommUtils.Trace_WriteLine("exit HandleInquiryComplete");
ExitIsWidcommThread();
}
internal void HandleInquiryComplete_Internal(bool success, UInt16 numResponses)
{
AR_Inquiry sacAr;
List<AR_Inquiry> sacArFollowers = null;
List_IBluetoothDeviceInfo sacResult;
lock (lockInquiry) {
m_btIf.StopInquiry();
sacAr = m_arInquiry;
sacResult = m_inquiryDevices;
m_arInquiry = null;
if (m_arInquiryFollowers != null) {
sacArFollowers = m_arInquiryFollowers;
m_arInquiryFollowers = null;
}
}//lock
WaitCallback dlgt = delegate {
RaiseInquiryComplete(sacAr, sacResult, sacArFollowers);
};
ThreadPool.QueueUserWorkItem(dlgt);
}
static void RaiseInquiryComplete(AR_Inquiry sacAr,
List_IBluetoothDeviceInfo sacResult, List<AR_Inquiry> sacArFollowers)
{
if (sacAr != null) {
sacAr.SetAsCompleted(sacResult, false);
if (sacArFollowers != null) {
foreach (AR_Inquiry ar in sacArFollowers)
ar.SetAsCompleted(sacResult, false);
}
}
}
internal List_IBluetoothDeviceInfo EndInquiry(IAsyncResult ar)
{
// (Can't lock here as that would block the callback methods).
// Check is one of queued ar. However this function is only called from
// inside BluetoothClient.DiscoverDevices so we can be less careful/helpful!!
AR_Inquiry ar2 = (AR_Inquiry)ar;
return ar2.EndInvoke();
}
struct InquiryTimeoutParams
{
internal readonly IAsyncResult _ar;
internal readonly TimeSpan _InquiryLength;
public InquiryTimeoutParams(AR_Inquiry ar, TimeSpan inquiryLength)
{
_ar = ar;
_InquiryLength = inquiryLength;
}
/// <summary>
/// Get timeout value in Int32 milliseconds,
/// as NETCF <c>WaitHandle.WaitOne</c> can't use TimeSpan.
/// </summary>
/// -
/// <returns>An Int32 containing the timeout value in milliseconds.
/// </returns>
internal int InquiryLengthAsMiliseconds()
{
double ms0 = this._InquiryLength.TotalMilliseconds;
int ms = checked((int)ms0);
return ms;
}
}
void _InquiryTimeoutRunner(object state)
{
InquiryTimeoutParams args = (InquiryTimeoutParams)state;
bool completed = args._ar.AsyncWaitHandle.WaitOne(args.InquiryLengthAsMiliseconds(), false);
if (completed)
return;
lock (lockInquiry) {
if (args._ar.IsCompleted) // It won the race to enter the lock.
return;
object arDD = m_arInquiry;
// TO-DO What if its in the 'followers' list.
if (arDD == null) // etc
return;
if (arDD != args._ar)
return;
HandleInquiryComplete_Internal(false, unchecked((ushort)-1));
WidcommUtils.Trace_WriteLine("Cancelling Inquiry due to timeout.");
Debug.Assert(m_arInquiry == null, "NOT m_arInquiry==null after (timed-out) completion.");
}
}
//----------
const int MaxNumberSdpRecords = 10;
//
object lockServiceDiscovery = new object();
AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams> m_arServiceDiscovery;
public IAsyncResult BeginServiceDiscovery(BluetoothAddress address, Guid serviceGuid, SdpSearchScope searchScope,
AsyncCallback asyncCallback, Object state)
{
// Just in case the user modifies the original address!!!
BluetoothAddress addr2 = (BluetoothAddress)address.Clone();
AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams> ar
= new AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams>(asyncCallback, state,
new ServiceDiscoveryParams(addr2, serviceGuid, searchScope));
lock (lockServiceDiscovery) {
if (m_arServiceDiscovery != null)
throw new NotSupportedException("Currently support only one concurrent Service Lookup operation.");
bool success = false;
try {
m_arServiceDiscovery = ar;
bool ret = m_btIf.StartDiscovery(addr2, serviceGuid);
if (!ret) {
WBtRc ee = GetExtendedError();
throw WidcommSocketExceptions.Create_StartDiscovery(ee);
}
success = true;
} finally {
if (!success)
m_arServiceDiscovery = null;
}
}
return ar;
}
public ISdpDiscoveryRecordsBuffer EndServiceDiscovery(IAsyncResult asyncResult)
{
AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams> checkTypeMatches = m_arServiceDiscovery;
AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams> ar2
= (AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams>)asyncResult;
return ar2.EndInvoke();
}
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "will rethrow")]
internal void HandleDiscoveryComplete()
{
EntryIsWidcommThread();
WidcommUtils.Trace_WriteLine("HandleDiscoveryComplete");
AsyncResult<ISdpDiscoveryRecordsBuffer, ServiceDiscoveryParams> sacAr = null;
ISdpDiscoveryRecordsBuffer recBuf = null;
Exception sacEx = null;
try {
lock (lockServiceDiscovery) {
Debug.Assert(m_arServiceDiscovery != null, "NOT m_arServiceDiscovery != null");
if (m_arServiceDiscovery == null) { return; } // Nothing we can do then!
sacAr = m_arServiceDiscovery;
m_arServiceDiscovery = null;
BluetoothAddress addr;
ushort numRecords0;
DISCOVERY_RESULT result = m_btIf.GetLastDiscoveryResult(out addr, out numRecords0);
if (result != DISCOVERY_RESULT.SUCCESS) {
sacEx = WidcommSocketExceptions.Create(result, "ServiceRecordsGetResult");
return;
}
if (!addr.Equals(sacAr.BeginParameters.address)) {
sacEx = new InvalidOperationException("Internal error -- different DiscoveryComplete address.");
return;
}
// Get the records
recBuf = m_btIf.ReadDiscoveryRecords(addr, MaxNumberSdpRecords,
sacAr.BeginParameters);
}//lock
} catch (Exception ex) {
sacEx = ex;
} finally {
Debug.Assert(sacAr != null, "out: NOT sacAr != null");
Debug.Assert(m_arServiceDiscovery == null, "out: NOT m_arServiceDiscovery == null");
WaitCallback dlgt = delegate {
RaiseDiscoveryComplete(sacAr, recBuf, sacEx);
};
ThreadPool.QueueUserWorkItem(dlgt);
ExitIsWidcommThread();
}
}
static void RaiseDiscoveryComplete(
AsyncResult<ISdpDiscoveryRecordsBuffer,ServiceDiscoveryParams> sacAr,
ISdpDiscoveryRecordsBuffer recBuf, Exception sacEx)
{
if (sacAr != null) { // will always be true!
if (sacEx != null) {
sacAr.SetAsCompleted(sacEx, false);
} else {
sacAr.SetAsCompleted(recBuf, false);
}
}
}
//----------
public List_IBluetoothDeviceInfo GetKnownRemoteDeviceEntries()
{
List<REM_DEV_INFO> list = new List<REM_DEV_INFO>();
REM_DEV_INFO info = new REM_DEV_INFO();
int cb = System.Runtime.InteropServices.Marshal.SizeOf(typeof(REM_DEV_INFO));
IntPtr pBuf = System.Runtime.InteropServices.Marshal.AllocHGlobal(cb);
try {
REM_DEV_INFO_RETURN_CODE ret = m_btIf.GetRemoteDeviceInfo(ref info, pBuf, cb);
WidcommUtils.Trace_WriteLine("GRDI: ret: {0}=0x{0:X}", ret);
while (ret == REM_DEV_INFO_RETURN_CODE.SUCCESS) {
list.Add(info); // COPY it into the list
ret = m_btIf.GetNextRemoteDeviceInfo(ref info, pBuf, cb);
WidcommUtils.Trace_WriteLine("GnRDI: ret: {0}=0x{0:X}", ret);
}//while
if (ret != REM_DEV_INFO_RETURN_CODE.EOF)
throw WidcommSocketExceptions.Create(ret, "Get[Next]RemoteDeviceInfo");
//
List_IBluetoothDeviceInfo bdiList = new List_IBluetoothDeviceInfo(list.Count);
foreach (REM_DEV_INFO cur in list) {
IBluetoothDeviceInfo bdi = WidcommBluetoothDeviceInfo.CreateFromStoredRemoteDeviceInfo(cur, m_factory);
bdiList.Add(bdi);
}
return bdiList;
} finally {
System.Runtime.InteropServices.Marshal.FreeHGlobal(pBuf);
}
}
//----------
const string DevicesRegPath = @"Software\WIDCOMM\BTConfig\Devices\"; // "HKEY_LOCAL_MACHINE\..."
public List_IBluetoothDeviceInfo ReadKnownDevicesFromRegistry()
{
// Multiple keys, one per device, named with address e.g. 00:11:22:33:44:55
// Each with values: BRCMStack DWORD, Code DWORD, DevClass DWORD, etc etc
//
List_IBluetoothDeviceInfo devices = new List_IBluetoothDeviceInfo();
using (RegistryKey rkDevices = Registry.LocalMachine.OpenSubKey(DevicesRegPath)) {
if (rkDevices == null) {
// The Registry key is created when the first device is stored,
// so on a new device it doesn't exist. So return an empty list.
return devices;
// IOException is what GetValueKind throws.
//throw new System.IO.IOException("Widcomm 'Devices' key not found in the Registry.");
}
foreach (string itemName in rkDevices.GetSubKeyNames()) {
using (RegistryKey rkItem = rkDevices.OpenSubKey(itemName)) {
WidcommBluetoothDeviceInfo bdi = ReadDeviceFromRegistryAndCheckAndSetIfPaired_(
itemName, rkItem, m_factory);
devices.Add(bdi);
}
}//for
}
return devices;
}
private WidcommBluetoothDeviceInfo ReadDeviceFromRegistryAndCheckAndSetIfPaired_(
string itemName, RegistryKey rkItem, WidcommBluetoothFactoryBase factory)
{
BluetoothAddress address = BluetoothAddress.Parse(itemName);
byte[] devName = Registry_ReadBinaryValue(rkItem, "Name");
byte[] devClass = Registry_ReadBinaryValue(rkItem, "DevClass");
Int32? trusted = Registry_ReadDwordValue_Optional(rkItem, "TrustedMask");
WidcommBluetoothDeviceInfo bdi = CreateFromStoredRemoteDeviceInfo(address, devName, devClass, factory);
WidcommBluetoothDeviceInfo.CheckAndSetIfPaired(bdi, factory);
return bdi;
}
internal WidcommBluetoothDeviceInfo ReadDeviceFromRegistryAndCheckAndSetIfPaired(BluetoothAddress address,
WidcommBluetoothFactoryBase factory)
{
using (RegistryKey rkDevices = Registry.LocalMachine.OpenSubKey(DevicesRegPath)) {
if (rkDevices == null) {
// The Registry key is created when the first device is stored,
// so on a new device it doesn't exist. So return an empty list.
return null;
}
string itemName = address.ToString("C");
using (RegistryKey rkItem = rkDevices.OpenSubKey(itemName)) {
if (rkItem == null) {
return null;
}
WidcommBluetoothDeviceInfo bdi = ReadDeviceFromRegistryAndCheckAndSetIfPaired_(itemName, rkItem, factory);
return bdi;
}
}
}
private static WidcommBluetoothDeviceInfo CreateFromStoredRemoteDeviceInfo(
BluetoothAddress devAddress, byte[] devName, byte[] devClass,
WidcommBluetoothFactoryBase factory)
{
REM_DEV_INFO rdi = new REM_DEV_INFO();
rdi.bda = WidcommUtils.FromBluetoothAddress(devAddress);
rdi.bd_name = devName;
rdi.dev_class = devClass;
// rdi.b_connected = ...
// rdi.b_paired = ...
WidcommBluetoothDeviceInfo bdi = WidcommBluetoothDeviceInfo.CreateFromStoredRemoteDeviceInfo(rdi, factory);
string nameStr = bdi.DeviceName;
Debug.Assert(nameStr.Length == 0 || nameStr[nameStr.Length - 1] != 0, "null terminator!!");
int idxDbg;
Debug.Assert((idxDbg = nameStr.IndexOf((char)0)) == -1, "null terminator!! at: " + idxDbg);
return bdi;
}
private static byte[] Registry_ReadBinaryValue(RegistryKey rkItem, string name)
{
Registry_CheckIsKind(rkItem, name, RegistryValueKind.Binary);
byte[] raw = (byte[])rkItem.GetValue(name);
return raw;
}
private static Int32? Registry_ReadDwordValue_Optional(RegistryKey rkItem, string name)
{
object val = rkItem.GetValue(name);
if (val == null)
return null;
Registry_CheckIsKind(rkItem, name, RegistryValueKind.DWord);
return (Int32)val;
}
private static void Registry_CheckIsKind(RegistryKey rkItem, string name, RegistryValueKind expectedKind)
{
if (PlatformVerification.IsMonoRuntime) {
WidcommUtils.Trace_WriteLine("Skipping Registry_CheckIsKind check on Mono as it's not supported.");
return;
}
RegistryValueKind kind = rkItem.GetValueKind(name);
if (kind != expectedKind) {
string msg = string.Format(System.Globalization.CultureInfo.InvariantCulture,
"Expected '{0}':'{1}', to be '{2}' but was '{3}'.",
rkItem.Name, name, expectedKind, kind);
throw new FormatException(msg);
}
}
//----------
internal bool GetLocalDeviceVersionInfo(ref DEV_VER_INFO m_dvi)
{
return m_btIf.GetLocalDeviceVersionInfo(ref m_dvi);
}
internal bool GetLocalDeviceInfoBdAddr(byte[] bdAddr)
{
return m_btIf.GetLocalDeviceInfoBdAddr(bdAddr);
}
internal bool GetLocalDeviceName(byte[] bdName)
{
return m_btIf.GetLocalDeviceName(bdName);
}
internal void IsStackUpAndRadioReady(out bool stackServerUp, out bool deviceReady)
{
m_btIf.IsStackUpAndRadioReady(out stackServerUp, out deviceReady);
}
internal void IsDeviceConnectableDiscoverable(out bool conno, out bool disco)
{
m_btIf.IsDeviceConnectableDiscoverable(out conno, out disco);
}
internal void SetDeviceConnectableDiscoverable(bool connectable, bool forPairedOnly, bool discoverable)
{
m_btIf.SetDeviceConnectableDiscoverable(connectable, forPairedOnly, discoverable);
}
internal int GetRssi(byte[] bd_addr)
{
return m_btIf.GetRssi(bd_addr);
}
internal bool BondQuery(byte[] bd_addr)
{
return m_btIf.BondQuery(bd_addr);
}
internal BOND_RETURN_CODE Bond(BluetoothAddress address, string passphrase)
{
return m_btIf.Bond(address, passphrase);
}
internal bool UnBond(BluetoothAddress address)
{
return m_btIf.UnBond(address);
}
//----------
/// <summary>
/// Call CBtIf::GetExtendedError.
/// </summary>
/// -
/// <remarks>
/// <para>Is not currently used anywhere...
/// </para>
/// <para>Not supported on Widcomm WCE WM/WinCE, we (natively) return -1.
/// </para>
/// </remarks>
/// -
/// <returns>A <see cref="T:InTheHand.Net.Bluetooth.Widcomm.WBtRc"/> value.</returns>
private WBtRc GetExtendedError()
{
return m_btIf.GetExtendedError();
}
/// <summary>
/// CBtIf::IsRemoteDevicePresent
/// </summary>
/// -
/// <remarks>
/// <note>"added BTW and SDK 5.0.1.1000"</note>
/// <note>"added BTW-CE and SDK 1.7.1.2700"</note>
/// </remarks>
internal SDK_RETURN_CODE IsRemoteDevicePresent(byte[] bd_addr)
{
return m_btIf.IsRemoteDevicePresent(bd_addr);
}
/// <summary>
/// CBtIf::IsRemoteDeviceConnected
/// </summary>
/// -
/// <remarks>
/// <note>"added BTW 5.0.1.300, SDK 5.0"</note>
/// <note>"added BTW-CE and SDK 1.7.1.2700"</note>
/// </remarks>
internal bool IsRemoteDeviceConnected(byte[] bd_addr)
{
return m_btIf.IsRemoteDeviceConnected(bd_addr);
}
//----------
/// <summary>
/// Mark that we're running on a thread provided from within the Widcomm API.
/// </summary>
/// -
/// <remarks>
/// <para>These annotations should be added at the concrete level of the
/// stack and not at the swappable interface level, i.e. not at WidcommRfcommPort
/// but at WidcommRfcommStream. That's a bit further from the native callback
/// method but it means that we can test this area in unit-tests where we
/// use mock IRfcommPort etc.
/// </para>
/// </remarks>
internal static void EntryIsWidcommThread()
{
#if WIDCOMM_SINGLE_THREADING
//if (IsWidcommThread) { // DEBUG
//} else { // DEBUG
//}
#if !NETCF
checked { ++_InWidcommCallbackThreadCount; }
#else
int v = GetStaticData<int>(_slotInWidcommCallbackThreadCount);
checked { ++v; }
Thread.SetData(_slotInWidcommCallbackThreadCount, v);
#endif
#endif
}
internal static void ExitIsWidcommThread()
{
#if !NETCF
checked { --_InWidcommCallbackThreadCount; }
if (_InWidcommCallbackThreadCount < 0) {
Debug.Fail("_InWidcommThreadCount exit became -ve: " + _InWidcommCallbackThreadCount);
_InWidcommCallbackThreadCount = 0;
}
#else
int v = GetStaticData<int>(_slotInWidcommCallbackThreadCount);
checked { --v; }
if (v < 0) {
Debug.Fail("_InWidcommThreadCount exit became -ve: " + v);
v = 0;
}
Thread.SetData(_slotInWidcommCallbackThreadCount, v);
#endif
}
internal static bool IsWidcommCallbackThread
{
get
{
#if !WIDCOMM_SINGLE_THREADING
return false;
#else
#if !NETCF
int c = _InWidcommCallbackThreadCount;
#endif
#if NETCF
int c = GetStaticData<int>(_slotInWidcommCallbackThreadCount);
#endif
bool flag = (c > 0);
Debug.Assert(c >= 0, "NEG _InWidcommThreadCount!! is: " + c);
if (flag) {
//WidcommUtils.Trace_WriteLine("(IsWidcommThread)");
} else {
//WidcommUtils.Trace_WriteLine("(NOT IsWidcommThread)");
}
return flag;
#endif
}
}
internal static void ReportIfWidcommThread(string name)
{
#if WIDCOMM_SINGLE_THREADING
if (!IsWidcommSingleThread) {
WidcommUtils.Trace_WriteLine("NOT {0} on our Widcomm SINGLE thread!", name);
}
if (IsWidcommCallbackThread) {
Debug.Assert(!IsWidcommSingleThread, "Does Widcomm use the main thread for callbacks!!??");
WidcommUtils.Trace_WriteLine("{0} on Widcomm callback thread!", name);
}
if (IsWidcommSingleThread && IsWidcommCallbackThread) { // COVERAGE
}
#endif
}
#if WIDCOMM_SINGLE_THREADING
public static bool IsWidcommSingleThread
{
get
{
#if !NETCF
return _IsWidcommSingleThread;
#else
bool v = GetStaticData<bool>(_slotIsWidcommSingleThread);
return v;
#endif
}
set
{
#if !NETCF
_IsWidcommSingleThread = value;
#else
Thread.SetData(_slotIsWidcommSingleThread, value);
#endif
}
}
static T GetStaticData<T>(LocalDataStoreSlot slot) where T : struct
{
object o = Thread.GetData(slot);
T v = o == null ? default(T) : (T)o;
return v;
}
#endif
}//class
internal enum SdpSearchScope
{
Anywhere,
ServiceClassOnly
}
sealed class ServiceDiscoveryParams
{
readonly internal BluetoothAddress address;
readonly internal Guid serviceGuid;
readonly internal SdpSearchScope searchScope;
internal ServiceDiscoveryParams(BluetoothAddress address, Guid serviceGuid, SdpSearchScope searchScope)
{
this.address = address;
this.serviceGuid = serviceGuid;
if (searchScope != SdpSearchScope.Anywhere
&& searchScope != SdpSearchScope.ServiceClassOnly)
throw new ArgumentException("Unrecognized value for SdpSearchScope enum.", "searchScope");
this.searchScope = searchScope;
}
}
}
|