Search code examples
c#.netserial-portfreeze

SerialPort.Close() freezes application if the USB COM Port in use has been removed


I faced my application freeze, when closing .NET C# SerialPort after the current COM Port connected to, has been removed.

Doing a SerialPort.Dispose() freezes also.

I read this blog which gave some explainations (to take with caution) on the possible issue : https://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport

Could you help me solving this issue ?


Solution

  • I found a workaround but not sure it's a good way to solve the issue.

    I'm using the dmitrynogin / PnP excellent library to handle serial COM Port add/remove events.

    private SerialPort _serialPort;
    ...
    private void Main()
    {
        ...
        Open();         // Open COM Port
        ...             // Do Stuff
    
    }
    ...
    // COM Port removed event
    private void PortCOMRemoved()
    {
        ...
        Close(true);
        ...
    }
    ...
    private void Close(bool currentCOMPortRemoved = false)
    {    
        ...
        if (currentCOMPortRemoved)
        {
            _serialPort.DtrEnable = false;
            _serialPort.RtsEnable = false;
            _serialPort.DiscardInBuffer();
            _serialPort.DiscardOutBuffer();
            // Do not close the COM Port, otherwise, it will freeze
            // This is a Bug in SerialPort class management Framework
            // On next connexion, it will create a new SerialPort instance
            // Application can close itself
        }
        else
        {
            _serialPort.Close();
        }
        ...
    }
    
    ...
    private bool Open()
    {
        bool success = false;
    
        Close();
    
        try
        {
            _serialPort = new SerialPort();
            _serialPort.ErrorReceived += HandleErrorReceived;
            _serialPort.PortName = _portName;
            _serialPort.BaudRate = _baudRate;
            _serialPort.StopBits = _stopBits;
            _serialPort.Parity = _parity;
            _serialPort.DataBits = (int)_dataBits;
            _serialPort.ReadTimeout = 1000;
    
            // We are not using serialPort.DataReceived event for receiving data since     this is not working under Linux/Mono.
            // We use the readerTask instead (see below).
            _serialPort.Open();
            success = true;
        }
        catch (Exception e)
        {
            Close();
        }
    
        return success;
    }
    

    When trying to Close() properly the SerialPort the application freeze. So why not closing it if the current COM Port has been removed ? Later when the COM Port will be plugged again, a call to Open() will create a new instance of SerialPort then forget the previous SerialPort instance that was not Closed properly. Then the application don't freeze and can be closed normaly.

    I tryed it and it's working as a Workaround hoping someone will find a better solution.

    Another way could be to bypass the native .Net SerialPort class by SerialPortStream : jcurl / SerialPortStream an independent implementation of System.IO.Ports.SerialPort and SerialStream for better reliability and maintainability.

    Best regards