Detecting when a SerialPort gets disconnected

后端 未结 7 984
天命终不由人
天命终不由人 2020-12-01 09:25

I have an open SerialPort and receive data through the DataReceived event.

Is there any way to detect if the SerialPort gets d

相关标签:
7条回答
  • 2020-12-01 10:03

    If the device you're connecting to uses the CD pin, you can watch for that to change (other pins may apply for some devices using flow control). If not, then there isn't really a definitive way to do this.

    Depending on the expected behavior of the connected device, you might want to implement a timeout or some kind of keep alive.

    0 讨论(0)
  • 2020-12-01 10:04

    Update for those who are still facing this problem; a few points...

    1. Telling users "don't disconnect the USB device" is futile and just annoys everyone involved. Even though we wish they wouldn't, we know they will yank the device out whilst our program is running...
    2. Earlier versions of the framework did update the SerialPort.GetPortNames() immediately on yank, but 4.7 does not update the list for an open port. We have a background thread that checks this list for changes (as suggested above), which used to work great, but it no longer works...
    3. Because of this framework change (bug?), we updated the check thread to test SerialPort.IsOpen(), which in 4.7 immediately reports the device closed when the user yanks out the device. We do see the WM_DEVICECHANGE message immediately on yank but for our app its easier to just test SerialPort.IsOpen() in the background thread.

    Hope that helps, Best Regards, Dave

    0 讨论(0)
  • 2020-12-01 10:08

    USB-serial ports are a huge pain. See, for example, this question. I'm not sure whether it really was fixed with .NET 4.0, but back in the day I tried to deal with the problem of disconnections crashing the whole program with something like this:

    public class SafeSerialPort : SerialPort
    {
        private Stream theBaseStream;
    
        public SafeSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
            : base(portName, baudRate, parity, dataBits, stopBits)
        {
    
        }
    
        public new void Open()
        {
            try
            {
                base.Open();
                theBaseStream = BaseStream;
                GC.SuppressFinalize(BaseStream);
            }
            catch
            {
    
            }
        }
    
        public new void Dispose()
        {
            Dispose(true);
        }
    
        protected override void Dispose(bool disposing)
        {
            if (disposing && (base.Container != null))
            {
                base.Container.Dispose();               
            }
            try
            {
                if (theBaseStream.CanRead)
                {
                    theBaseStream.Close();
                    GC.ReRegisterForFinalize(theBaseStream);
                }
            }
            catch
            {
                // ignore exception - bug with USB - serial adapters.
            }
            base.Dispose(disposing);
        }
    }
    

    Apologies to whoever I adapted this from, it seems I failed to make a note of it in my code. The problem apparently stemmed from how .NET handled the underlying stream in the case of the serial port disappearing. It seemed you couldn't close the stream after the serial port is disconnected.

    Another strategy I used was to create a small program that did just the serial communication part and exposed a WCF service for my main program to connect to. That way, when the USB-serial adapter flakes out and crashes the communication program, I can just automatically restart it from my main program.

    Finally, I don't know why nobody ever marketed a locking USB port to avoid the whole accidental disconnection problem, especially with USB-serial adapters!

    0 讨论(0)
  • 2020-12-01 10:08

    Use the C# SerialPort.CDHolding flag.

    So save the bool to a lastCDHolding flag, before your open and read loop.

    After you read test SerialPort.CDHolding != lastCDHolding to trap changes or just test SerialPort.CDHoldin==false to detect the port was closed.

    0 讨论(0)
  • 2020-12-01 10:17

    I also faced the problem of an unhandleable exception (and not being able to detect/circumvent the problem in code) as soon as the USB-Serial adapter had been disconnected. I can confirm that the solution from Mattt Burland works.

    Simplified version:

    class SafeSerialPort : SerialPort {
        public new void Open() {
            if (!base.IsOpen) {
                base.Open();
                GC.SuppressFinalize(this.BaseStream);
            }
        }
    
        public new void Close() {
            if (base.IsOpen) {
                GC.ReRegisterForFinalize(this.BaseStream);
                base.Close();   
            }           
        }
    
        protected override void Dispose(bool disposing) {
            try {
                base.Dispose(disposing);
            } catch (Exception ex) {
                Debug.WriteLine(ex.Message);
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-12-01 10:21

    The problem is that IsOpen value is only set back to false when the Close method is executed.

    You could try caputuring the WM_DEVICECHANGE message and using that.

    http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx

    0 讨论(0)
提交回复
热议问题