UWP SerialDevice DataReader 异常:0x800710DD。操作标识符无效
UWP SerialDevice DataReader Exception: 0x800710DD. The operation identifier is not valid
我正在将示例 Windows 表单应用程序的功能移植到 Xamarin.Forms UWP 应用程序,它应该在 COM 端口上写入和读取蓝牙设备。我大部分时间都运行良好,但 UWP 应用程序会间歇性地进入任何对 dataReader.LoadAsync 的调用都会触发异常的状态:
Exception thrown at 0x74AF1A62 (KernelBase.dll) in MyApp.UWP.exe: WinRT originate error - 0x800710DD : 'The operation identifier is not valid.'.
Exception thrown: 'System.Runtime.InteropServices.COMException' in MyApp.UWP.exe
WinRT information: The operation identifier is not valid.
重新启动应用程序或Visual Studio没有帮助,问题仍然存在。
上次发生时似乎没有影响我的 dataWriter 写入设备,仅影响后续读取。
所有代码都在 UWP 项目中。
private DataReader _dataReader;
private DataWriter _dataWriter;
private SerialDevice _currentSerialDevice;
private async Task ReadAsync(SerialDevice serialDevice)
{
const uint ReadBufferLength = 1024;
if (_dataReader == null)
{
_dataReader = new DataReader(_currentSerialDevice.InputStream) { InputStreamOptions = InputStreamOptions.Partial };
}
uint bytesRead = await _dataReader.LoadAsync(ReadBufferLength); // <- exception here
if (bytesRead > 0)
{
var vals = new byte[bytesRead];
_dataReader.ReadBytes(vals);
DoStuffWithBytes(vals);
}
}
串行设备是从应用程序的列表中选择的。
// Get serial devices
DeviceInformationCollection serialDeviceCollection = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector());
// Load serial device from user choosing a device from serialDeviceCollection
public async void ConnectToSerialDevice(DeviceInformation device)
{
_currentSerialDevice = await SerialDevice.FromIdAsync(device.Id);
_currentSerialDevice.BaudRate = 115200;
_currentSerialDevice.Parity = SerialParity.None;
_currentSerialDevice.DataBits = 8;
_currentSerialDevice.StopBits = SerialStopBitCount.One;
_currentSerialDevice.Handshake = SerialHandshake.RequestToSend;
}
写入设备的代码,即使它处于奇数状态也能正常工作:
private async Task WriteToDevice(byte[] outBuffer)
{
if (_currentSerialDevice != null)
{
if (_dataWriter == null)
{
_dataWriter = new DataWriter(_currentSerialDevice.OutputStream);
}
_dataWriter.WriteBytes(outBuffer);
await _dataWriter.StoreAsync();
}
}
我尝试过刷新数据写入器,每次都重新创建数据写入器和数据读取器,但我仍然遇到同样的错误,无法从设备读取任何内容。在正常操作中,我能够成功读取我期望的字节(即使没有要读取的字节,它 "reads" 0 字节)并且可以毫无例外地输出这个结果。
关于这一切的奇怪之处在于,不仅原始 Windows Forms 应用程序即使在进入此状态后也能正常工作(使用相同的蓝牙设备),而且只需打开端口并从该设备(在旧应用程序中)实际上修复了 UWP 应用程序中的问题一段时间,允许我再次从设备读取。
这可能与异步方法有关。你可以试试这个:
var task = await _dataReader.LoadAsync(ReadBufferLength);
task.AsTask().Wait();
uint bytesRead = task.GetResults();
对于异步方法(如DataReader.LoadAsync
),事件发生在UI线程上,只能触发一次,并且只有在上一个异步方法完成后才能继续触发。你的问题可能与此有关。
最后发现问题的原因是 LoadAsync 方法在等待填充整个缓冲区(1024 字节)时挂起,尽管 InputStreamOptions 被设置为 Partial。我得到的异常有点不相关,并且与异步方法无法正常工作有关(当第一个任务未完成时再次调用该方法)。
修复是将 ReadTimeout 添加到 SerialDevice 的组合:
_currentSerialDevice.ReadTimeout = TimeSpan.FromMilliseconds(500);
并将 LoadAsync 任务本身包装在一个定时取消令牌中:
using (var cts = new CancellationTokenSource(500))
{
var task = _dataReader.LoadAsync(ReadBufferLength);
var readTask = task.AsTask(cts.Token);
uint bytesRead = await readTask;
}
这允许 LoadAsync 方法在设备消耗的字节少于 1024 字节(由 SerialDevice.ReadTimeout 处理)和设备消耗的字节为 0 字节(由 CancellationToken 处理)时完成。
我仍然不确定为什么 运行 win 表单应用程序暂时解决了这个问题,可能是设置了 ReadTimeout(而我的 UWP 应用程序没有设置)并且这在串行端口上持续存在在某种程度上。
我正在将示例 Windows 表单应用程序的功能移植到 Xamarin.Forms UWP 应用程序,它应该在 COM 端口上写入和读取蓝牙设备。我大部分时间都运行良好,但 UWP 应用程序会间歇性地进入任何对 dataReader.LoadAsync 的调用都会触发异常的状态:
Exception thrown at 0x74AF1A62 (KernelBase.dll) in MyApp.UWP.exe: WinRT originate error - 0x800710DD : 'The operation identifier is not valid.'.
Exception thrown: 'System.Runtime.InteropServices.COMException' in MyApp.UWP.exe
WinRT information: The operation identifier is not valid.
重新启动应用程序或Visual Studio没有帮助,问题仍然存在。
上次发生时似乎没有影响我的 dataWriter 写入设备,仅影响后续读取。
所有代码都在 UWP 项目中。
private DataReader _dataReader;
private DataWriter _dataWriter;
private SerialDevice _currentSerialDevice;
private async Task ReadAsync(SerialDevice serialDevice)
{
const uint ReadBufferLength = 1024;
if (_dataReader == null)
{
_dataReader = new DataReader(_currentSerialDevice.InputStream) { InputStreamOptions = InputStreamOptions.Partial };
}
uint bytesRead = await _dataReader.LoadAsync(ReadBufferLength); // <- exception here
if (bytesRead > 0)
{
var vals = new byte[bytesRead];
_dataReader.ReadBytes(vals);
DoStuffWithBytes(vals);
}
}
串行设备是从应用程序的列表中选择的。
// Get serial devices
DeviceInformationCollection serialDeviceCollection = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector());
// Load serial device from user choosing a device from serialDeviceCollection
public async void ConnectToSerialDevice(DeviceInformation device)
{
_currentSerialDevice = await SerialDevice.FromIdAsync(device.Id);
_currentSerialDevice.BaudRate = 115200;
_currentSerialDevice.Parity = SerialParity.None;
_currentSerialDevice.DataBits = 8;
_currentSerialDevice.StopBits = SerialStopBitCount.One;
_currentSerialDevice.Handshake = SerialHandshake.RequestToSend;
}
写入设备的代码,即使它处于奇数状态也能正常工作:
private async Task WriteToDevice(byte[] outBuffer)
{
if (_currentSerialDevice != null)
{
if (_dataWriter == null)
{
_dataWriter = new DataWriter(_currentSerialDevice.OutputStream);
}
_dataWriter.WriteBytes(outBuffer);
await _dataWriter.StoreAsync();
}
}
我尝试过刷新数据写入器,每次都重新创建数据写入器和数据读取器,但我仍然遇到同样的错误,无法从设备读取任何内容。在正常操作中,我能够成功读取我期望的字节(即使没有要读取的字节,它 "reads" 0 字节)并且可以毫无例外地输出这个结果。
关于这一切的奇怪之处在于,不仅原始 Windows Forms 应用程序即使在进入此状态后也能正常工作(使用相同的蓝牙设备),而且只需打开端口并从该设备(在旧应用程序中)实际上修复了 UWP 应用程序中的问题一段时间,允许我再次从设备读取。
这可能与异步方法有关。你可以试试这个:
var task = await _dataReader.LoadAsync(ReadBufferLength);
task.AsTask().Wait();
uint bytesRead = task.GetResults();
对于异步方法(如DataReader.LoadAsync
),事件发生在UI线程上,只能触发一次,并且只有在上一个异步方法完成后才能继续触发。你的问题可能与此有关。
最后发现问题的原因是 LoadAsync 方法在等待填充整个缓冲区(1024 字节)时挂起,尽管 InputStreamOptions 被设置为 Partial。我得到的异常有点不相关,并且与异步方法无法正常工作有关(当第一个任务未完成时再次调用该方法)。
修复是将 ReadTimeout 添加到 SerialDevice 的组合:
_currentSerialDevice.ReadTimeout = TimeSpan.FromMilliseconds(500);
并将 LoadAsync 任务本身包装在一个定时取消令牌中:
using (var cts = new CancellationTokenSource(500))
{
var task = _dataReader.LoadAsync(ReadBufferLength);
var readTask = task.AsTask(cts.Token);
uint bytesRead = await readTask;
}
这允许 LoadAsync 方法在设备消耗的字节少于 1024 字节(由 SerialDevice.ReadTimeout 处理)和设备消耗的字节为 0 字节(由 CancellationToken 处理)时完成。
我仍然不确定为什么 运行 win 表单应用程序暂时解决了这个问题,可能是设置了 ReadTimeout(而我的 UWP 应用程序没有设置)并且这在串行端口上持续存在在某种程度上。