Tôi có một ứng dụng biểu mẫu C# windows giao tiếp với USB dongle qua cổng COM. Tôi đang sử dụng lớp SerialPort trong .Net 2.0 để giao tiếp, và đối tượng cổng nối tiếp mở cho toàn bộ thời gian của ứng dụng. Ứng dụng gửi lệnh đến thiết bị và cũng có thể nhận dữ liệu không mong muốn từ thiết bị.ObjectDisposedException khi đóng SerialPort trong .Net 2.0
Sự cố của tôi xảy ra khi biểu mẫu bị đóng - tôi nhận được (ngẫu nhiên, không may) một ObjectDisposedException khi cố gắng đóng cổng COM. Dưới đây là Windows stack trace:
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:
Tôi đã tìm thấy bài viết từ những người có vấn đề tương tự và đã cố gắng thực hiện giải pháp [ở đây] [1]
[1]: http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html mặc dù đó là cho một IOException và đã không dừng vấn đề.
Close() Mã của tôi là như sau:
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 + "*******");
}
}
đăng nhập của tôi cho thấy thực hiện mà không bao giờ nhận được vượt quá cố gắng để đóng BaseStream của SerialPort (đây là trong try
khối đầu tiên), vì vậy tôi đã thử nghiệm với loại bỏ này dòng nhưng ngoại lệ vẫn được ném định kỳ - việc ghi nhật ký trong khối try
thứ hai xuất hiện sau đó ngoại lệ đã xảy ra. Không bắt khối bắt ngoại lệ.
Bất kỳ ý tưởng nào?
CẬP NHẬT - thêm lớp đầy đủ:
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();
}
}
}
}
}
Dường như bạn đang bị 'rò rỉ' (không đóng hoặc hủy) phiên bản của lớp 'SerialStream' (vì' SerialStream.Finalize' được gọi trong dấu vết ngăn xếp của bạn), tôi đề nghị rằng đây là * a * vấn đề, tuy nhiên để xác định những gì mối quan hệ này mang đến vấn đề hiện tại của bạn thêm thông tin là cần thiết. –
Cảm ơn bạn đã phản hồi. Thông tin nào sẽ giúp xác định vấn đề? – barry
Toàn bộ lớp có chứa phương thức 'Close' ở trên sẽ giúp ích. –