diff --git a/InTheHand.Net.Bluetooth/Platforms/Win32/BluetoothDeviceInfo.win32.cs b/InTheHand.Net.Bluetooth/Platforms/Win32/BluetoothDeviceInfo.win32.cs index d6c6a3f..5aa76cd 100644 --- a/InTheHand.Net.Bluetooth/Platforms/Win32/BluetoothDeviceInfo.win32.cs +++ b/InTheHand.Net.Bluetooth/Platforms/Win32/BluetoothDeviceInfo.win32.cs @@ -29,7 +29,7 @@ public BluetoothDeviceInfo(BluetoothAddress address) { _info = BLUETOOTH_DEVICE_INFO.Create(); _info.Address = address; - NativeMethods.BluetoothGetDeviceInfo(IntPtr.Zero, ref _info); + DoRefresh(); } BluetoothAddress GetDeviceAddress() diff --git a/InTheHand.Net.Bluetooth/Platforms/Win32/NativeMethods.cs b/InTheHand.Net.Bluetooth/Platforms/Win32/NativeMethods.cs index cbe2b4a..d46e1e8 100644 --- a/InTheHand.Net.Bluetooth/Platforms/Win32/NativeMethods.cs +++ b/InTheHand.Net.Bluetooth/Platforms/Win32/NativeMethods.cs @@ -2,7 +2,7 @@ // // InTheHand.Net.Bluetooth.Win32.NativeMethods // -// Copyright (c) 2003-2020 In The Hand Ltd, All rights reserved. +// Copyright (c) 2003-2021 In The Hand Ltd, All rights reserved. // This source code is licensed under the MIT License using System; @@ -35,10 +35,8 @@ public static bool IsRunningOnMono() return _isRunningOnMono.Value; } - [DllImport("User32", ExactSpelling = true)] - internal static extern IntPtr GetActiveWindow(); - - // Requires Vista SP2 or later + + // Authentication [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)] internal static extern int BluetoothRegisterForAuthenticationEx(ref BLUETOOTH_DEVICE_INFO pbtdi, out IntPtr phRegHandle, BluetoothAuthenticationCallbackEx pfnCallback, IntPtr pvParam); @@ -49,7 +47,6 @@ public static bool IsRunningOnMono() [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool BluetoothUnregisterAuthentication(IntPtr hRegHandle); - [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode)] internal static extern int BluetoothSendAuthenticationResponseEx(IntPtr hRadio, ref BLUETOOTH_AUTHENTICATE_RESPONSE__PIN_INFO pauthResponse); @@ -68,6 +65,7 @@ public static bool IsRunningOnMono() [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true)] internal static extern int BluetoothRemoveDevice(ref ulong pAddress); + // Radio [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true)] internal static extern IntPtr BluetoothFindFirstRadio(ref BLUETOOTH_FIND_RADIO_PARAMS pbtfrp, out IntPtr phRadio); @@ -100,6 +98,7 @@ public static bool IsRunningOnMono() [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool BluetoothEnableIncomingConnections(IntPtr hRadio, bool fEnabled); + // Discovery [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true)] internal static extern IntPtr BluetoothFindFirstDevice(ref BLUETOOTH_DEVICE_SEARCH_PARAMS pbtsp, ref BLUETOOTH_DEVICE_INFO pbtdi); @@ -118,20 +117,23 @@ public static bool IsRunningOnMono() [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true)] internal static extern int BluetoothSetServiceState(IntPtr hRadio, ref BLUETOOTH_DEVICE_INFO pbtdi, ref Guid pGuidService, uint dwServiceFlags); - [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] + [DllImport("kernel32", ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle(IntPtr handle); - //SetService - [DllImport(wsDll, EntryPoint = "WSASetService", SetLastError = true)] + // SetService + [DllImport(wsDll, ExactSpelling = true, EntryPoint = "WSASetService", SetLastError = true)] internal static extern int WSASetService(ref WSAQUERYSET lpqsRegInfo, WSAESETSERVICEOP essoperation, int dwControlFlags); // Last Error - [DllImport(wsDll, EntryPoint = "WSAGetLastError", SetLastError = true)] + [DllImport(wsDll, ExactSpelling = true, EntryPoint = "WSAGetLastError", SetLastError = true)] internal static extern int WSAGetLastError(); // Picker + [DllImport("user32", ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr GetActiveWindow(); + [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool BluetoothSelectDevices(ref BLUETOOTH_SELECT_DEVICE_PARAMS pbtsdp); @@ -142,9 +144,18 @@ public static bool IsRunningOnMono() internal delegate bool PFN_DEVICE_CALLBACK(IntPtr pvParam, ref BLUETOOTH_DEVICE_INFO pDevice); + [DllImport(bthpropsDll, ExactSpelling = true, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool BluetoothDisplayDeviceProperties(IntPtr hwndParent, ref BLUETOOTH_DEVICE_INFO pbtdi); + + // Events + [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true, EntryPoint = "RegisterDeviceNotification")] + internal static extern RegisterDeviceNotificationSafeHandle RegisterDeviceNotification( + IntPtr hRecipient, + ref DEV_BROADCAST_HANDLE notificationFilter, + RegisterDeviceNotificationFlags flags + ); } /// @@ -185,4 +196,103 @@ internal struct BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS /// internal uint Numeric_Value_Passkey; } + + struct DEV_BROADCAST_HANDLE + { + // 32-bit: 3*4 + 2*4 + 16 + 4 + a = 6*4+16 = 24+16 + a = 40 + a = 44 + // 64-bit: (3+1)*4 + 2*8 + 16 + 4 + a = 16+16+16+4 + a = 52 + a = 56 + const int SizeWithoutFakeDataArray = 40; + const int SizeOfOneByteWithPadding = 4; + const int SizeWithFakeDataArray = SizeWithoutFakeDataArray + SizeOfOneByteWithPadding; + static int ActualSizeWithFakeDataArray; + + public DEV_BROADCAST_HDR header; + //-- + internal readonly IntPtr dbch_handle; + internal readonly IntPtr dbch_hdevnotify; + internal readonly Guid dbch_eventguid; + internal readonly Int32 dbch_nameoffset; + // We can't include the fake data array because we use this struct as + // the first field in other structs! + // byte dbch_data__0; //dbch_data[1]; + + //---- + public DEV_BROADCAST_HANDLE(IntPtr deviceHandle) + { + this.header.dbch_reserved = 0; + this.dbch_hdevnotify = IntPtr.Zero; + this.dbch_eventguid = Guid.Empty; + this.dbch_nameoffset = 0; + //-- + this.header.dbch_devicetype = DbtDevTyp.Handle; + this.dbch_handle = deviceHandle; + //System.Diagnostics.Debug.Assert( + // SizeWithoutFakeDataArray == System.Runtime.InteropServices.Marshal.SizeOf(typeof(DEV_BROADCAST_HANDLE)), + // "Size not as expected"); + if (ActualSizeWithFakeDataArray == 0) + { + int actualSizeWithoutFakeDataArray = System.Runtime.InteropServices.Marshal.SizeOf(typeof(DEV_BROADCAST_HANDLE)); + ActualSizeWithFakeDataArray = Pad(1 + actualSizeWithoutFakeDataArray, IntPtr.Size); + } + this.header.dbch_size = ActualSizeWithFakeDataArray; + //this.header.dbch_size = actualSizeWithoutFakeDataArray; + + } + + private static int Pad(int size, int alignment) + { + int x = size + alignment - 1; + x /= alignment; + x *= alignment; + return x; + } + + } + + [StructLayout(LayoutKind.Sequential)] + internal struct DEV_BROADCAST_HDR + { + internal int dbch_size; + internal DbtDevTyp dbch_devicetype; + internal int dbch_reserved; + } + + internal enum DbtDevTyp : uint + { + /// + /// OEM-defined device type + /// + Oem = 0x00000000, + /// + /// Devnode number + /// /// + DevNode = 0x00000001, + /// + /// + /// + Volume = 0x00000002, + /// + /// + /// + Port = 0x00000003, + /// + /// Network resource + /// + Network = 0x00000004, + /// + /// Device interface class + /// + DeviceInterface = 0x00000005, + /// + /// File system handle + /// + Handle = 0x00000006 + } + + internal enum RegisterDeviceNotificationFlags + { + WINDOW_HANDLE = 0x00000000, + SERVICE_HANDLE = 0x00000001, + ALL_INTERFACE_CLASSES = 0x00000004 + } } \ No newline at end of file diff --git a/InTheHand.Net.Bluetooth/Platforms/Win32/RegisterDeviceNotificationSafeHandle.cs b/InTheHand.Net.Bluetooth/Platforms/Win32/RegisterDeviceNotificationSafeHandle.cs new file mode 100644 index 0000000..685b70b --- /dev/null +++ b/InTheHand.Net.Bluetooth/Platforms/Win32/RegisterDeviceNotificationSafeHandle.cs @@ -0,0 +1,38 @@ +// 32feet.NET - Personal Area Networking for .NET +// +// InTheHand.Net.Bluetooth.Win32.RegisterDeviceNotificationSafeHandle +// +// Copyright (c) 2008-2021 In The Hand Ltd, All rights reserved. +// Copyright (c) 2008-2011 Alan J.McFarlane, All rights reserved. +// This source code is licensed under the MIT License + +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; + +namespace InTheHand.Net.Bluetooth.Win32 +{ + internal sealed class RegisterDeviceNotificationSafeHandle : SafeHandleZeroOrMinusOneIsInvalid + { + public RegisterDeviceNotificationSafeHandle() : base(true) // ownsHandle + { + } + + protected override bool ReleaseHandle() + { + return BluetoothUnregisterDeviceNotification(handle); + } + + private static bool BluetoothUnregisterDeviceNotification(IntPtr deviceNotificationHandle) + { + System.Diagnostics.Debug.Assert(deviceNotificationHandle != IntPtr.Zero, "Device notification not registered."); + bool success = UnregisterDeviceNotification(deviceNotificationHandle); + System.Diagnostics.Debug.Assert(success, "UnregisterDeviceNotification success false."); + return success; + } + + [DllImport("user32", ExactSpelling = true, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnregisterDeviceNotification(IntPtr handle); + } +}