M
Major_Major
Guest
I am developing a C# program that communicates with positioners via RS232. I would like this program to let go of all serial ports when it shuts down and when it crashes. It doesn't really do either. I believe I have done everything recommended to correctly handle these com ports.
The actual architecture is USB to RS485 Converter. Every time I close and reopen the program, it can't get control of the ports and errors. I have to switch the USB cables to new jacks to free them, specifically:
`System.UnauthorizedAccessException: 'Access Denied: COM6'`
This happens 100% of the time if the program crashes or if I hit the square to stop debugging.
It happens 50% - 75% of the time if I shut down the debugging program orderly-like.
I do wonder if this is related to the debugging environment.
To try to fix this, I create an instance of the ComPort class for each com port that exists. It implements IDisposable and is supposed to release its com port on dispose.
Dispose() does fire as expected.
public class ComPort : INotifyPropertyChanged, IDisposable
{
public ComPort(string name)
{
portStream.PortName = name;
PositionerNodes.CollectionChanged += Nodes_CollectionChanged;
SetPortDefaults();
try
{
portStream.Open();
// TODO: Implement user-select on number of nodes
}
catch (UnauthorizedAccessException ex)
{
if (name == "COM1")
{
// eat the exception
}
else
{
Reporter.Warn($"Unable to get access to {name}. Another process may be using it.", $"Exception:\n\n{ex.Message}\n\n\nInner exception:\n\n {ex.InnerException?.Message ?? "No inner"}");
throw;
}
}
<snip></snip>
}
<snip></snip>
// IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
foreach (Node node in Nodes)
{
node.Stop();
}
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
Debug.WriteLine($"Start dispose {portStream.PortName}");
#if DEBUG
string report = $"Finish dispose {portStream.PortName}";
#endif
if (!portStream.IsDisposed)
{
if (portStream.IsOpen)
{
portStream.Close();
}
portStream.Dispose();
}
Debug.WriteLine(report);
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
~ComPort()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(false);
}
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
GC.SuppressFinalize(this);
}
}
Also, I have a method in App.xaml.cs that is supposed to shut the comports down on Exit and on unhandled exceptions. These methods seem to be firing as expected.
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ShutDown();
}
private void Application_Exit(object sender, ExitEventArgs e)
{
ShutDown();
}
private void ShutDown()
{
foreach (Node node in ComPortManager.ComPorts.SelectMany(x => x.Nodes))
{
Debug.WriteLine($"Node: {node.ID}");
node.Stop();
}
foreach (ComPort comPort in ComPortManager.ComPorts)
{
comPort.Dispose();
}
}
}
}
Continue reading...
The actual architecture is USB to RS485 Converter. Every time I close and reopen the program, it can't get control of the ports and errors. I have to switch the USB cables to new jacks to free them, specifically:
`System.UnauthorizedAccessException: 'Access Denied: COM6'`
This happens 100% of the time if the program crashes or if I hit the square to stop debugging.
It happens 50% - 75% of the time if I shut down the debugging program orderly-like.
I do wonder if this is related to the debugging environment.
To try to fix this, I create an instance of the ComPort class for each com port that exists. It implements IDisposable and is supposed to release its com port on dispose.
Dispose() does fire as expected.
public class ComPort : INotifyPropertyChanged, IDisposable
{
public ComPort(string name)
{
portStream.PortName = name;
PositionerNodes.CollectionChanged += Nodes_CollectionChanged;
SetPortDefaults();
try
{
portStream.Open();
// TODO: Implement user-select on number of nodes
}
catch (UnauthorizedAccessException ex)
{
if (name == "COM1")
{
// eat the exception
}
else
{
Reporter.Warn($"Unable to get access to {name}. Another process may be using it.", $"Exception:\n\n{ex.Message}\n\n\nInner exception:\n\n {ex.InnerException?.Message ?? "No inner"}");
throw;
}
}
<snip></snip>
}
<snip></snip>
// IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
foreach (Node node in Nodes)
{
node.Stop();
}
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
Debug.WriteLine($"Start dispose {portStream.PortName}");
#if DEBUG
string report = $"Finish dispose {portStream.PortName}";
#endif
if (!portStream.IsDisposed)
{
if (portStream.IsOpen)
{
portStream.Close();
}
portStream.Dispose();
}
Debug.WriteLine(report);
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
~ComPort()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(false);
}
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
GC.SuppressFinalize(this);
}
}
Also, I have a method in App.xaml.cs that is supposed to shut the comports down on Exit and on unhandled exceptions. These methods seem to be firing as expected.
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
ShutDown();
}
private void Application_Exit(object sender, ExitEventArgs e)
{
ShutDown();
}
private void ShutDown()
{
foreach (Node node in ComPortManager.ComPorts.SelectMany(x => x.Nodes))
{
Debug.WriteLine($"Node: {node.ID}");
node.Stop();
}
foreach (ComPort comPort in ComPortManager.ComPorts)
{
comPort.Dispose();
}
}
}
}
Continue reading...