【发布时间】:2012-02-14 04:36:39
【问题描述】:
我有一个 C# windows 窗体应用程序,它通过 COM 端口与 USB 加密狗进行通信。我正在使用 .Net 2.0 中的 SerialPort 类进行通信,并且串行端口对象在应用程序的生命周期内都是开放的。应用程序向设备发送命令,也可以从设备接收未经请求的数据。
我的问题在表单关闭时出现 - 我在尝试关闭 COM 端口时(随机,不幸地)收到 ObjectDisposedException。这是 Windows 堆栈跟踪:
System.ObjectDisposedException was unhandled
Message=Safe handle has been closed
Source=System
ObjectName=""
StackTrace:
at Microsoft.Win32.UnsafeNativeMethods.SetCommMask(SafeFileHandle hFile, Int32 dwEvtMask)
at System.IO.Ports.SerialStream.Dispose(Boolean disposing)
at System.IO.Ports.SerialStream.Finalize()
InnerException:
我找到了有类似问题的人的帖子,并尝试了解决方法 [此处][1]
[1]: http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html 虽然这是针对 IOException 并没有解决问题。
我的 Close() 代码如下:
public void Close()
{
try
{
Console.WriteLine("******ComPort.Close - baseStream.Close*******");
baseStream.Close();
}
catch (Exception ex)
{
Console.WriteLine("******ComPort.Close baseStream.Close raised exception: " + ex + "*******");
}
try
{
_onDataReceived = null;
Console.WriteLine("******ComPort.Close - _serialPort.Close*******");
_serialPort.Close();
}
catch (Exception ex)
{
Console.WriteLine("******ComPort.Close - _serialPort.Close raised exception: " + ex + "*******");
}
}
我的日志显示执行永远不会超出尝试关闭 SerialPort 的 BaseStream(这是在第一个 try 块中),所以我尝试删除此行但仍然定期抛出异常 - 第二个 @ 中的日志记录987654325@ 块出现然后异常发生。两个 catch 块都没有捕获异常。
有什么想法吗?
更新 - 添加完整类:
namespace My.Utilities
{
public interface ISerialPortObserver
{
void SerialPortWriteException();
}
internal class ComPort : ISerialPort
{
private readonly ISerialPortObserver _observer;
readonly SerialPort _serialPort;
private DataReceivedDelegate _onDataReceived;
public event DataReceivedDelegate OnDataReceived
{
add { lock (_dataReceivedLocker) { _onDataReceived += value; } }
remove { lock (_dataReceivedLocker) { _onDataReceived -= value; } }
}
private readonly object _dataReceivedLocker = new object();
private readonly object _locker = new object();
internal ComPort()
{
_serialPort = new SerialPort { ReadTimeout = 10, WriteTimeout = 100, DtrEnable = true };
_serialPort.DataReceived += DataReceived;
}
internal ComPort(ISerialPortObserver observer) : this()
{
_observer = observer;
}
private void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
DataReceivedDelegate temp = null;
lock (_locker)
{
lock (_dataReceivedLocker)
{
temp = _onDataReceived;
}
string dataReceived = string.Empty;
var sp = (SerialPort) sender;
try
{
dataReceived = sp.ReadExisting();
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPort.DataReceived raised exception: " + ex);
}
if (null != temp && string.Empty != dataReceived)
{
try
{
temp(dataReceived, TickProvider.GetTickCount());
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPort.DataReceived raised exception calling handler: " + ex);
}
}
}
}
public string Port
{
set
{
try
{
_serialPort.PortName = value;
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPort.Port raised exception: " + ex);
}
}
}
private System.IO.Stream comPortStream = null;
public bool Open()
{
SetupSerialPortWithWorkaround();
try
{
_serialPort.Open();
comPortStream = _serialPort.BaseStream;
return true;
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Warning, "ComPort.Open raised exception: " + ex);
return false;
}
}
public bool IsOpen
{
get
{
SetupSerialPortWithWorkaround();
try
{
return _serialPort.IsOpen;
}
catch(Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPort.IsOpen raised exception: " + ex);
}
return false;
}
}
internal virtual void SetupSerialPortWithWorkaround()
{
try
{
//http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html
// This class is meant to fix the problem in .Net that is causing the ObjectDisposedException.
SerialPortFixer.Execute(_serialPort.PortName);
}
catch (Exception e)
{
Logger.Log(TraceLevel.Info, "Work around for .Net SerialPort object disposed exception failed with : " + e + " Will still attempt open port as normal");
}
}
public void Close()
{
try
{
comPortStream.Close();
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPortStream.Close raised exception: " + ex);
}
try
{
_onDataReceived = null;
_serialPort.Close();
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPort.Close raised exception: " + ex);
}
}
public void WriteData(string aData, DataReceivedDelegate handler)
{
try
{
OnDataReceived += handler;
_serialPort.Write(aData + "\r\n");
}
catch (Exception ex)
{
Logger.Log(TraceLevel.Error, "ComPort.WriteData raised exception: " + ex);
if (null != _observer)
{
_observer.SerialPortWriteException();
}
}
}
}
}
【问题讨论】:
-
您似乎正在“泄漏”(不关闭或处置)
SerialStream类的实例(因为在您的堆栈跟踪中调用了SerialStream.Finalize),我建议这是 问题,但是要确定这与您当前的问题有什么关系,需要更多信息。 -
感谢您的回复。哪些信息有助于查明问题?
-
包含上述
Close方法的整个类会有所帮助。 -
这个错误是纯粹的癌症,MS 在 2017 年仍然没有解决这个问题
标签: c# .net-2.0 serial-port objectdisposedexception