locked
Application Crash without exception when calling SerialPort.Close() (Visual C# 2005) RRS feed

  • Question

  • Dear Programmers,

    Let me introduce first, Iam a student and programming for a while now in Visual C# (Visual Studio 2005 Professional)
    Iam programming an application for a Windows Mobile device that uses the SerialPort. The use of the serial port is
    possible since .NET 2.0. The application is working like it should, but there is only one problem. When i try to call the function
    Close(), the application crashes. Normally i would see a debug/exception messagebox, but that is not the case. The screen is
    just freezed and the only thing i can do is press the 'X' button in the upperright corner. I cant start it again and i need to restart
    my phone. I tried to catch this error with 'try/catch' but it still freezes.. no catch at all. It seems that this error especially occurs when
    there is data in the databuffer that is not read yet, but i can't control that because the data that i use is generated by a bluetooth GPS.

    The problem occurs on the following targets:

    Pocket PC 2003 Second Edition Emulator (shipped with Visual Studio 2005 Professional)
    My phone with Windows Mobile 6.0 (HTC Wizzard)

    My Question is: Is there anyway to close the serial port so that i can successfully use the SerialPort.Close() function? Else my phone or other
    Windows mobile device will crash evertime when i want to quit the application.

    Kind regards,

    Mathijs


    • Moved by OmegaMan Friday, May 8, 2009 1:47 AM (From:Visual C# General)
    Thursday, May 7, 2009 10:20 PM

Answers

  • Here's a snippet for using a thread from the thread pool to attempt to close the connection.  Make certain that you have using System.Threading at the top of your code.  The code below simply calls QueueUserWorkItem to get a worker thread from the ThreadPool to close the serial port.  This will mean that the Close method will not be called on the main UI thread which is what causes your UI to freeze.  However this does not necessarily mean that your problem is completely solved. 

            private void CloseSerialPortInWorkerThread()
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
            }
    
            private void ThreadProc(Object stateInfo)
            {
                // Attempt to close serial port
                if (this._mySerialPort.IsOpen == true)
                    this._mySerialPort.Close();
            }

    why do you robot?
    Monday, May 11, 2009 7:35 PM

All replies

  • I've seen similar issues with SerialPort class.  

    1) you could try calling DiscardInBuffer() and DiscardOutBuffer() before calling Close().  

    2)  if you haven't already, be sure to hook the ErrorReceived event from the SerialPort class.  Not all serial errors are reported by the OS. 

    3) it's probably freezing/hanging because you're calling Close() in the UI thread.  You might try having a separate thread where you call Close so that the UI can continue.

    Just some ideas to try...

    why do you robot?
    • Proposed as answer by therobotgeek Friday, May 8, 2009 6:58 PM
    Friday, May 8, 2009 6:58 PM
  • Dear Malleswar and therobotgeek,

    First, i would like to thank you both for replying to my topic.
    I have read the topics that malleswar gave me. For as far i could read, there was no solution for the Close() crash problem.

    I tried to following new things

    - Set the WriteTimeout to 1000 (1000ms) instead of -1 (unlimited)
    - Set the ReadTimeout to 1000 (1000ms) instead of -1 (unlimited)
    - Call the DiscardInBuffer() and DiscardOutBuffer() functions prior to the Close() function.
    - Hook the ErrorReceived event

    Still, the program crashes without firing the ErrorReceived event, or the try/catch. I also found out that the program ONLY crashes
    when there is data in the databuffer to process. This data is read by SerialPort.Readline()

    Things to try:

    -Calling the Close() function in a different thread. I have no idea to implement this. therobotgeek, can you maybe give me an example how to realise
    this? Would this be the same like the delegate function i use for the SerialPort.Readline() and the UI Textbox?

    Kind Regards,

    Mathijs

    Friday, May 8, 2009 9:39 PM
  • Have you solved the problem? If not maybe you can post the repro steps and code here.


    Please mark the post that helps you, and unmark that does not. This benefits our community members.
    Monday, May 11, 2009 10:03 AM
  • The problem is still not solved. I was actually awaiting a reply of therobotgeek.
    I made a small testprogram with only the serialport in it to reproduce the error as
    you suggested.

    the project (Visual C# 2005) can be downloaded from:

    http://www.livetrack.nl/dev/Mathijs_SerialPort.rar

    To successfully reproduce the error, you need to send date with a baudrate of 115200 to the selected comport.
    I made a small program that does this, but this is not yet included in the RAR file. If someone needs this program,
    i will put it online too.

    Instructions:

    -Select the Serial Port
    -Press Connect
    -Send a lot of continuous data to the port (This program only receives data)
    -Press the Close button
    -You will see a text 'Trying to Close' and it might be followed with 'Port Closed'
    -It may take 2 or 3 times, but at some time, the text 'Trying to Close' will appear and the program is freezed

    For the people who dont like to download RAR files, here is the main code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO.Ports;
    
    namespace Mathijs_SerialPort
    {
        public partial class Form1 : Form
        {
            delegate void SetTextCallback(string text);
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void menuItem1_Click(object sender, EventArgs e)
            {
                Application.Exit();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                // Nice methods to browse all available ports:
                string[] ports = SerialPort.GetPortNames();
    
                // Add all port names to the combo box:
                foreach (string port in ports)
                {
                    cmbComSelect.Items.Add(port);
                    cmbComSelect.SelectedItem = port;
                }
            }
    
            private void SetText(string text)
            {
                // InvokeRequired required compares the thread ID of the
                // calling thread to the thread ID of the creating thread.
                // If these threads are different, it returns true.
                if (this.ReceivedData.InvokeRequired)
                {
                    SetTextCallback d = new SetTextCallback(SetText);
                    this.Invoke(d, new object[] { text });
                }
                else this.ReceivedData.Text = text;
            }
    
            private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                string InputData;
    
                try
                {
                    InputData = serialPort1.ReadLine();
                    SetText(InputData);
    
                }
                catch
                {
                    SetText("Error");
                }
            }
    
            private void ComClose_Click(object sender, EventArgs e)
            {
                try
                {
                    serialPort1.DiscardInBuffer();
                    serialPort1.DiscardOutBuffer();
                    ReceivedData.Text = "Trying to Close";
                    serialPort1.Close();
                    ReceivedData.Text = "Port Closed";
                }
                catch
                {
                    ReceivedData.Text = "Failed to Close";
                }
            }
    
            private void ComConnect_Click(object sender, EventArgs e)
            {
                serialPort1.PortName = cmbComSelect.Text;
                serialPort1.Open();
                serialPort1.DiscardInBuffer();
            }
    
    
    
        }
    }
    Kind Regards,

    Mathijs


    • Proposed as answer by AngeloErre Friday, March 16, 2012 12:49 AM
    Monday, May 11, 2009 12:09 PM
  • Here's a snippet for using a thread from the thread pool to attempt to close the connection.  Make certain that you have using System.Threading at the top of your code.  The code below simply calls QueueUserWorkItem to get a worker thread from the ThreadPool to close the serial port.  This will mean that the Close method will not be called on the main UI thread which is what causes your UI to freeze.  However this does not necessarily mean that your problem is completely solved. 

            private void CloseSerialPortInWorkerThread()
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
            }
    
            private void ThreadProc(Object stateInfo)
            {
                // Attempt to close serial port
                if (this._mySerialPort.IsOpen == true)
                    this._mySerialPort.Close();
            }

    why do you robot?
    Monday, May 11, 2009 7:35 PM
  • After looking at the code you posted, you could add another line to the code snippet I posted.  Then you will get a message stating that it is finished closing the port.  One thing to keep in mind if you read the MSDN docs, it states, "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."

    So don't think that the port instantly closes when you call Close method.  You need to give it a few seconds to clear the buffers, and close the underlying stream.  Hope this has been helpful.


     
           private void ThreadProc(Object stateInfo)
            {
                // Attempt to close serial port
                if (this.serialPort1.IsOpen == true)
                {
                    this.serialPort1.Close();
                    SetText("Port is closed");
                }
            }
    

    why do you robot?
    • Proposed as answer by AngeloErre Friday, March 16, 2012 12:49 AM
    Monday, May 11, 2009 7:46 PM
  • After inserting the lines you suggested, the Closing function is working properly now! When i press the Close button, it will continue
    for about a second and then the port is really closed! Just like I thought there was some data to process before the port could be closed.

    Thank you very much!

    Kind Regards,

    Mathijs
    Monday, May 11, 2009 9:25 PM
  • After looking at the code you posted, you could add another line to the code snippet I posted.  Then you will get a message stating that it is finished closing the port.  One thing to keep in mind if you read the MSDN docs, it states, "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."

    So don't think that the port instantly closes when you call Close method.  You need to give it a few seconds to clear the buffers, and close the underlying stream.  Hope this has been helpful.


     
           private void ThreadProc(Object stateInfo)
            {
                // Attempt to close serial port
                if (this.serialPort1.IsOpen == true)
                {
                    this.serialPort1.Close();
                    SetText("Port is closed");
                }
            }
    

    why do you robot?

    Hi, may you help tp use this code, i'm new to c#. I have the same problem, when i close serial port, i obtain an exception.

    This is my code

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace SimpleSerial
    {
        public partial class Form1 : Form
        {
            // Add this variable 
            string RxString;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void buttonStart_Click(object sender, EventArgs e)
            {
                serialPort1.PortName = "COM7";
                serialPort1.BaudRate = 9600;
                serialPort1.Parity = System.IO.Ports.Parity.None;
            serialPort1.DataBits = 8;
            serialPort1.StopBits = System.IO.Ports.StopBits.One;
            serialPort1.Handshake = System.IO.Ports.Handshake.None;
            serialPort1.RtsEnable = true;
    
                serialPort1.Open();
                if (serialPort1.IsOpen)
                {
                    buttonStart.Enabled = false;
                    buttonStop.Enabled = true;
                    textBox1.ReadOnly = false;
                }
            }
    
            private void buttonStop_Click(object sender, EventArgs e)
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    buttonStart.Enabled = true;
                    buttonStop.Enabled = false;
                    textBox1.ReadOnly = true;
                }
    
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (serialPort1.IsOpen)
                    
                 
                    serialPort1.Close();
            }
    
            private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
            {
                // If the port is closed, don't try to send a character.
                if (!serialPort1.IsOpen) return;
    
                // If the port is Open, declare a char[] array with one element.
                char[] buff = new char[1];
    
                // Load element 0 with the key character.
                buff[0] = e.KeyChar;
    
                // Send the one character buffer.
                serialPort1.Write(buff, 0, 1);
    
                // Set the KeyPress event as handled so the character won't
                // display locally. If you want it to display, omit the next line.
                e.Handled = true;
            }
    
            private void DisplayText(object sender, EventArgs e)
            {
                textBox1.Text = RxString ;
    
            }
    
            private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                RxString = serialPort1.ReadLine();
                if (RxString.Length > 9)
                {
                    RxString = RxString.Remove(0, 2);
    
    
                    this.Invoke(new EventHandler(DisplayText));
                }
    
                
            }
    
            private void copiatag(object sender, EventArgs e)
            {
                textBox1.Text = textBox2.Text;
    
    
            }
            
        }
    }

    Friday, March 16, 2012 12:48 AM