1

UPDATE 1

I found out that if I reverse the order of my close/dispose then I get the error from dispose instead of close... so probably disposable protection means the method is only invoked once.

I've been able to replicate the error on my device by creating a short to ground on one of the Data Lines. I'm using an FT230x on my device and found that if I short the Reset Pin then communication can resume, however now I am getting a different exception from my application as soon as I do this. So technically my application will now reconnect on a restart, which is an improvement where as before I had to physically unplug and replug my device. New Exception Below:

System.ObjectDisposedException
  HResult=0x80131622
  Message=Safe handle has been closed
  Source=mscorlib
  StackTrace:
   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)
   at Microsoft.Win32.UnsafeNativeMethods.GetOverlappedResult(SafeFileHandle hFile, NativeOverlapped* lpOverlapped, Int32& lpNumberOfBytesTransferred, Boolean bWait)
   at System.IO.Ports.SerialStream.EventLoopRunner.WaitForCommEvent()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

New weirdness is that the callstack doesn't contain any of my code and Visual Studio isn't allowing me to trace it back to my code.

ORIGINAL POST

I have a device that is giving me an IOException on a SerialPort.Write, and then when I attempt to close the port I get UnauthorizedAccessException. Following that I can dispose the serialport without exception, but attempts to re-open the port result in UnauthorizedAccessException. My real confusion comes in when I keep reading that Dispose and Close are supposed to do the exact same thing. Is there a way I can recover from this without restarting the program (or in some cases the computer)?

In my project, I manage multiple devices that either use the same Com Port or use a unique com port. So I have a manager that manages my devices, finds their ports, and creates a port manager for those devices. Sometimes devices disconnect and when that happens I close and dispose the com port and the com port manager. Below is my code:

private void DisposeComPort()
{
    if (ComPort != null)
    {
        string message = "Disposing Com Port.";
        try
        {
            ComPort.DataReceived -= ComPort_DataReceived;
            ComPort.ErrorReceived -= ComPort_ErrorReceived;
            message += " Com Port Events Unsubscribed.";

        }
        catch (Exception ex)
        {
            HandleException(this, ex, "Exception attempting to remove Handlers for on " + this.ToString() + ".");

        }
        try
        {
            if (ComPort.IsOpen)
            {
                ComPort.Close(); message += " Com Port Closed.";
            }
        } catch(Exception ex)
        {
            HandleException(this, ex, "Exception attempting to close on " + this.ToString() + ".");
        }
        try
        {
            ComPort.Dispose(); message += " Com Port Disposed.";
        } catch (Exception ex)
        {
            HandleException(this, ex, "Exception attempting to Dispose Com Port on " + this.ToString() + ".");
        }
        ComPort = null;
        LogMessage(this, message);
    }
}

I have a single device that is every couple of days giving me "System.IO.IOException: A device attached to the system is not functioning" when I attempt ComPort.Write(). When this happens I attempt to dispose my com port. Under Normal circumstances I would be able to close the port and reopen it, however in this case my code fails to close and succeeds to dispose, however when my device manager attempts to re-open the com port I continue to get UnauthorizedAccessException. Below is my exception log.

11:26:35.862, Exception Sending Com Packet to Device 34 on ModbusPortManager Port COM4 Created 6:30:48 AM.
System.IO.IOException: A device attached to the system is not functioning.

   at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
   at System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult)
   at System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
   at System.IO.Ports.SerialPort.Write(Byte[] buffer, Int32 offset, Int32 count)
   at ModbusPortManager.TransmitPacket(IModbusDevice device, ComPacket packet, Int32 packetIndex) in Classes\ModbusPortManager.cs

-----------------------------------------------------------------------------

11:26:35.880, Disposing Timers. Stopped MessageReceived EventWaitHandle. Stopped PacketTimeoutTimer Timer. Stopped RetransmitTimer Timer. Stopped AgePrioritizerTimer Timer. Stopped 4/4. ~ ModbusPortManager Port COM4 Created 6:30:48 AM Disposed

-----------------------------------------------------------------------------

11:26:35.894, Exception attempting to close on ModbusPortManager Port COM4 Created 6:30:48 AM Disposed.
System.UnauthorizedAccessException: Access to the port is denied.
   at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
   at System.IO.Ports.InternalResources.WinIOError()
   at System.IO.Ports.SerialStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at System.IO.Ports.SerialPort.Dispose(Boolean disposing)
   at System.IO.Ports.SerialPort.Close()
   at ModbusPortManager.DisposeComPort() in Classes\ModbusPortManager.cs

-----------------------------------------------------------------------------

11:26:35.904, Disposing Com Port. Com Port Events Unsubscribed. Com Port Disposed. ~ ModbusPortManager Port COM4 Created 6:30:48 AM Disposed

-----------------------------------------------------------------------------

11:26:36.934, Port Manager Created. ~ ModbusPortManager Port COM4 Created 11:26:36 AM

-----------------------------------------------------------------------------

11:26:36.947, Exception Testing on ModbusPortManager Port COM4 Created 11:26:36 AM

System.UnauthorizedAccessException: Access to the port 'COM4' is denied.
   at ModbusPortManager.OpenPort() in Classes\ModbusPortManager.cs
   at ModbusPortManager.TestPort() in Classes\ModbusPortManager.cs

-----------------------------------------------------------------------------
adragon202
  • 21
  • 5
  • May be you cannot close a com port the same way you cannot close say port :80.. instead of manually disposing of your variable please try to put it inside using statement.. – estinamir Feb 14 '19 at 14:56
  • @bestinamir Yes, you _can_ close a COM Port. If you have the rights and it is open. – Fildor Feb 14 '19 at 15:15
  • Under "Remarks" in [SerialPort.Close](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.close?view=netframework-4.7.2) : _"The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly."_ – Fildor Feb 14 '19 at 15:17
  • Also, make sure it is not a hardware defect. Not sure what Exception that would cause. Maybe there is a cold soldering point. – Fildor Feb 14 '19 at 15:26
  • How are you updating your UI? Are you using the `DataReceivedEvent`? Sometimes when data is still coming through the event and you close the port it gets mad. If you are using `Invoke` I would recommend trying to use `BeginInvoke` instead as it is non-blocking. – Baddack Feb 14 '19 at 19:10
  • @Fildor I am checking the com ports every 1 second. How much time should I consider as _"Some amount of time."_ Based on my testing it leaves me to believe it may be a hardware defect of some sort, however I would still like to be able to recover from it to a degree. – adragon202 Feb 14 '19 at 21:45
  • @Baddack I am using the DataReceivedEvent. However I'm not sure how I would check it under this issue, as anything relating to Data on the port gives me an AccessDenied, and anything inside my DataReceivedEvent Method trying to access the data would be where the IOException gets thrown. – adragon202 Feb 14 '19 at 21:50
  • Avoid focusing on the wrong problem, you cannot expect anything good to happen when the write failed with such a nasty exception. This problem is caused by the device driver. First thing to do is to interview the people that are close to this machine to find out what is really going on. You do need to remind them that messing with the USB device (like jerking it out while your program is running) is not the correct way to troubleshoot the real issue they have. – Hans Passant Feb 15 '19 at 06:56
  • @Hans Passant, we're confident that we've narrowed it down to a hardware issue with the device. The practical result of making the program recoverable from this issue is making detection of these problems faster in the future. – adragon202 Feb 15 '19 at 12:06
  • 1
    It is not recoverable, replace the hardware. – Hans Passant Feb 15 '19 at 12:54

1 Answers1

1

Ultimately ended up solving the issue of the System.ObjectDisposedException by implementing the solution from ObjectDisposedException when closing SerialPort in .Net 2.0 and the class from http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html

SerialPortFixer class throws invalid parameters on some ports, but on my device it did not and the exception no longer occurs that crashed the program on reconnect.

adragon202
  • 21
  • 5