ObjectDisposeException при закрытии SerialPort в .Net 2.0C#

Место общения программистов C#
Ответить
Anonymous
 ObjectDisposeException при закрытии SerialPort в .Net 2.0

Сообщение Anonymous »

У меня есть приложение Windows Forms на C#, которое взаимодействует с USB-ключом через COM-порт. Я использую класс SerialPort в .Net 2.0 для связи, и объект последовательного порта открыт на протяжении всего срока службы приложения. Приложение отправляет команды на устройство, а также может получать от устройства незапрошенные данные.

Моя проблема возникает при закрытии формы — я получаю (случайно, к сожалению) исключение ObjectDisposeException при попытке закрыть COM-порт. Вот трассировка стека 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 ... -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 + "*******");
}
}


Мое ведение журнала показало, что выполнение никогда не выходило за рамки попытки закрыть BaseStream SerialPort (это в первом блоке try), поэтому я экспериментировал с удалением этой строки, но исключение по-прежнему периодически выдается - журналирование во втором блоке try появилось, а затем произошло исключение. Ни один блок 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 ... -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();
}
}
}
}
}


Подробнее здесь: https://stackoverflow.com/questions/892 ... in-net-2-0
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»