locked
C# SerialPort System.ObjectDisposedException, safe handle has been closed in System.DLL RRS feed

  • Question

  • I have an application in which at start up I need to do a port discovery process to determine whether instruments are attached to the end of any number of PC com ports. These com ports could be Bluetooth enumerated or, using FTDI USB to serial line convertor drivers, a USB connection. At start up I determine which ports are being used for this session by interogating all the ports stored in a list. I do this by opeing the port and then using a synchronous write and read (using timeouts of 500ms). I put try and catch around the port open to capture the case where the port has been disconnected (USB) or is not currently accessible (Bluetooth) and create a list of instrument objects each of which will have its own serial port object. Before going into normal mode I close the ports. So in essence this is

    foreach(string portname in portstouselist)

        if open port success

            if writeline(Instrument?) success

                if Readline success

                     add instrument found and associated port to list

           close port

    Normal running operates something like a data logger so I open each of the ports to which I have an instrument connected and start an asynchronous read with an associated data received event handler and infinite time out.

    It is possible that the user connections could change during the application run. In order to recover the situation I provide the user with a 'rediscover' menu item that Closes down all the ports opened and then does the discovery process that I do at start up. Having recreated the list of attached instrument ports to use I then go back into normal logging mode.

    My problem is as follows:

    When I run my code in the Visual studio environment with the debugger running I do not encounter any problems or see any unhandled exceptions, but if I run the code without the debugger and I disconnect an instrument connected using a USB connection then during the rediscovery process I get an unhandled exception failure which closes down the application despite the fact that I am successfully capturing the open failure. In fact invoking the CLR debugger specifies that the exception is as follows:

    Unhandled System.ObjectDisposedException

    Safe handle has been closed

    in System.DLL

    Which prevents me from going further as this is in the run time library code.

    Has anybody encountered this or has anyone any ideas how to work around this problem please. The key appears to be the USB disconnection which actually cause the COM port to dissappear from the list of available ports but not until the port is first closed by the application.

     

    Monday, July 3, 2006 12:37 PM

Answers

  • This could, conceivably, have something to do with the SerialPort's internal Stream object getting disposed by the garbage collector when the physical port disappears.  Try creating a brand new SerialPort instance when you rediscover rather than using the original one.

    Monday, July 3, 2006 8:07 PM

All replies

  • This could, conceivably, have something to do with the SerialPort's internal Stream object getting disposed by the garbage collector when the physical port disappears.  Try creating a brand new SerialPort instance when you rediscover rather than using the original one.

    Monday, July 3, 2006 8:07 PM
  •  I suspect you are right in your assumption about the stream object being disposed. The problem is this stream object is wrapped by the serial com object. I can recheck the ports available whenever I do anything, albeit a some what tedious business, but this just tells me I have a problem. The crash appears to occur as I attempt to close the failed port, despite putting a try, catch around the close method, I still get a fatal unhandled exception. Unfortuantely If I do not close the COM port I can not attempt to re-open it later because the access will be denied (ie already open). This makes it impossible to start another instance on the same port.

    It looks like I will have to abandon use of the serial com object and create my own, unless they are any other clues forthcoming.

    Thursday, July 6, 2006 7:44 AM
  • I have a similar problem.  We have a device that uses FTDI USB com ports.  When the USB cable is disconnected, the ports that I am communicating on get removed from the system.  When I detect that the ports have been removed, I attempt to close them.  When the close is issued I catch the exception "Access to the port is denied".  Then I get the unhandled exception from somewhere "safe handle has been closed" and my application is terminated.  Is there a way around this?
    Wednesday, March 14, 2007 11:02 PM
  • Same Problem, so always get an application crash if device will be unplugged during active connection. An solution is needed ! Or i have to write my own SerialPort only because this ?

    Regards Sven

    Tuesday, March 20, 2007 6:51 AM
  • The problem is discussed in this Product Feedback article.  It proposes a workaround.  Add your vote, use large fonts if you don't like it.
    Tuesday, March 20, 2007 7:19 AM
  • I have the impression there is an issue with the way that the serial port object connects with the underlying com service. When the USB cable is pulled out (before the serial port is closed) the USB com service terminates but the serial port object does not notice. Worse if an asynchronous read is in process there are a number of other side effects.

    a. If you had a pending read then the CPU and memory usage starts to escalate until you close the serial object port (look at the task manager processes and performance). This is because a low level read loop continues to operate because the logic assumes it is still reading. Without the low level service this operates faster increasing CPU usage. The loop allocates memory each time round the loop but the conditions for release are not met and so the memory usage increase with each loop.

    b. A fatal unhandled exception occurs when you try and close the object.

     

    The Microsoft support team have logged the problem, but have not been able to resolve it at this time. There is no harm in indicating how many other people are experiencing the issue though! Here is what they said about the problem

     

                 I can see what's happening.  Basically we are reading data in a tight  loop.

    When you pull out  the USB cable, we are part way through a read, and are expecting more  data.

    We never meet the  loop end condition (hence the 50% CPU).  Also in the loop, structures  are

    being allocated, but  the freeing condition for these structures is not being met (hence the 100K per  second leak).

    I'm escalating your  case over to our local Critical Problem Resolution Engineer Rob Martin  (CCed).

    He will discuss this  issue with US development, to find out their view. 

     

    Looking at the code,  we currently can't see any viable workaround.  Fundamentally you will need  to

    terminate and  restart you application when the USB cable is unplugged when using the  SerialPort class.

     

    And also

     

    It was good speaking with you earlier this afternoon.  As discussed we have been working closely with our development team in Redmond to assess this issue.  During our investigations, we have undertaken a full design appraisal of our serial portprocessing implementation in the .NET Framework and evaluate thepossibility of resolving the issue by way of a code change to the .NET Framework.  Unfortunately, the best way to resolve the issue represents a considerable work item.

    Microsoft’s Developer Division Servicing Team has a primaryresponsibility to ensure the integrity and security of the platform.  Regrettably the work necessary to resolve the issue properly is not something we can undertake between releases without a real and present risk to stability of the framework. Consequently we areunable to deliver the necessary code changes at this time.  Microsoft are fully committed to properly addressingthis issue in our next revision of Visual Studio and the .NET Framework– currently schedule circa Q2 2007.

    I can confirm that the issue is a result of a design oversight on Microsoft’s part, and as mentioned over the telephone,we willcredit back to your support agreement with this service request.   Please do not hesitate to contact me should you have further questions or need additional information in connection to this incident.

     

     

    To prevent (a) getting out of hand try and get the user to close before pulling the cable out. If this is not possible then detect the loss of port from the available ports list (static method in serial port object) as soon as possible and close the serial port down.

    To overcome (b) a short term (but not ideal solution) is to get the system to handle the unhandled exception “quietly” by adding an App.config file to the main application with the following

     

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <runtime>

        <legacyUnhandledExceptionPolicy enabled="1"/>

      </runtime>

    </configuration>

      

    This stops the unhandled exception from closing the application (but be careful it could also hide other errors which you should be handling)

    Wednesday, March 28, 2007 7:51 AM
  • Hi,

     

    I'm having the identical problem as stated above. The problem I am now having is, I have implemented the below and if I remove the USB device on my laptop it doesn't crash etc (as it's suppose to do). My Laptop has VS2005 installed etc. Once I deploy my application on my other Windows XP Pro SP2 or Windows XP SP2 Embedded devices I get the unhandled exception when I unplug the USB device.


    Can someone point me in the correct direction? Is there something else I need to do/set etc?

     

    To overcome (b) a short term (but not ideal solution) is to get the system to handle the unhandled exception “quietly” by adding an App.config file to the main application with the following

     

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <runtime>

        <legacyUnhandledExceptionPolicy enabled="1"/>

      </runtime>

    </configuration>

      

    Regards

     

    Andrew

    Tuesday, April 3, 2007 10:10 AM
  • Hi all, and thank you for the information on this topic...
    Unfortunatelly i find myself in the very same situation. From the message above from BWTSOL, i see that a revision was scheduled to be released in Q2...Any news about that ?

    Does anyone have a workaround already (without restricting unhandled exceptions)

    Thank you in advance,
    -Arlind Cela

    Wednesday, September 26, 2007 3:25 PM
  • The next release of Visual Studio (Visual Studio 2008) is scheduled to be released Februrary 2008 (http://blogs.msdn.com/cdndevs/archive/2007/07/11/visual-studio-2008-launch.aspx).

     

    I don't know if this fix made it into this release...

    Friday, September 28, 2007 4:46 PM
  • There is a change in EventLoopRunner.WaitForCommEvent() in the V3.5 beta 2 version of SerialPort.  It looks a bit strange (checks for Access Denied) but I would assume this patch was made to avoid this untrappable exception.
    • Proposed as answer by E. Schoch Thursday, January 26, 2012 9:05 PM
    Friday, September 28, 2007 5:19 PM
  • Hi peter, nobugs, and thank you for your reply.

    I personally do not know how it works, but should Microsoft not make a fix for existing products as well (VS2005/.NET 2.0)?
    This is closed software, so...Microsoft is the only one who can fix it (and they were supposed to do so around Q2).

    We have been blaming the PC for the +50% CPU and it costed so much time to get after this problem; and now if i understand properly, you are telling me that it is not sure if there is a fix and "if" there would be one, we will have to switch to VS2008/.NET 3.5?

    I find this a bit strange...do you maybe know if there is someone at Microsoft i could contact about this issue?

    Greetings,
    -Arlind Cela







    Monday, October 1, 2007 8:02 AM
  • V3.5 of the framework replaces V2.0, it will be a free download and you won't need to purchase VS2008 or recompile your program.  If you have an urgent problem, you should call Microsoft Support.  Beware that his thread only discusses a SerialPort problem that is evident when the port is removed, the workaround is trivial.  It has nothing to do with CPU load.
    Monday, October 1, 2007 12:25 PM
  • There is a service pack to .NET 2.0 that should be released the same time as .NET 3.5; but, again, I don't know if it includes a fix for your problem.  As nobugz says, if this is a important issue contact PSS.  Otherwise, you could try downloading Visual Studio 2008 (which includes a beta of the .NET 2.0 service pack) to see if you problem has been resolved.

     

    Monday, October 1, 2007 12:59 PM
  •  

    What do you mean with an trivial workaround?

     

    Best regards

     

    Sven

    Monday, October 1, 2007 1:57 PM
  • Isn't it obvious?  Don't unplug the device while your program is running.
    Monday, October 1, 2007 2:39 PM
  • I believe that would be a walkaround rather than a workaround. While it could work when using the application for yourself...you can expect troubles when delivering the application to your customers.

    In our case we use an application to configure/monitor/update firmware for our devices. Some of our customers need  to configure/update a number of devices daily and telling them 'do not switch devices when the application is still running' is just not right.
    Tuesday, October 2, 2007 12:53 PM
  • with the latest VS2008 i'm still running into problems with disconnecting a USB/serial converter.  instead of throwing an uncatchable object disposed exception, it's now an uncatchable unauthorized access exception!

    i came up with a hackish workaround...
    GC.SuppressFinalize(_port.BaseStream);

    seems to work so far...
    Tuesday, January 8, 2008 8:28 PM
  • Don't even think about using SerialPort in .Net 3.5. It is so full of errors that it may be regarded as useless and it may even destroy the COM ports if you load your application on an XP PC - see this warning: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2635314&SiteID=1

    Wednesday, January 9, 2008 8:45 AM
  • Hallo Leute

     

    Ich hab jetzt so 50 Stunden infestiert und hab für mich eine Lustige Lösung für das Problem gefunden!!!!

    Mir is es ur komisch vogekommen das man beim debugen keinen Fehler bekommt und so hab ich mir gedacht man kann ja einen ähnlichen zustand erreichn wärend der Laufzeit =>

     

    1) Mal schaun das man fast immer auf den comport zugreift am besten mit einen unabhängigen thread...

    2) dann bei einem Fehler (es tritt ein fehle beim zugriff auf die recourse auf wenn der USB abgestekt wird)

    den fehler natürlich abfangen!

    Dann ganz lustig ein Paar secunden Warten mit Thread.Sleep(5000)

    Bei mir gehts mit 5 sec fehlerfrei

    3) Dann den Basestream zerstören ... mögliche Fehler wieder abfangen falls er schon zertört wurde!!

     

    Ich kann mir nicht genau erklären was da passiert ich danke das durch das abstecken die recourse verlohren geht und vom GC gefressen wird irgendwie kann er sich aber doch noch retten wenn eine Pause engelegt wird ... wie auch

     

    in english:

    After you find out that the Comport is unplugt => whenn an error bei Using the serlialport recours happens

    Then as soon as possible make a brak with Threading.sleep(5000)

     

    Bestes gelingen

     

    MFG Patrick Knöbel

    Thursday, February 7, 2008 2:20 PM
  • Have you got a working example about

    Code Snippet

    GC.SuppressFinalize(serialPort.BaseStream);



    I detect the COM loss during a write operation and call immediately the function you suggested, but it fails throwing an exception, since the port is not open and the access to the base stream can only be performed when the port is open.

    It seems that the 3.5 SerialPort implementation correctly reports that the port is closed, but keeps on throwing an unhandeled exception.
    The finalize suppression method does not work for me, or at least I was not able to replicate the result hypermegachi could achieve.
    Friday, March 21, 2008 12:54 PM
  • Hello

     

    Sorry I'm working witch the Framework 2.0 and there I have used the Break of 3 Sekounds and I never have an extanthon error sice then.

    I dont know waht they habe change for the version 2.0 to 3.5.

     

    MFG Patrick Knöbel

    Sunday, March 23, 2008 9:13 AM
  • I beleive I found the answer, I came across the same problem by creating an autoconection program it goes through each port in the system and interogates the port if a valid response is received then the program connects to that port. It basically stops the user having to know which COM port they are on. However when I used a cheap laptop with a cheap usb 232 adaptor and windows vista basic, this problem occurred.

    I solved it by re-loading the serialport class everytime I am going to open it, so for example my serialport was a static global object called sp,

    so before opening it I did:
     

       sp = new SerialPort();

    then re-configure sp with the correct baud and port settings,

    then resubscribe any events

    i.e.

     sp.DataReceived += new .....


    Hope this helps people
    • Proposed as answer by Dan Walmsley Wednesday, March 4, 2009 1:34 PM
    Wednesday, March 4, 2009 12:34 PM
  • I managed to solve this problem, as mentioned above i tried to do a program that autodetected the port by interrogating it. This on some hardware generated the errors talked about.

    Here is my new code that is unaffected by this error that detects the port (it send ":P" down every serial port at 2400 bps and if within ~500ms it hears ":c" then that port is connected to.)

      bool Received = false;  
     
     public string DetectPortName()  
            {  
                string Result = "";  
                sp = new SerialPort();  
                sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);  
                sp.ReceivedBytesThreshold = 2;  
                sp.BaudRate = 2400;  
                foreach (string s in SerialPort.GetPortNames())  
                {  
                    sp.PortName = s;  
                    try 
                    {  
                        sp.Open();  
                        sp.Write(":P");  
                        Thread.Sleep(autocon_latency);  
                        if (Received)  
                        {  
                            char[] buff = new char[10];  
                            sp.Read(buff, 0, sp.BytesToRead);  
                            if (buff[1] == 'c')  
                            {  
                                Result = s;  
                            }  
                            Received = false;  
                        }  
                        sp.Close();  
                    }  
                    catch (Exception) { }  
                }  
                return Result;  
            }  
     
            private void sp_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)  
            {  
                Received = true;  
     
            } 

    The reason why my old code generated this error (only on some hardware it worked fine 99% of machines) was because the garbage collecter disposes the SerialPort.BaseStream, to get around this before I open a port I do:

    sp = new SerialPort();  
     
    //Now re-setup port and subscribe to events (again)  
    sp.BaudRate = 19200;  
    sp.PortName = COM4;  
    sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);  
    sp.Open(); 

    This may or may not make sense to you but trust me the key to this error is using the line,

    sp = new SerialPort(); 

    What ever has cause this error causes the old instance to the serial port class to become unstable, so reinstantiating it with the "new" keyword reloads the serialport class into memory and you no longer have the instability.

    Since from what I can gather MS are not likely to fix this bug, probably because it is so hard to replicate, this is the only hope if you are suffering from this.

    I beleive it is also important for developers not suffering with this problem to be made aware of this because their clients could end up with a combination of usb adaptor/ pc that causes the error in future.

    contact me if you want further advice on this error, I have spent almost a week debugging and coming up with this workaround.
    • Proposed as answer by Dan Walmsley Thursday, March 5, 2009 4:02 PM
    Thursday, March 5, 2009 4:02 PM
  • Hi everyone  ... and Dan in particular

    That looks very much like it would he of use to me ... I am however, no coder by any stretch. I have tried to implement a simlar addition of opening a new port but this is not getting around my issue.

    For me the application is for an oled computer display ... http://code.google.com/p/omauraoleddisplay/ ... I would be very grateful of any insight you may be able to offer for my specific issue.

    The problem that I have is that when the system comes out of sleep mode it fails to access the serial port again until a full system reboot occurs. This is only for a small %age of user h/w configs and I guess for the majority it functions as expected.

    Various solutions have been tried including manually closing the serial port down on the sleep event and now opening a "new" port of resume ... unfortunately this has not had any impact.

    If you would like any examples or snippets of code that I have tried then just shout.

    Many thanks

    Sam
    Saturday, March 14, 2009 1:36 AM
  • Does anyone know if this problem has been fixed (or addressed) in the new .NET 4.0 Beta 2?

    Would rather not have to rely on GC.SuppressFinalize "workaround"

    Thanks!!
    Thursday, December 10, 2009 6:31 PM
  • I have the problem also,so I use serialport class to search the port number,and use MSCOMM.ocx to communicte;but the baud rate can only highly to 230400 
    Friday, January 1, 2010 3:03 AM
  • i had used below solution.

    i think when you find a comport  after search or use it write this statement- PORT.dispose();  for every comport... so you can write it in loop also.... so it's need to write only one time.....

    so i am 100% sure that your problem will solved....

    Friday, April 2, 2010 7:58 AM
  • instead of write sp.close();  WRITE ONLY sp.dispose();

    your code will work successfully......

    Friday, April 2, 2010 8:03 AM
  • instead of write sp.close();  WRITE ONLY sp.dispose();

    your code will work successfully......

    Friday, April 2, 2010 8:03 AM
  • You can additionaly check underling stream like this

    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
            */
            if (BaseStream.CanRead)
            {
              GC.ReRegisterForFinalize(BaseStream);
            }
          }
          catch
          {
          }
    

    Tuesday, October 5, 2010 9:12 AM
  • If I use GC.SuppressFinalize(serialPort.BaseStream), it still doesn't work in my case. Although the serial port object is not disposed by GC, the serial port can't receive data yet.

    I find another way, and it works always!

    I write a endless loop to check and create a new serial port object if it is disposed by GC.

    while (true)

    {

    Thread.Sleep(60000);

    if (serialPort == null)

    {

    serialPort = new SerialPort(portName, 9600,Parity.None,8);

    serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);

    serialPort.Open();

    }

    }

    Wish it's usefull for you guys!

    • Proposed as answer by Wachauski Thursday, February 16, 2012 9:25 PM
    • Unproposed as answer by Wachauski Thursday, February 16, 2012 9:25 PM
    Friday, July 22, 2011 2:49 AM
  • Hello,

    My environment is the following:

    1. Windows 7 64-bit

    2. C#

    3. Visual Studio 2010

    4. .Net 4.0

    I had a thread running that opened up a serial com port.  And when the main application shut down the thread that closed the com port, I would receive an error in debug mode: System.ObjectDisposedException.

    After trying out the suggested workaround @ http://zachsaw.blogspot.com/2010/07/net-serialport-woes.html, my application still encountered the error. 

    So I moved the closing of the com port to above the thread abort; and used the "lock" on the com port object.  This produced a catchable (try-catch) error in the thread when the com port object was reading.  The SerialPortFixer class was also removed.  Here's the basic code:

    lock (this)

    {

        thePort.Close();

    }

    readThread.Abort();

    readThread.Join(THREAD_END_WAIT_TIME);

    • Edited by Wachauski Thursday, February 16, 2012 9:42 PM missing code
    Thursday, February 16, 2012 9:39 PM
  • I struggled with this for a long time.  I was about to give up when I found the solution. I was able to fix the problem by doing the following:

    In my PortManager class I created a global SerialPort, Timer, and List<string>.

    SerialPort _port = new SerialPort();

    Timer _timeOut;

    List<string> _portsNotAttempted;

    The SerialPort will make all of my connections, the timer lets the PortManager class know when no data is being received and the List<string> is used to keep track of the ports I have not tried to connect to yet.

    I then setup the timer and the port in the constructor.

    public PortManager(IGrowToolsUI ui) { _timeOut = new Timer(3000); _timeOut.Elapsed += new ElapsedEventHandler(TimeOut);

    //A port name is required so I passed in fake one till it can be set. _port = new SerialPort("InitialPortName", 19200, Parity.None, 8, StopBits.One); _port.DataReceived += new SerialDataReceivedEventHandler(DataReceived);

    _portsNotAttempted = SerialPort.GetPortNames().ToList(); }

    I then have a ConnectToPort method that starts the process.

    public void ConnectToPort() { //Make sure there are ports that have not been attempted yet. if (PortsNotAttempted.Count > 0) { //Get the first port in the list. var portName = PortsNotAttempted.FirstOrDefault(); //Remove the port name since we are about to try and connect to it. PortsNotAttempted = PortsNotAttempted.Where(p => p != portName).ToList();

    try { _port.PortName = portName; _port.Open(); _port.DiscardInBuffer(); _port.DiscardOutBuffer(); _timeOut.Start(); } catch { if (_port != null) { _port.Close(); } ConnectToPort(); } } else { //If there are not ports that have not been attempted then grab list again and start over PortsNotAttempted = SerialPort.GetPortNames().ToList(); _timeOut.Start(); } }

    The key here is that I am not recreating the port each time.  I am just assigning it a new name.  I close the port if an error occurs as well as in the TimeOut method.

    private void DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
    //Stop timer to prevent timeout issue.
            _timeOut.Stop();

    //Do you port validation in here. Also wrap your code in a try catch in here.

    _timeOut.Start();

    }

    private void TimeOut(object sender, ElapsedEventArgs e) { //If port has timed out then close it and try to connect to another. _port.Close();

    ConnectToPort(); }

    I am not sure why the Safe handle has been closed error occurs but I do know that it was caused by continually creating new SerialPort classes.  If you use the same one over and only change the PortName property and close it before you open it again it should work fine.

    Wrapping your code in a try catch will prevent the Access Denied errors that seem to be caused by a thread hanging on.  The nice thing is that this code will just skip it and come back to it later and check if the handle has been released.

    I have been running my application in test now for a few days.  I unplug the USB device periodically and everything seems to be working fine.  Good luck and I hope this helps the next poor person that has to work with SerialPorts.

    • Proposed as answer by lkmoody Monday, December 17, 2012 5:15 AM
    Monday, December 17, 2012 5:08 AM
  • Check this out: https://github.com/Microsoft/dotnet/blob/master/releases/net471/dotnet471-changes.md -> "SerialPort streams no longer terminate the process when exceptions occur on the background thread. This can happen when removing a USB serial port while in use. This new behavior is controlled by the Switch.System.IO.Ports.DoNotCatchSerialStreamThreadExceptions AppContext switch. This switch is set to truetf get by default when targeting .NET 4.7 or below. [428461, System.dll, Bug]" - Ref: https://blogs.msdn.microsoft.com/dotnet/2017/08/07/welcome-to-the-net-framework-4-7-1-early-access/

    Robert Breitenhofer, MICROSOFT   Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Tuesday, August 8, 2017 7:33 AM
  • It works!! Thank you very much.
    Thursday, September 7, 2017 6:58 AM