Как правильно освободить Com-порт при выходе - PullRequest
0 голосов
/ 22 октября 2019

Я занимаюсь разработкой программы на C #, которая связывается с позиционерами через RS232. Я хотел бы, чтобы эта программа отпустила все последовательные порты, когда она выключается и когда происходит сбой. Это не так.

Фактическая архитектура - конвертер USB в RS485. Каждый раз, когда я закрываю и снова открываю программу, она не может получить контроль над портами и ошибками. Я должен переключить USB-кабели на новые разъемы, чтобы освободить их, а именно:

System.UnauthorizedAccessException: 'Access Denied: COM6'

Это происходит в 100% случаев, если программа падает или я нажимаю на квадрат, чтобы остановитьотладки. Это происходит в 50% - 75% случаев, когда я выключаю программу отладки по порядку.

Интересно, связано ли это со средой отладки.

Чтобы попытаться это исправитьЯ создаю экземпляр класса ComPort для каждого существующего com-порта. Он реализует IDisposable и, как предполагается, освобождает свой com-порт при утилизации.

Dispose () запускается, как и ожидалось.

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);
        }

    }

Кроме того, у меня есть метод в App.xaml.cs, которыйПредполагается, что выключение завершается при выходе и необработанных исключениях. Эти методы, похоже, запускаются, как и ожидалось.

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();
        }
    }
}

}

...