如何在 C# 中使用 BluetoothGATTGetCharacteristic
how to use BluetoothGATTGetCharacteristic with C#
我编写了一个 C# 控制台应用程序,尝试获取我的耳机电池信息
class BluetoothAPI
class BluetoothAPIs
{
//https://docs.microsoft.com/zh-cn/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetservices
[DllImport("BluetoothAPIs.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int BluetoothGATTGetServices(
IntPtr hDevice,
UInt16 ServicesBufferCount,
IntPtr ServicesBuffer,
ref UInt16 ServicesBufferActual,
UInt32 Flags
);
//https://docs.microsoft.com/zh-cn/windows/win32/api/bthledef/ns-bthledef-bth_le_uuid
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_UUID
{
public Boolean isShortUuid;
public UInt16 ShortUuid;
public Guid LongUuid;
}
//https://docs.microsoft.com/zh-cn/windows/win32/api/bthledef/ns-bthledef-bth_le_gatt_service
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_SERVICE
{
public BTH_LE_UUID ServiceUuid;
public UInt16 AttributeHandle;
}
//https://docs.microsoft.com/en-us/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetcharacteristics
[DllImport("BluetoothAPIs.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int BluetoothGATTGetCharacteristics(
IntPtr hDevice,
ref BTH_LE_GATT_SERVICE Service,
UInt16 CharacteristicsBufferCount,
IntPtr CharacteristicsBuffer,
ref UInt16 CharacteristicsBufferActual,
UInt32 Flags
);
//https://docs.microsoft.com/en-us/windows/win32/api/bthledef/ns-bthledef-bth_le_gatt_characteristic
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_CHARACTERISTIC
{
public UInt16 ServiceHandle;
public BTH_LE_UUID CharacteristicUuid;
public UInt16 AttributeHandle;
public UInt16 CharacteristicValueHandle;
public Boolean IsBroadcastable;
public Boolean IsReadable;
public Boolean IsWritable;
public Boolean IsWritableWithoutResponse;
public Boolean IsSignedWritable;
public Boolean IsNotifiable;
public Boolean IsIndicatable;
public Boolean HasExtendedProperties;
}
//https://docs.microsoft.com/en-us/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetcharacteristicvalue
[DllImport("BluetoothAPIs.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int BluetoothGATTGetCharacteristicValue(
IntPtr hDevice,
ref BTH_LE_GATT_CHARACTERISTIC Characteristic,
UInt32 CharacteristicValueDataSize,
ref BTH_LE_GATT_CHARACTERISTIC_VALUE CharacteristicValue,
out UInt16 CharacteristicValueSizeRequired,
UInt32 Flags
);
//https://docs.microsoft.com/en-us/windows/win32/api/bthledef/ns-bthledef-bth_le_gatt_characteristic_value
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_CHARACTERISTIC_VALUE
{
public UInt32 DataSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] Data;
}
public static readonly UInt32 BLUETOOTH_GATT_FLAG_NONE = 0;
public static readonly UInt32 BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE = 0x00000004;
}
我试试这个:
IntPtr characteristicsBufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC)) * characteristicsBufferCount);
UInt16 characteristicsBufferActual = 0;
BluetoothAPIs.BluetoothGATTGetCharacteristics(hDevice, ref service, characteristicsBufferCount, characteristicsBufferPtr, ref characteristicsBufferActual, BluetoothAPIs.BLUETOOTH_GATT_FLAG_NONE);
for (int n = 0; n < characteristicsBufferActual; n++)
{
BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC characteristic = Marshal.PtrToStructure<BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC>(characteristicsBufferPtr + n * Marshal.SizeOf(typeof(BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC)));
BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC_VALUE characteristicValue = new BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC_VALUE();
UInt16 characteristicValueSizeRequired = 0;
BluetoothAPIs.BluetoothGATTGetCharacteristicValue(hDevice, ref characteristic, 256, ref characteristicValue, out characteristicValueSizeRequired, BluetoothAPIs.BLUETOOTH_GATT_FLAG_NONE);
if (characteristic.CharacteristicUuid.ShortUuid == 0x2A19) // battery level
{
Console.WriteLine("Battery Level: {0}", characteristicValue.Data[0]);
}
else if (characteristic.CharacteristicUuid.ShortUuid == 0x2A01) // appearance
{
int appearance = BitConverter.ToInt32(characteristicValue.Data);
string appearanceName = appearanceDict.GetValueOrDefault(appearance, "Unknown");
Console.WriteLine("Appearance: {1}, Data: {2}", appearance, appearanceName);
}
else //string
{
Console.WriteLine("UUID: {0}, DataSize: {1}, Data: {2}", characteristic.CharacteristicUuid.ShortUuid, characteristicValue.DataSize, Encoding.ASCII.GetString(characteristicValue.Data, 0, (int)characteristicValue.DataSize));
}
}
当n = 0时,我可以得到一个结构体'BTH_LE_GATT_CHARACTERISTIC'。
但是 n > 0,从 ptr 获取结构失败。
如何获取下一个''结构或获取结构数组
有完整代码:https://gist.github.com/cd2b1a504ee9155e8dcb2cc7c62257d7.git
Marshal.SizeOf(typeof(BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC))
的结果是60
。但是,在 C++ 中,sizeof(BTH_LE_GATT_CHARACTERISTIC)
是 36
.
问题是:
Boolean
在 C# 中是 4 个字节,而在 C++ 中 BOOLEAN
是一个字节。
所以在C#中,BTH_LE_UUID
和BTH_LE_GATT_CHARACTERISTIC
对应的定义会是这样:
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_UUID
{
public Byte isShortUuid;
public UInt16 ShortUuid;
public Guid LongUuid;
}
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_CHARACTERISTIC
{
public UInt16 ServiceHandle;
public BTH_LE_UUID CharacteristicUuid;
public UInt16 AttributeHandle;
public UInt16 CharacteristicValueHandle;
public Byte IsBroadcastable;
public Byte IsReadable;
public Byte IsWritable;
public Byte IsWritableWithoutResponse;
public Byte IsSignedWritable;
public Byte IsNotifiable;
public Byte IsIndicatable;
public Byte HasExtendedProperties;
}
我编写了一个 C# 控制台应用程序,尝试获取我的耳机电池信息
class BluetoothAPI
class BluetoothAPIs
{
//https://docs.microsoft.com/zh-cn/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetservices
[DllImport("BluetoothAPIs.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int BluetoothGATTGetServices(
IntPtr hDevice,
UInt16 ServicesBufferCount,
IntPtr ServicesBuffer,
ref UInt16 ServicesBufferActual,
UInt32 Flags
);
//https://docs.microsoft.com/zh-cn/windows/win32/api/bthledef/ns-bthledef-bth_le_uuid
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_UUID
{
public Boolean isShortUuid;
public UInt16 ShortUuid;
public Guid LongUuid;
}
//https://docs.microsoft.com/zh-cn/windows/win32/api/bthledef/ns-bthledef-bth_le_gatt_service
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_SERVICE
{
public BTH_LE_UUID ServiceUuid;
public UInt16 AttributeHandle;
}
//https://docs.microsoft.com/en-us/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetcharacteristics
[DllImport("BluetoothAPIs.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int BluetoothGATTGetCharacteristics(
IntPtr hDevice,
ref BTH_LE_GATT_SERVICE Service,
UInt16 CharacteristicsBufferCount,
IntPtr CharacteristicsBuffer,
ref UInt16 CharacteristicsBufferActual,
UInt32 Flags
);
//https://docs.microsoft.com/en-us/windows/win32/api/bthledef/ns-bthledef-bth_le_gatt_characteristic
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_CHARACTERISTIC
{
public UInt16 ServiceHandle;
public BTH_LE_UUID CharacteristicUuid;
public UInt16 AttributeHandle;
public UInt16 CharacteristicValueHandle;
public Boolean IsBroadcastable;
public Boolean IsReadable;
public Boolean IsWritable;
public Boolean IsWritableWithoutResponse;
public Boolean IsSignedWritable;
public Boolean IsNotifiable;
public Boolean IsIndicatable;
public Boolean HasExtendedProperties;
}
//https://docs.microsoft.com/en-us/windows/win32/api/bluetoothleapis/nf-bluetoothleapis-bluetoothgattgetcharacteristicvalue
[DllImport("BluetoothAPIs.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int BluetoothGATTGetCharacteristicValue(
IntPtr hDevice,
ref BTH_LE_GATT_CHARACTERISTIC Characteristic,
UInt32 CharacteristicValueDataSize,
ref BTH_LE_GATT_CHARACTERISTIC_VALUE CharacteristicValue,
out UInt16 CharacteristicValueSizeRequired,
UInt32 Flags
);
//https://docs.microsoft.com/en-us/windows/win32/api/bthledef/ns-bthledef-bth_le_gatt_characteristic_value
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_CHARACTERISTIC_VALUE
{
public UInt32 DataSize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[] Data;
}
public static readonly UInt32 BLUETOOTH_GATT_FLAG_NONE = 0;
public static readonly UInt32 BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE = 0x00000004;
}
我试试这个:
IntPtr characteristicsBufferPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC)) * characteristicsBufferCount);
UInt16 characteristicsBufferActual = 0;
BluetoothAPIs.BluetoothGATTGetCharacteristics(hDevice, ref service, characteristicsBufferCount, characteristicsBufferPtr, ref characteristicsBufferActual, BluetoothAPIs.BLUETOOTH_GATT_FLAG_NONE);
for (int n = 0; n < characteristicsBufferActual; n++)
{
BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC characteristic = Marshal.PtrToStructure<BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC>(characteristicsBufferPtr + n * Marshal.SizeOf(typeof(BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC)));
BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC_VALUE characteristicValue = new BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC_VALUE();
UInt16 characteristicValueSizeRequired = 0;
BluetoothAPIs.BluetoothGATTGetCharacteristicValue(hDevice, ref characteristic, 256, ref characteristicValue, out characteristicValueSizeRequired, BluetoothAPIs.BLUETOOTH_GATT_FLAG_NONE);
if (characteristic.CharacteristicUuid.ShortUuid == 0x2A19) // battery level
{
Console.WriteLine("Battery Level: {0}", characteristicValue.Data[0]);
}
else if (characteristic.CharacteristicUuid.ShortUuid == 0x2A01) // appearance
{
int appearance = BitConverter.ToInt32(characteristicValue.Data);
string appearanceName = appearanceDict.GetValueOrDefault(appearance, "Unknown");
Console.WriteLine("Appearance: {1}, Data: {2}", appearance, appearanceName);
}
else //string
{
Console.WriteLine("UUID: {0}, DataSize: {1}, Data: {2}", characteristic.CharacteristicUuid.ShortUuid, characteristicValue.DataSize, Encoding.ASCII.GetString(characteristicValue.Data, 0, (int)characteristicValue.DataSize));
}
}
当n = 0时,我可以得到一个结构体'BTH_LE_GATT_CHARACTERISTIC'。 但是 n > 0,从 ptr 获取结构失败。 如何获取下一个''结构或获取结构数组
有完整代码:https://gist.github.com/cd2b1a504ee9155e8dcb2cc7c62257d7.git
Marshal.SizeOf(typeof(BluetoothAPIs.BTH_LE_GATT_CHARACTERISTIC))
的结果是60
。但是,在 C++ 中,sizeof(BTH_LE_GATT_CHARACTERISTIC)
是 36
.
问题是:
Boolean
在 C# 中是 4 个字节,而在 C++ 中 BOOLEAN
是一个字节。
所以在C#中,BTH_LE_UUID
和BTH_LE_GATT_CHARACTERISTIC
对应的定义会是这样:
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_UUID
{
public Byte isShortUuid;
public UInt16 ShortUuid;
public Guid LongUuid;
}
[StructLayout(LayoutKind.Sequential)]
public struct BTH_LE_GATT_CHARACTERISTIC
{
public UInt16 ServiceHandle;
public BTH_LE_UUID CharacteristicUuid;
public UInt16 AttributeHandle;
public UInt16 CharacteristicValueHandle;
public Byte IsBroadcastable;
public Byte IsReadable;
public Byte IsWritable;
public Byte IsWritableWithoutResponse;
public Byte IsSignedWritable;
public Byte IsNotifiable;
public Byte IsIndicatable;
public Byte HasExtendedProperties;
}