C#: Proper way to close SerialPort with Winforms - c#

I have an app where I read from the serialport, everything goes fine, until I close the app. When I click on the [X] the app simply hangs, the UI: unresponsive.
I read from the port in the DataReceived event handler, and I close the port when FormClosed happens:
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
{
mySerialPort.Close();
}

It's not a bug.
The only reason it would hang when you close it is because in the event handler of your SerialPort object, you're synchronizing a call with the main thread (typically by calling invoke). SerialPort's close method waits for its EventLoopRunner thread which fires DataReceived/Error/PinChanged events to terminate, but since your own code in the event is also waiting for main thread to respond, you run into a dead lock situation.
The reason the bug report was closed 'as designed' is because the 'bug' is in your own code.

Serial Port hangs while closing
This is a known issue with the SerialPort class and described in this Product Feedback article as well as several threads in these forums. You may notice the "closed by design" dismissal.

If your application is calling Invoke to process recevied data try calling BeginInvoke instead.
Instead of:
this.Invoke(d, new object[] { s, tb });
use:
this.BeginInvoke(d, new object[] { s, tb });

Simplest solution if you only want to close the port when the app closes, is to just not bother to Close() the port. The port will still get closed anyway when the app disposes of the serial port. The port will be available to be opened again by your app when it restarts, or by other apps that may wish to use the port.

this work very good :
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_serialPort.IsOpen)
{
e.Cancel = true; //cancel the fom closing
Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit)); //close port in new thread to avoid hang
CloseDown.Start(); //close port in new thread to avoid hang
}
}
private void CloseSerialOnExit()
{
try
{
_serialPort.Close(); //close the serial port
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); //catch any serial port closing error messages
}
this.Invoke(new EventHandler(NowClose)); //now close back in the main thread
}
private void NowClose(object sender, EventArgs e)
{
this.Close(); //now close the form
}

Related

serialPort_DataReceived don't work in exe file

i writed a program with Serial Port as this:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
serialLabel.BackColor = Color.Red;
storage = serialPort1.ReadExisting();
if (storage.Contains("CMGL"))
{
if (storage.Length > 65)
{
processUnreadedMessages(storage);
}
else
{
Thread.Sleep(500);
}
}
else if (storage.Contains("CMTI"))
{
serialPort1.Write("AT+CMGL\r");
Thread.Sleep(500);
}
storage = "";
serialLabel.BackColor = Color.Lime;
}
in visual studio when i run program works good!
but when i'l create setup for my program or run exe file, data don't receive to serialPort, and i don't get any error. but when i send data with this program it's work!
can you help Me?
the problematic lines are probably those:
serialLabel.BackColor = Color.Red;
and
serialLabel.BackColor = Color.Lime;
there's a slim chance it will still work in developent environment, but:
The DataReceived event is raised on a secondary thread when data is
received from the SerialPort object. Because this event is raised on a
secondary thread, and not the main thread, attempting to modify some
elements in the main thread, such as UI elements, could raise a
threading exception. If it is necessary to modify elements in the main
Form or Control, post change requests back using Invoke, which will do
the work on the proper thread.
[msdn]
try instead:
serialLabel.Invoke(new EventHandler(delegate
{
serialLabel.BackColor = Color.Red;
}));
Also:
make sure you don't touch GUI or anything that should be accessed from the thread it was created on without invoking (e.g. you also shouldn't write data to EventLog without Invoking) in your method processUnreadedMessages()
Check if there's no First Chance exceptions when you debug your application
check Application EventLog for messages generated by your application.
log data you received in serialPort1_DataReceived event to a file before you do anything else (this will check if DataReceived event is raised at all when it should)
subscribe to SerialPort.ErrorReceived event

Re attach Socket

So I have a socket server running, inside an asp.net ( C# ) application (very bad approach) that notifies any device connected,
It was like that when I started working at this company and changing it is not on a priority to my supervisors even though it will be better.
So what happens is when we do an update to the Website the Socket connection stays open (in another thread), then we have to restart the Server, but what I want to do is somehow get the Thread ID on startup of the Socket, then store it, if the update is done it should reattach to that thread and end the Socket somehow or reset it.
Is this possible?
this is sample code
private void Start()
{
_socketServer = new TcpListener(IPAddress.Any, Convert.ToInt32(ConfigurationManager.AppSettings["NotificationSocketPort"]));
_socketServer.Start();
_acceptingThread = new Thread(() =>
{
while (true)
{
try
{
var client = _socketServer.AcceptTcpClient();
StartClient(client);
}
catch (ObjectDisposedException ex)
{
_acceptingThread = null;
_socketServer = null;
Start();
break;
}
}
});
_acceptingThread.Start();
}
public void Close()
{
if (_acceptingThread != null)
{
_acceptingThread.Abort(0x0);
_socketServer.Stop();
_acceptingThread = null;
_socketServer = null;
}
}
In global.asax
protected void Application_End(object sender, EventArgs e)
{
SocketNotifier.GetNotifierInstance().Close();
}
The SocketNotifier is using the Singleton Design Pattern
Frankly, this is just the wrong approach. Web apps restart, and should be expected to restart. Sockets don't like that, and should not be expected to like that. Your best bet here would be to re-write the socket code as a windows service - that way it can keep running independently of the web-app.
They [the sockets] stay open that is the problem after IIS worker process terminates and a new one is started
Probably, IIS has trouble shutting down the old process. That keeps the socket open. Your socket thread is a foreground thread. It does not prevent process termination. Also, aborting a thread does not affect IO. And your socket listening method automatically restarts itself when the socket is closed.
Remove these problems. Make the thread a background thread. Don't abort it. Don't restart it in case of an ObjectDisposedException.

SerialPort sometimes hangs on close

I am developing a .NET 4.0 WPF application in C# that controls a motor via RS232. I am having problems when exiting my application that the application sometimes deadlocks when closing the comport.
After some research on the internet I noticed this was a common problem and that using BeginInvoke in the DataReceivedEvent or closing the serialport in a different thread should solve the problem.
The problem with those workarounds are that.
1. I dont use the DataReceiveEvent.
2. closing the serialport in another thread doesnt make any difference. What happens is that the GUI shutsdown but you can see in the TaskManager that the process is still running.
Other things I have tried is:
Not closing the serialport and just exiting the application. This successfully closes the application and process but the serialport is still blocked, and to unblock the serialport I need to restart the computer.
Sleeping a couple of seconds before and after I close the serialport.
Having the application be a WinForms app. instead of WPF. No difference in the deadlock between the two.
The computer I run the program on uses com ports that are mounted on the motherboard and have Microsoft drivers.
And now for some code:
Window_Closing event looks like this:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
window.Closing -= Window_Closing;
Thread CloseDown = new Thread(new ThreadStart(server.Dispose)); //Closes serialport everything in another thread to avoid hang on serialport close.
CloseDown.Start();
}
Where server is the object that manages the serialport. And Dispose calls the serialport close function.
Serialport close function:
public void Close()
{
DebugLog.Write(3, "-->MacCommSerialPort.Close");
_com.Close();
DebugLog.Write(3, "<--MacCommSerialPort.Close");
}
Serialport settings:
_com = new SerialPort(portNumber);
_com.BaudRate = 19200;
_com.Parity = Parity.None;
_com.DataBits = 8;
_com.Encoding = Encoding.GetEncoding("Windows-1252");
_com.StopBits = StopBits.One;
_com.RtsEnable = false;
_com.DtrEnable = false;
_com.WriteTimeout = 400;
_com.ReadTimeout = 1000;
I just happened to look at your code and guess you should use the AutoThreadRest event before closing your GUI.
private static AutoResetEvent PortClosedEvent = new AutoResetEvent(false);
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
window.Closing -= Window_Closing;
Thread CloseDown = new Thread(new ThreadStart(server.Dispose));
CloseDown.Start();
PortClosedEvent.WaitOne();
}
and inside the server.Dispose method after you are done disposing the connection add this below line of code.
PortClosedEvent.Set();
I would check to make sure that the handshaking protocol between your application and the motor (i.e. sender and receiver) matches.

Show "please wait" message box

I want to show a 'please wait' message box while my main form is doing a lengthy task. As for my case, the lengthy task is transmitting serial protocol. Below is my code:
public void transmitprotocol()
{
try
{
MessageBox.Show("Please wait. Uploading logo.", "Status");
// Transmitting protocol coding here. Takes around 2 minutes to finish.
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
I've tried the above method using MessageBox like the above coding, but I always have to close the MessageBox only it will start transmitting protocol.
Is there any method I can do to still show the 'please wait' MessageBox while it transmit protocol?
You will need to do the expensive operation on a background thread. For that, use either a BackgroundWorker or the new Parallelization Library (.NET 4 and so on).
Actually you need to close the dialog because it blocks the execution until you, well, close it. What you do is that you start the operation, then show the dialog and then, once the operation is done, you close the dialog.
Now, if you're using WPF I will strongly suggest you to don't use a Dialog Box and instead use a Busy Indicator, it's free, pretty easy to use and not so ugly as the Message Box.
EDIT: Now that you specify you're using WinForms, then go ahead, implement the background worked and, why not, a transparent window without chrome whose purpose is to show a Busy label. Once the background worker ends you close that window.
You have to prepare a backgroundworker and use a windows form instead of MessageBox.
Something like this as simple as copy/paste:
Form1 msgForm;
public void transmitprotocol()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
//you can use progresschange in order change waiting message while background working
msgForm = new Form1();//set lable and your waiting text in this form
try
{
bw.RunWorkerAsync();//this will run all Transmitting protocol coding at background thread
//MessageBox.Show("Please wait. Uploading logo.", "Status");
msgForm.ShowDialog();//use controlable form instead of poor MessageBox
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
// Transmitting protocol coding here. Takes around 2 minutes to finish.
//you have to write down your Transmitting codes here
...
//The following code is just for loading time simulation and you can remove it later.
System.Threading.Thread.Sleep(5*1000); //this code take 5 seconds to be passed
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//all background work has complete and we are going to close the waiting message
msgForm.Close();
}
The easiest way to do this is to open the splash with show()
Open the desired form and pass it an instance of the splash form in the constructor:
Wait myWaitDialog = new Wait(); //Wait is your splash
myWaitDialog.Show();
myWaitDialog.Refresh(); //Otherwise screen fails to refresh splash
ScheduleClassForm myForm = new ScheduleClassForm(myWaitDialog);
myForm.TopLevel = true;
myForm.ShowDialog();
Add this code to your resulting form constructor:
public ScheduleClassForm(Form WaitWindow)
{
InitializeComponent();
WaitWindow.Close();
}
For me it failed in the form_load but worked in the constructor. Make sure your work is done (e.g. db load) prior to closing the WaitWindow.

Application won't end VideoStreams and Exit

I've got an application what's working with two video streams.
When the form is being closed, it runs this function:
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (FinalVideoDevice.IsRunning) { FinalVideoDevice.Stop(); }
if (streamMJPEG.IsRunning) { streamMJPEG.Stop(); }
Application.Exit();
}
But in reality it doesn't kill the application, only hides the form, but still is seen from TaskManager/Processes.
Any ideas what I might be doing wrong?
Thanks!
Assuming you are in Windows Forms you can call Application.ExitThread();
in general one of the reasons why you still see the process in TaskManager could be that you still have some background / worker threads active.
Roger check this question/answers as well: Application.Exit

Categories