我正在嘗試編寫一個使用WinRT Bluetooth LE API(Windows.Devices.Bluetooth命名空間)的C#應用程序。該應用程序是Windows經典桌面應用程序(WPF,而不是 UWP)。在創作者更新之前運行Windows 10版本時,這些API按預期運行。但是,運行創作者更新時,應將數據發送到藍牙設備的API不起作用。具體來說,有以下方法返回成功狀態碼,但不要通過藍牙無線電的任何數據(比如使用藍牙流量嗅探器驗證):如何從Windows 10創建者更新上運行的WPF應用程序註冊BLE通知?
- GattCharacteristic.WriteClientCharacteristicConfigurationDescriptorWithResultAsync
- GattCharacteristic.WriteValueAsync
因此,任何爲特性註冊ValueChanged處理程序的嘗試都不起作用。由於註冊不會發送到Bluetooth LE設備,因此應用程序不會收到通知。
我知道並非所有的UWP API都可以從非UWP應用程序中使用,但我希望有人已經成功開發了這種配置中的BLE應用程序(或者至少現在可以確認它是不可能的)。我能夠在創作者更新之前連接並從BLE設備讀取數據並將數據寫入BLE設備,並且僅在此最新版本的Windows 10中才會出現上述問題。 (注意:示例代碼中使用的Async API已添加到創作者更新中,之前版本的應用程序使用舊版BLE API,但在運行創作者更新時它們也不起作用。)
具體來說,我的問題是:給出了以下項目參考列表和示例代碼,是否有任何我可以嘗試在運行非UWP應用程序的創作者更新的Windows 10上使用Bluetooth LE連接?請注意,「將應用程序轉換爲UWP應用程序」的顯而易見的答案對我們來說不起作用,因爲我們以UWP沙箱內無法實現的方式與其他硬件和文件進行交互。
該項目具有以下引用配置:
- System.Runtime.WindowsRuntime,在發現:C:\ Program Files文件(x86)的\參考大會\微軟\ Framework.NETCore \ V4.5 \ System.Runtime.WindowsRuntime.dll
- Windows中,發現:C:\ Program Files文件(x86)的\的Windows套件\ 10 \ UnionMetadata \外觀\ Windows.WinMD
- Windows.Foundation.FoundationContract,在發現:C: \ Program Files(x86)\ Windows Kits \ 10 \ References \ 10.0.15063.0 \ Windows.Foundation.FoundationContract \ 3.0.0.0 \ Windows.Foundation.FoundationContract.winmd
- Windows.Foundation.UniversalApiContract,找到在:C:\ Program Files文件(x86)\ Windows Kits \ 10 \ References \ 10.0.15063.0 \ Windows.Foundation.UniversalApiContract \ 4.0.0.0 \ Windows.Foundation.UniversalApiContract.winmd
以下是我的應用程序中非常簡潔的藍牙代碼版本。需要注意的是很多的錯誤處理和這種已爲清楚起見刪除,但它應該給的什麼,我試圖做一個總體思路:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Storage.Streams;
using System.Threading;
namespace BLEMinimumApp
{
class Program
{
private List<string> foundDevices = new List<string>(5);
static void Main(string[] args)
{
new Program().Execute();
}
private void Execute()
{
Console.WriteLine("Starting device watcher...");
string[] requestedProperties = { "System.Devices.Aep.IsConnected" };
String query = "";
//query for Bluetooth LE devices
query += "(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")";
//query for devices with controllers' name
query += " AND (System.ItemNameDisplay:=\"GPLeft\" OR System.ItemNameDisplay:=\"GPRight\")";
var deviceWatcher = DeviceInformation.CreateWatcher(query, requestedProperties, DeviceInformationKind.AssociationEndpoint);
deviceWatcher.Added += DeviceWatcher_OnAdded;
deviceWatcher.Start();
Console.ReadLine();
}
private async void DeviceWatcher_OnAdded(DeviceWatcher sender, DeviceInformation deviceInfo)
{
lock (foundDevices)
{
if (foundDevices.Contains(deviceInfo.Name))
{
return;
}
foundDevices.Add(deviceInfo.Name);
}
Console.WriteLine($"[{deviceInfo.Name}] DeviceWatcher_OnAdded...");
await ConnectTo(deviceInfo);
}
private async Task ConnectTo(DeviceInformation deviceInfo)
{
try
{
// get the device
BluetoothLEDevice device = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
Console.WriteLine($"[{device.Name}] Device found: connectionStatus={device?.ConnectionStatus}");
// get the GATT service
Thread.Sleep(150);
Console.WriteLine($"[{device.Name}] Get GATT Services");
var gattServicesResult = await device.GetGattServicesForUuidAsync(new Guid("<GUID REMOVED FOR SO POST"));
Console.WriteLine($"[{device.Name}] GATT services result: status={gattServicesResult?.Status}, count={gattServicesResult?.Services?.Count}, cx={device.ConnectionStatus}");
if (gattServicesResult == null
|| gattServicesResult.Status != GattCommunicationStatus.Success
|| gattServicesResult.Services == null
|| gattServicesResult.Services?.Count < 1)
{
Console.WriteLine($"[{device.Name}] Failed to find GATT service.");
return;
}
var service = gattServicesResult.Services[0];
Console.WriteLine($"[{device?.Name}] GATT service found: gattDeviceService={service.Uuid}");
// get the GATT characteristic
Thread.Sleep(150);
Console.WriteLine($"[{device.Name}] Get GATT characteristics");
var gattCharacteristicsResult = await service.GetCharacteristicsForUuidAsync(new Guid("<GUID REMOVED FOR SO POST>"));
Console.WriteLine($"[{device.Name}] GATT Characteristics result: status={gattCharacteristicsResult?.Status}, count={gattCharacteristicsResult?.Characteristics?.Count}, cx={device.ConnectionStatus}");
if (gattCharacteristicsResult == null
|| gattCharacteristicsResult.Status != GattCommunicationStatus.Success
|| gattCharacteristicsResult.Characteristics == null
|| gattCharacteristicsResult.Characteristics?.Count < 1)
{
Console.WriteLine($"[{device.Name}] Failed to find GATT characteristic.");
return;
}
var characteristic = gattCharacteristicsResult.Characteristics[0];
// register for notifications
Thread.Sleep(150);
characteristic.ValueChanged += (sender, args) =>
{
Console.WriteLine($"[{device.Name}] Received notification containing {args.CharacteristicValue.Length} bytes");
};
Console.WriteLine($"[{device.Name}] Writing CCCD...");
GattWriteResult result =
await characteristic.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
Console.WriteLine($"[{device?.Name}] Characteristics write result: status={result.Status}, protocolError={result.ProtocolError}");
// send configuration to device
await SendConfiguration(device, characteristic);
}
catch (Exception ex) when((uint) ex.HResult == 0x800710df)
{
Console.WriteLine("bluetooth error 1");
// ERROR_DEVICE_NOT_AVAILABLE because the Bluetooth radio is not on.
}
}
private async Task SendConfiguration(BluetoothLEDevice device, GattCharacteristic characteristic)
{
if (characteristic != null)
{
var writer = new DataWriter();
// CONFIGURATION REMOVED, but this code writes device-specific bytes to the DataWriter
await SendMessage(device, characteristic, writer.DetachBuffer());
}
}
private async Task SendMessage(BluetoothLEDevice device, GattCharacteristic characteristic, IBuffer message)
{
if (characteristic != null && device.ConnectionStatus.Equals(BluetoothConnectionStatus.Connected) && message != null)
{
Console.WriteLine($"[{device.Name}] Sending message...");
GattCommunicationStatus result = await characteristic.WriteValueAsync(message);
Console.WriteLine($"[{device.Name}] Result: {result}");
}
}
}
}
感謝您的答覆。我指定了該線程中描述的AppID,這似乎解決了該問題。還沒有完成詳盡的測試,看看通知是否停止,如你所描述的。希望不是。 :) –