Home Dashboard Directory Help
Search

SerialPort Crashes after disconnect of USB COM port by It pedel


Status: 

Closed
 as By Design Help for as By Design


49
1
Sign in
to vote
Type: Bug
ID: 140018
Opened: 6/19/2006 5:55:34 AM
Access Restriction: Public
10
Workaround(s)
view
43
User(s) can reproduce this bug

Description

We have an application talking to a phone via a USB-cable, using
System.IO.Ports.SerialPort.

If the user unplugs the USB cable from the PC before the application has
called SerialPort.Close(), we (nearly always) get an unhandled exception
window (<application> has encountered an error and needs to close. Please
inform Microsoft about the error. Etc. etc.) about a
System.ObjectDisposedException.

Calling close after the USB cable has been unplugged does not help - it
throws an exception that we can catch (UnauthorizedAccessException), but the
error report comes anyway.

We believe this happens when the CLR disposes the serial stream. It does not
happen on "our" thread - we can't catch it.

When the USB cable is unplugged the COM port will disappear from the system
- it is not returned from SerialPort.GetPortNames().

We have the same behaviour with both SonyEricsson phones (T610, T630) and
Siemens (S55).

The phone does not appear in Safely Remove Hardware - neither when attached
or removed.

The problem does not arise when running in the debugger.

Here is sample code that exposes the problem. Attach a (turned on) cell
phone via a USB cable before running the sample - change the COM-port to
match the one you are using.

====
using System;
using System.IO.Ports;

namespace SerialPortUsbCrash {
class Program {
    static void Main(string[] args) {
     SerialPort serialPort = null;
     serialPort = new SerialPort("COM12", 19200, Parity.None, 8,
StopBits.One);
     serialPort.Open();
     Console.Write("Pull out the USB cable, and push return");
     Console.ReadLine();
     try {
        serialPort.Close();
     } catch (Exception ex) {
        Console.WriteLine("Got exception closing SerialPort: " + ex);
     }
     Console.WriteLine("- THE END -");
     Console.ReadLine();
    }
}
}
====

Any advice? Fix? Patch?

Best regards,
Speakanet
Details
Sign in to post a comment.
Posted by Petoj87 on 9/18/2013 at 11:47 PM
Im a bit unsure if i have the exact same problem, but after pulling the Serial/usb cabel it still reports as open, even tho the device is removed from the device manager....
Posted by 13910987628139.com on 7/8/2012 at 11:19 PM
Where can I find the SerialStream.cs file?
Posted by Krish Kapadia on 5/27/2012 at 11:15 PM
Hello,

This issue is not solved in .NET Framework Client Profile 4.0 and .NET framework 4.0 too and those are major release after .NET 3.5 SP1.

I use serial port to send AT commands to mobile/modem.

To re-produce this error, please follow this steps.

1. Plug in mobile using data cable.
2. Connect that mobile via COM port using Open method of Serial Port..
3. Plugged out mobile while app is running without closing COM port.
4. Then try to disconnect that COM port using Close method of serial Port. and you will get 'ObjectDisposedException' with error message 'Safe handle has been closed. This exception is not caught by any try catch block.

When this error comes software hangs and need to close forcefully.

But I solved this error because I didn't found any solution in your major release of .NET framework.

Here is how I catch that unhandled exception.

First I get all code of classes of System.IO.Ports namespace and of some dependent classes too.

Some classes are of System.IO.Ports namespace. Some classes (dependent) are not of this namespace.

InternalResources.cs
NativeMethods.cs
SafeFileMappingHandle.cs
SafeFileMapViewHandle.cs
SafeLocalMemHandle.cs
SafeNativeMethods.cs
SafeProcessHandle.cs
SafeThreadHandle.cs
SerialDataReceivedEventArgs.cs
SerialErrorReceivedEventArgs.cs
SerialPinChangedEventArgs.cs
SerialPort.cs
SerialStream.cs
SR.cs
UnsafeNativeMethods.cs


And the error is in SerialStream class.

Here is exact location of error with code you have written in SerialStream class.

SerialStream(Class) -> EventLoopRunner(internal Class) -> WaitForCommEvent (Function)

Here is code of WaitForCommEvent Function.

I have commented '// Line of error. 'this.handle' is closed. I just put an exception here.' above the line of error.

internal unsafe void WaitForCommEvent()
            {
                int lpNumberOfBytesTransferred = 0;
                bool flag = false;
                NativeOverlapped* lpOverlapped = null;
                while (!this.ShutdownLoop)
                {
                    SerialStream.SerialStreamAsyncResult ar = null;
                    if (this.isAsync)
                    {
                        ar = new SerialStream.SerialStreamAsyncResult();
                        ar._userCallback = null;
                        ar._userStateObject = null;
                        ar._isWrite = false;
                        ar._numBytes = 2;
                        ar._waitHandle = this.waitCommEventWaitHandle;
                        this.waitCommEventWaitHandle.Reset();
                        lpOverlapped = new Overlapped(0, 0, this.waitCommEventWaitHandle.SafeWaitHandle.DangerousGetHandle(), ar).Pack(this.freeNativeOverlappedCallback, null);
                    }
                    fixed (int* numRef = &this.eventsOccurred)
                    {
                        if (!UnsafeNativeMethods.WaitCommEvent(this.handle, numRef, lpOverlapped))
                        {
                            int num2 = Marshal.GetLastWin32Error();
                            if (num2 == 5)
                            {
                                flag = true;
                                break;
                            }
                            if (num2 == 0x3e5)
                            {
                                int num3;
                                bool flag2 = this.waitCommEventWaitHandle.WaitOne();
                                do
                                {
                                    /* Before
                                    flag2 = UnsafeNativeMethods.GetOverlappedResult(this.handle, lpOverlapped, ref lpNumberOfBytesTransferred, false);
                                    */
                                    
                                    // After - Start
                                    try
                                    {
                                        // Line of error. 'this.handle' is closed. I just put an exception here.
                                        flag2 = UnsafeNativeMethods.GetOverlappedResult(this.handle, lpOverlapped, ref lpNumberOfBytesTransferred, false);
                                    }
                                    catch (ObjectDisposedException)
                                    {
                                        flag2 = true;
                                    }
                                    // After - End
                                    num3 = Marshal.GetLastWin32Error();
                                }
                                while (((num3 == 0x3e4) && !this.ShutdownLoop) && !flag2);
                                if ((!flag2 && ((num3 == 0x3e4) || (num3 == 0x57))) && !this.ShutdownLoop)
                                {
                                }
                            }
                        }
                    }
                    if (!this.ShutdownLoop)
                    {
                        this.CallEvents(this.eventsOccurred);
                    }
                    if (this.isAsync && (Interlocked.Decrement(ref ar._numBytes) == 0))
                    {
                        Overlapped.Free(lpOverlapped);
                    }
                }
                if (flag)
                {
                    this.endEventLoop = true;
                    Overlapped.Free(lpOverlapped);
                }
                this.eventLoopEndedSignal.Set();
            }


So right now I'm using a serial port of your code with little modification in it. I don't know its a perfect solution but It is perfect for me.

There are many developers facing this issue. Please search 'ObjectDisposedException safe handle has been closed' in any search engine. And no solution is working.

Checkout this link
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/8a1825d2-c84b-4620-91e7-3934a4d47330/


I hope it will be solved in next release of .NET Framework. Contact me for more information.

Thanks
Posted by Luthfi on 5/11/2011 at 7:41 PM
I also experienced this bug and luckyly I found this workaround from this blog post:
http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html

The serialport class still throws an error when the usb port is removed but at least the exception is now catchable.
Posted by ServiceInMotion on 1/18/2011 at 1:51 AM
This bug has been logged multiple times across Microsoft Connect. It is a major problem for anyone using the serial port object. If .net is to be taken seriously by anyone who has to get their .net app to talk with serial port based systems they need to address this bug.

More than four years on and they still can't be bothered to fix it? Very disappointing... and to say it is by design is insulting.
Posted by JestinJ on 4/20/2010 at 4:30 AM
Thanks for reporting this issue.
This workaround had helped me a lot. Thanks a ton!
Hope this bug gets fixed on next version.
Posted by lex57ukr on 3/12/2010 at 4:39 PM
Vista 64 bit SP2, VS2008, project targets .Net 2.0

I've experienced the same issue with an instance of ObjectDisposedException thrown on an arbitrary thread when communicating with a Bluetooth device through a COM port. I'm using Rocketfish BT Adapter (RF-FLBTAD).

After disconnecting a dongle with a port still open, both CPU and RAM consumption sky-rockets. My application dies when closing a broken COM port explicitly. Suggested "workarounds" appear to "work" when Ctrl+F5 from VS only (no crash but CPU and RAM still go high - unacceptable). The bug reappears after deploying the app (the <AppName>.exe.config is deployed).

Just to be clear, Task Manager indicates that my app starts using CPU and RAM like crazy when a connection breaks - that happens inside the broken SerialPort.

So, how come this is closed?! I'm sorry, I just don't get it...
Posted by Pertti A. _ on 2/27/2010 at 7:39 PM
Come on Microsoft - Its 2010 and this bug is still not fixed! Ever heard word quality ?
How can a bug be closed when application crashes without workaround?

//The workaround in c++
// when opening port
GC::SuppressFinalize(serialPort1->BaseStream);

//add to the port closing
try
{    
     GC::ReRegisterForFinalize(this->serialPort1->BaseStream);
}
catch (Exception ^e) {}        

Posted by slava.vassiliev on 2/24/2010 at 11:51 PM
[Exuse my Eng]
Workaround is working. Thank you so much! I hope this one will be fixed in a next version ( 4 ?) .net.
Posted by Tapsa- on 1/30/2010 at 3:09 PM
"Because this workaround will allow you to catch the exception, I'm marking this as resolved now" Oh nose. Some times m$ just suprice me how mutch they are careless of bugs. This bug is still here and this kind things make developpers work to nightmare.
Posted by Everything Is Jake on 6/5/2009 at 11:41 AM
Why is this closed? People are still having problems, and there isn't a work around.
Posted by The Other Dave on 4/27/2009 at 6:47 AM
How Microsoft can leave its faithful partners twisting in the wind over something as simple as a serial port interface is completely beyond me.
Posted by ScottMcG1 on 4/4/2009 at 5:02 PM
Thank you, chanceu; your workaround works. I had this USB disconnect problem using an FTDI chip.
Posted by chanceu on 3/29/2009 at 9:50 AM
I "reopened" this issue with another feedback and Microsoft's response is they are aware of the issue and it will be fixed in the next major release of the .NET Framework. See the link below:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=426766
Posted by MohanRenganathan on 3/27/2009 at 2:51 AM
Anybody has any working solution for this issue? I am also having this issue.

Microsoft team, any update?
Posted by wtheronjones on 3/25/2009 at 12:08 AM
I'll note that this is on VS2008, .Net 3.5 SP1
Posted by wtheronjones on 3/25/2009 at 12:01 AM
I'll add my comment to the list of those also encountering this problem. Fix it please.
Posted by kwerner123 on 3/9/2009 at 2:38 PM
I've been fighting this problem for some time. I've even taken to keeping "old" serial ports in a queue so they don't get disposed until the application terminates. I then get some CLR raised uncatchable errors, but they disappear as my app closes.

This case needs to be reopened and addressed. This is a significant problem that has no reasonable work around.
Posted by Petr Vones on 3/9/2009 at 5:14 AM
That's ridiculous "resolved" state. If there is an unhandled exception causing the CLR to teminate during legal USB device unplugging it must be fixed. Reverting the exception handling policy to 1.1 behavior is NOT a solution. Can you imagine the same "workaround" for unplugging a LAN cable, if similar problem existed there ? Managed platforms should deliver as reliable as possible code. This is not the case.
Posted by Karel Kral on 3/6/2009 at 12:28 AM
Having the same issue!. Why this issue still exists in the 3.5 SP1?
Posted by shulki on 1/26/2009 at 2:54 AM
Having the same issue with FTDI devices. I'm using C# Express. Is there a way to prevent finalizer from attempting to dispose of the serial port? Or at least a way to catch this exception, so the application won't crash?
Posted by denisbohm on 12/20/2008 at 12:59 PM
Why is this bug report marked as closed? This issue still exists in .NET 3.5 SP1 and the workaround is still needed. Please reopen and fix the issue.
Posted by David McMinn on 12/18/2008 at 7:21 AM
As well as enabling legacy exception handling, you need to subscribe to the Application.ThreadException and CurrentDomain.UnhandledException and then you can see whether the exception was caused by the serial port using something like:

if (!((Exception)e.ExceptionObject).StackTrace.Contains("System.IO.Ports.SerialStream.EventLoopRunner.WaitForCommEvent()"))

and do whatever you see fit. I also find that it helps if you get the SerialPort.BaseStream member as soon as you open the port, you can then close the stream within a try/catch and then close the port within a try/catch.
Posted by Jonathon Reinhart on 11/30/2008 at 8:19 PM
This workaround did NOTHING for me. Made no difference at all. Microsoft, help!
Posted by dbasnett on 10/15/2008 at 4:07 AM
This is still present in .net 3.5 SP1.

Also, if you are using Visual Basic where would this

<configuration>
<runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</configuration>

go. Also, what where would you catch this exception???
Posted by RicardoPretrazey on 3/14/2008 at 6:39 PM
I'm also experiencing a strange error when connected to a com port.

The stack trace is..

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.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

And the error is - ObjectDisposedException=Safe handle has been closed

This happens mainly with one of our clients, but I've tried to reproduce on my machine.. after unplugging the serial port, and re-plugging it in, but it works fine, but it's happening on our client machine 20 x a day.. which is really annoying.. I think that I can trap this error, but I'd rather work out why it's happening, and how to prevent this exception in the first place.

Any ideas ?
Posted by denisbohm on 10/5/2007 at 9:45 PM
I have the same problem. With a FTDI USB serial port device, if it is inserted and com port opened, then removed and com port closed, and inserted and com port opened then later a finalizer for the serial stream of the serial port throws an unhandled exception and my service exits. This is clearly a bug in the .NET framework as the serial stream is handled by the serial port and not user code. Here is the exception:

Unhandled Exception: System.UnauthorizedAccessException: Access to the port is denied.
at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
at System.IO.Ports.SerialStream.Dispose(Boolean disposing)
at System.IO.Ports.SerialStream.Finalize()

I am closing the port when the USB device is removed - so why is there anything left to do in the finaizer? Resources should already be freed by the serial port close on my thread.

Is there any way to catch or avoid this exception until it is fixed?
Posted by calvin_baank on 6/26/2007 at 1:25 PM
Is this fixed in .net 3.0?
Posted by Microsoft on 7/12/2006 at 8:22 PM
No additional steps are required for the workaround. The problem with re-connecting appeared to be a problem with the device; other devices didn't have this problem.

Because this workaround will allow you to catch the exception, I'm marking this as resolved now. However, as mentioned in the previous post, we are considering alternate fixes for a future release. Please let us know if you have any questions.

Thanks,
Kim Hamilton
Base Class Libraries
Posted by Microsoft on 7/7/2006 at 3:42 PM
Thanks for reporting this bug. There is a workaround that allows you to revert to the 1.1 behavior and catch the exception. To do this, set the legacyUnhandledExceptionPolicy in the application config file, as in the following example:

<configuration>
<runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
</runtime>
</configuration>

To avoid this, we're considering modifying this in a future release. A related change may include adding a first class event for fatal errors.

I'm not marking this bug as resolved yet. I attempted the workaround and I could catch the exception; however, when I re-ran the program it won't connect to the com port. At the moment I'm not sure if it's the device causing this, so I'll get back to you and let you know whether the workaround requires more steps.

Thanks again, and please let me know if you have any questions,

Kim Hamilton
Base Class Libraries
Posted by Microsoft on 6/26/2006 at 2:53 PM
Thanks for reporting this issue. I'm looking into this and I'll get back to you with more information.
Thanks,
Kim Hamilton
Base Class Libraries
Posted by PaulWorksTooMuch on 6/20/2006 at 10:03 PM
I see the same problem - unhandled ObjectDisposedException with IsTerminating=true and message "Safe handle has been closed" - when unplugging the USB connection on a USB serial port. My application catches the Access Denied exceptions that occur when the application trys to access the port after the connection is broken, but the unhandled ObjectDisposedException causes the application to terminate. The call stack is as follows:

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.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

It appears that SerialStream.EventLoopRunner.WaitForCommEvent doesn't catch the exception that occurs when it accesses the inaccessible serial port.

My expected results are that the SerialPort is disposed and any exceptions resulting from trying to access the SerialPort can be catchable and don't result in the application terminating.

Maybe the WaitForCommEvent could catch the exception and initiate a dispose of the SerialStream and SerialPort. Then when an application attempts to access the SerialPort, a ObjectDisposed exception would be thrown and could be caught.

Any way to workaround this problem?
Sign in to post a workaround.
Posted by Luthfi on 5/11/2011 at 7:37 PM
There is another workaround that fix the problem in a more general way, have a look at this blog post along with it's explanation. And after reading that you can conclude it yourself if this bug is by design or not.

http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html
Posted by zob0 on 4/7/2010 at 10:07 AM
If you are looking for VB code, here's an option (easily portable to C# as well):

Imports System.IO
Imports System.IO.Ports

Public Class DisposableSerialPort
    Inherits SerialPort
    Implements IDisposable

    Private m_SerialStream As Stream

    Private disposedValue As Boolean = False        ' To detect redundant calls

    Public Overloads Shared Function GetPortNames() As String()
        Return SerialPort.GetPortNames()
    End Function

    Public Sub New(ByVal name As String)
        MyBase.New(name)
    End Sub

    Public Shadows Sub Open()
        MyBase.Open()
        m_SerialStream = MyBase.BaseStream
        GC.SuppressFinalize(m_SerialStream)
    End Sub

    ''' <summary>
    ''' Correctly disposes of a serial port. The default implementation
    ''' doesn't dispose the base stream when disposing the serial port
    ''' itself, meaning that base stream throws an exception when the GC
    ''' finalizes it, crashing the application.
    ''' </summary>
    Public Shadows Sub Dispose()
        If (Not Me.disposedValue) Then
            Console.WriteLine("Disposing connection to " & MyBase.PortName)

            Try
                MyBase.Close()
            Catch ex As Exception
            End Try

            Try
                MyBase.Dispose()
            Catch ex As Exception
            End Try

            Try
                If (m_SerialStream IsNot Nothing) Then
                    m_SerialStream.Close()
                End If
            Catch ex As Exception
            End Try

            Try
                If (m_SerialStream IsNot Nothing) Then
                    m_SerialStream.Dispose()
                End If
            Catch ex As Exception
            End Try

            Try
                If (m_SerialStream IsNot Nothing) Then
                    GC.ReRegisterForFinalize(m_SerialStream)
                End If
            Catch ex As Exception
            End Try

        Me.disposedValue = True
        End If
    End Sub
End Class
Posted by Anthony Wieser on 12/8/2009 at 2:58 AM
Another workaround.

This is my close code:
     public void Close()
        {
            if ((m_SerialPort != null))
            {
                if (m_SerialPort.IsOpen)
                {
                    m_SerialPort.Close();
                }
                else
                {
                    // zombify this thing....
                    GC.SuppressFinalize(safeBaseStream);
                    // hack around microsoft error
                }
                m_SerialPort = null;
                safeBaseStream = null;
            }

I naively thought that calling GC.SuppressFinalize(m_SerialPort.BaseStream) would work, but it threw an exception if the port was not open, so when I successfully open the device, I save a copy of the BaseStream to safeBaseStream.

This now all seems to work (though it may leak any resources the BaseStream has, but I guess that's better than crashing instead).
Posted by Deguoren on 8/6/2009 at 6:53 AM
There is another solution:

When you open the com port you save the BaseStream in a variable:

comPort.Open();
System.IO.Stream comPortStream = comPort.BaseStream;

Before you close the com port you try to close the BaseStream and catch the occuring exception:

try
{
comPortStream.Close();
}
catch (Exception ex)
{
}
comPort.Close();

I dont know why, but once the exception is catched it is not thrown again, when for instance the garbage collector tries (again) to close the stream.

Posted by ReadyToHelp on 5/26/2009 at 6:03 AM
CharlesTB your comment is great. But what is the implementation for System.ComponentModel.IContainer that you pass to constructor?
Thank you very much.
Posted by CharlieChicken on 5/12/2009 at 12:39 PM
I used chanceu's workaround. However, to get it to work, I had to add in a constructor:

public YourPort(System.ComponentModel.IContainer iC) : base(iC) {}

and then I had to replace "components" with "base.Container"

Works like a charm now. Thanks a ton, chanceu.
Posted by chanceu on 3/24/2009 at 2:05 PM
The problem seems to be with finalizing the serial port stream (BaseStream) associated with SerialPort. I am not sure why, but when the USB cable is disconnected, any attempt to access BaseStream causes an exception. Then when the SerialPort is finalized, it attempts to finalize the stream and that is where the problem occurs.

My workaround is to suppress the finalization of the serial port stream right after it is created, then un-suppress its finalization when SerialPort is disposed if the stream is still good.

public partial class YourPort : SerialPort
    {
    public new void Open()
        {
        try
            {
            base.Open();

            /*
            ** because of the issue with the FTDI USB serial device,
            ** the call to the stream's finalize is suppressed
            **
            ** it will be un-suppressed in Dispose if the stream
            ** is still good
            */
            GC.SuppressFinalize(BaseStream);
            }
        catch
            {
            }
        }

    public new void Dispose()
        {
        Dispose(true);
        }

    protected override void Dispose(bool disposing)
        {
        if (disposing && (components != null))
            {
            components.Dispose();
            }

        try
            {
            /*
            ** because of the issue with the FTDI USB serial device,
            ** the call to the stream's finalize is suppressed
            **
            ** an attempt to un-suppress the stream's finalize is made
            ** here, but if it fails, the exception is caught and
            ** ignored
            */
            GC.ReRegisterForFinalize(BaseStream);
            }
        catch
            {
            }
                
        base.Dispose(disposing);
        }
    }
Posted by Dan Walmsley on 3/5/2009 at 7:43 AM
I have spent almost a week on this error which only seems to occur on some PCs and some hardware combinations, because the error is internal to .net it is very hard to debug, as far as i can tell it seems that after you close the serialport the garbage collector gets rid of the SerialPort.BaseStream, however if you try to use the serialport again too soon (or again im not sure) then the error is caused. So to get around this.

Any where in your code before you do (sp.Open()) (where sp = the name of your serial port) re-instatiate the serial port class. This way you will not be using a serial port class that was used previously. i.e.

sp = new SerialPort();
// then re-setup the ports, including event subscription.
sp.BaudRate = 19200;
sp.PortName = "COM1";
sp.DataReceived += new SerialDataReceivedEventHandler sp_DataReceived);


Then do your sp.Open(); you should now find the problem is gone.

contact dan at walms.co.uk for more info on this problem.
Posted by dbasnett on 10/15/2008 at 11:14 AM
the previous work around does not work under vb 2008, .net 3.5 both sp1.
Posted by ShloEmi on 5/12/2008 at 1:19 AM
Use win32 API instead of .Net Comport.