using System; using System.Runtime.InteropServices; using System.Threading; namespace BluetoothLENet { class BetterScanner { /// /// The BLUETOOTH_FIND_RADIO_PARAMS structure facilitates enumerating installed Bluetooth radios. /// [StructLayout(LayoutKind.Sequential)] private struct BLUETOOTH_FIND_RADIO_PARAM { internal UInt32 dwSize; internal void Initialize() { this.dwSize = (UInt32)Marshal.SizeOf(typeof(BLUETOOTH_FIND_RADIO_PARAM)); } } /// /// Closes an open object handle. /// /// [In] A valid handle to an open object. /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. [DllImport("Kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr handle); /// /// Finds the first bluetooth radio present in device manager /// /// Pointer to a BLUETOOTH_FIND_RADIO_PARAMS structure /// Pointer to where the first enumerated radio handle will be returned. When no longer needed, this handle must be closed via CloseHandle. /// In addition to the handle indicated by phRadio, calling this function will also create a HBLUETOOTH_RADIO_FIND handle for use with the BluetoothFindNextRadio function. /// When this handle is no longer needed, it must be closed via the BluetoothFindRadioClose. /// Returns NULL upon failure. Call the GetLastError function for more information on the error. The following table describe common errors: [DllImport("irprops.cpl", SetLastError = true)] static extern IntPtr BluetoothFindFirstRadio(ref BLUETOOTH_FIND_RADIO_PARAM pbtfrp, out IntPtr phRadio); [StructLayout(LayoutKind.Sequential)] private struct LE_SCAN_REQUEST { internal int scanType; internal ushort scanInterval; internal ushort scanWindow; } [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)] static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, ref LE_SCAN_REQUEST lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped); /// /// Starts scanning for LE devices. /// Example: BetterScanner.StartScanner(0, 29, 29) /// /// 0 = Passive, 1 = Active /// Interval in 0.625 ms units /// Window in 0.625 ms units public static void StartScanner(int scanType, ushort scanInterval, ushort scanWindow) { var thread = new Thread(() => { BLUETOOTH_FIND_RADIO_PARAM param = new BLUETOOTH_FIND_RADIO_PARAM(); param.Initialize(); IntPtr handle; BluetoothFindFirstRadio(ref param, out handle); uint outsize; LE_SCAN_REQUEST req = new LE_SCAN_REQUEST { scanType = scanType, scanInterval = scanInterval, scanWindow = scanWindow }; DeviceIoControl(handle, 0x41118c, ref req, 8, IntPtr.Zero, 0, out outsize, IntPtr.Zero); }); thread.Start(); } } }