I'm having a problem with the SerialPort class.
We're using multiple serialports in a generic list since we need to connect to multiple devices.
This is what our basic code looks like:
List<SerialPort> ports = new List<SerialPort>();
private void button1_Click(object sender, EventArgs e)
{
ports.Add(new SerialPort("COM6"));
ports.Add(new SerialPort("COM7"));
ports.Add(new SerialPort("COM8"));
foreach (SerialPort port in ports)
{
port.Open();
}
}
Now, after the button is clicked, if one of the devices (mobile phone in our case) is switched off or if its cable is disconnected from the USB port,there is an immediate massive memory leakage.
I have noticed a similar thread here and a couple of bug reports in Microsoft Connect.
Are you sure that the problem is with SerialPort and not the driver for the USB-Serial device? I would try another test to validate the issue:
Start up hyperterm
Connect to your problem device
Check memory usage
Disconnect in same way that causes problem in C#
Check memory usage and compare
If it does not happen, then there is a bug in particular to SerialPort. If it happens again, you would at least know that it has nothing to do with SerialPort's implementation. The problem might be in either the Window's COM Port code or in the driver you are using. Personally, I find it likelier that it the problem might be in the driver, but I'd love to know if there is some unknown issue with Window's serial ports.
I've used SerialPort before while connecting/disconnecting ports without any such problems.
Another thing you can try to is debug into the CLR's code. There are plenty of other SO questions on this topic, so it should be easy to find the method to do that. That should let you debug down a bit further and see exactly at which point in Open() the memory leak happens. Warning though, since it is a "simple" wrapper to the system's serial port, you might quickly see it go to P/Invoke world and will probably not get to see to much.
Not sure the issue is this simple, but are you disposing your SerialPort objects correctly? You need to call the Dispose method on each instance as soon as you're finished with them.
Related
I got a little problem with a USB Barcode Scanner.
I am using the Scanner with the "SerialPort" class:
this._barcodeScanner = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One) { Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 };
this._barcodeScanner.Open();
this._barcodeScanner.DataReceived += BarcodeScannerCallback;
If I unplug the USB Device while it´s opened via the "SerialPort" class, I can´t close the software properly and the virtual port stays open for all eternity or till I reboot the whole computer.
So my question is, is there any way to close the virtual port after I unplugged the device via C# code?
Greetings
[edit #1]
Alrighty, some more code:
This way I am checking every 10 seconds if the device is plugged in:
private bool CheckUsbDeviceAvailability()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName WHERE PortName = '" + this.PortName + "'");
if (searcher.Get().Count > 0)
return true;
return false;
}
Thats the Callback-Event of the Serial Port:
void BarcodeScannerCallback(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = this._barcodeScanner.ReadExisting().Replace(Convert.ToChar(2), Convert.ToChar(32)).Trim();
if (data.StartsWith("AX"))
{
string[] arrData = data.Split('\n');
this._barcodeScanner.StopAvailabilityThread();
Barcode code = new Barcode(arrData[0].Replace("\r", ""));
if (CheckIfBarcodeExists(code))
this.UpdateBarcodeNode(code);
else
this.CreateBarcodeNode(code);
BarcodeScannerCallbackEvent(sender, e, code);
this._barcodeScanner.StartAvailabilityThread();
}
this._barcodeScanner.ComDevicePluggedIn = ScannerDevice.ComAvailabilityState.Available;
}
if it doesnt answer anymore it will fire the "DeviceNotAvailableEvent()":
void BarcodeScannerDeviceNotAvailableEvent()
{
this._barcodeScanner.Close();
this._barcodeScanner.Dispose();
}
I have overriden the Dispose Event of the "SerialPort" class so that it´s going to abort the Thread:
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
this._deviceAvailableThread.Abort();
}
base.Dispose(isDisposing);
}
Serial ports date from the stone age of computing. That's where you plugged in your ASR-33 teletype to start typing in your Fortran program. The electrical interface is very simple. So is the Windows API to use a serial port from your own code. Practically any runtime environment supports them.
USB has replaced serial port hardware completely. It has a much more advanced logical interface to the machine, supporting many different type of devices. And it supports Plug and Play, allowing the operating system to detect when a device is attached or removed as well as automatically installing the device driver, etcetera.
This flexibility comes at a price however, a USB device always needs a device driver to become usable. Device drivers are not created equal. Different drivers require different ways to talk to the device. Usually done through DeviceIoControl() or Read/WriteFile() but those are very opaque API functions. In the early days of USB, device manufacturers would supply a DLL that provided a rich API to hide the implementation details.
That did not work so well, manufacturers are not very good at writing good APIs and they sure don't like to support them. So a good solution would be to support a standard API, one that's available on any machine, supported by any runtime, documented and maintained by somebody else. Like the serial port API.
That did not work so well, manufacturers are not very good at writing device drivers that emulate serial ports. The biggest hang-up with the API is that it doesn't have any support for Plug and Play. The core support for it is missing, after all serial port hardware doesn't have the logical interface to support it. There is some support for detecting that a device is attached through the DTR hardware handshake line, but no support whatsoever for detecting that the port is no longer there.
Detaching the USB device is the problem. In an ideal world, the emulator built into the device driver would simply pretend that the serial port is still there until the last handle on the device is closed. That would be the logical implementation, given that there's no way to trigger a Plug and Play event. For some strange reason that seems to be difficult to implement. Most USB drivers take the crummy shortcut, they simply make the device disappear even while it is in use.
This plays havoc on any user mode code that uses the device. Which is typically written to assume it is a real serial port and real serial ports don't suddenly disappear. At least not without drawing a bright blue spark. What goes wrong is pretty unpredictable because it depends on how the driver responds to requests on a device that's no longer there. An uncatchable exception in a worker thread started by SerialPort was a common mishap. Sounds like your driver really gets it wrong, it generates an error return code on the MJ_CLOSE driver request. Which is kind of a logical thing to do for a driver, after all the device isn't there anymore, but quite unsolvable from your end. You have a handle and you can't close it. That's up a creek with no paddle.
Every major release of .NET had a small patch to the SerialPort classes to try to minimize the misery a bit. But there's a limited amount that Microsoft can do, catching all errors and pretending they didn't happen ultimately leads to class that provides no good diagnostic anymore, even with a good driver.
So practical approaches are:
always use the Remove Hardware Safely tray icon in Windows
use the latest version of .NET
contact the vendor and ask for a driver update
ditch vendors that supply lousy drivers
tell your users that, just because it is the only thing you can do with a USB device, that unplugging it doesn't solve any problems
make closing the port easy and accessible in your UI
glue the USB connector to the port so it can't be removed
The 5th bullet is also what gets programmers in trouble. Writing serial port code isn't easy, it is heavily asynchronous and the threadpool thread that runs the DataReceived event is difficult to deal with. When you can't diagnose the software problem you tend to blame the hardware. There's very little you can do with the hardware but unplug it. Bad Idea. Now you have two problems.
This Problem Exists in .Net 2 , 3 , 3.5 you can use framework 4 (problem does not exist in .net 4)
I got a little problem with a USB Barcode Scanner.
I am using the Scanner with the "SerialPort" class:
this._barcodeScanner = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One) { Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 };
this._barcodeScanner.Open();
this._barcodeScanner.DataReceived += BarcodeScannerCallback;
If I unplug the USB Device while it´s opened via the "SerialPort" class, I can´t close the software properly and the virtual port stays open for all eternity or till I reboot the whole computer.
So my question is, is there any way to close the virtual port after I unplugged the device via C# code?
Greetings
[edit #1]
Alrighty, some more code:
This way I am checking every 10 seconds if the device is plugged in:
private bool CheckUsbDeviceAvailability()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName WHERE PortName = '" + this.PortName + "'");
if (searcher.Get().Count > 0)
return true;
return false;
}
Thats the Callback-Event of the Serial Port:
void BarcodeScannerCallback(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = this._barcodeScanner.ReadExisting().Replace(Convert.ToChar(2), Convert.ToChar(32)).Trim();
if (data.StartsWith("AX"))
{
string[] arrData = data.Split('\n');
this._barcodeScanner.StopAvailabilityThread();
Barcode code = new Barcode(arrData[0].Replace("\r", ""));
if (CheckIfBarcodeExists(code))
this.UpdateBarcodeNode(code);
else
this.CreateBarcodeNode(code);
BarcodeScannerCallbackEvent(sender, e, code);
this._barcodeScanner.StartAvailabilityThread();
}
this._barcodeScanner.ComDevicePluggedIn = ScannerDevice.ComAvailabilityState.Available;
}
if it doesnt answer anymore it will fire the "DeviceNotAvailableEvent()":
void BarcodeScannerDeviceNotAvailableEvent()
{
this._barcodeScanner.Close();
this._barcodeScanner.Dispose();
}
I have overriden the Dispose Event of the "SerialPort" class so that it´s going to abort the Thread:
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
this._deviceAvailableThread.Abort();
}
base.Dispose(isDisposing);
}
Serial ports date from the stone age of computing. That's where you plugged in your ASR-33 teletype to start typing in your Fortran program. The electrical interface is very simple. So is the Windows API to use a serial port from your own code. Practically any runtime environment supports them.
USB has replaced serial port hardware completely. It has a much more advanced logical interface to the machine, supporting many different type of devices. And it supports Plug and Play, allowing the operating system to detect when a device is attached or removed as well as automatically installing the device driver, etcetera.
This flexibility comes at a price however, a USB device always needs a device driver to become usable. Device drivers are not created equal. Different drivers require different ways to talk to the device. Usually done through DeviceIoControl() or Read/WriteFile() but those are very opaque API functions. In the early days of USB, device manufacturers would supply a DLL that provided a rich API to hide the implementation details.
That did not work so well, manufacturers are not very good at writing good APIs and they sure don't like to support them. So a good solution would be to support a standard API, one that's available on any machine, supported by any runtime, documented and maintained by somebody else. Like the serial port API.
That did not work so well, manufacturers are not very good at writing device drivers that emulate serial ports. The biggest hang-up with the API is that it doesn't have any support for Plug and Play. The core support for it is missing, after all serial port hardware doesn't have the logical interface to support it. There is some support for detecting that a device is attached through the DTR hardware handshake line, but no support whatsoever for detecting that the port is no longer there.
Detaching the USB device is the problem. In an ideal world, the emulator built into the device driver would simply pretend that the serial port is still there until the last handle on the device is closed. That would be the logical implementation, given that there's no way to trigger a Plug and Play event. For some strange reason that seems to be difficult to implement. Most USB drivers take the crummy shortcut, they simply make the device disappear even while it is in use.
This plays havoc on any user mode code that uses the device. Which is typically written to assume it is a real serial port and real serial ports don't suddenly disappear. At least not without drawing a bright blue spark. What goes wrong is pretty unpredictable because it depends on how the driver responds to requests on a device that's no longer there. An uncatchable exception in a worker thread started by SerialPort was a common mishap. Sounds like your driver really gets it wrong, it generates an error return code on the MJ_CLOSE driver request. Which is kind of a logical thing to do for a driver, after all the device isn't there anymore, but quite unsolvable from your end. You have a handle and you can't close it. That's up a creek with no paddle.
Every major release of .NET had a small patch to the SerialPort classes to try to minimize the misery a bit. But there's a limited amount that Microsoft can do, catching all errors and pretending they didn't happen ultimately leads to class that provides no good diagnostic anymore, even with a good driver.
So practical approaches are:
always use the Remove Hardware Safely tray icon in Windows
use the latest version of .NET
contact the vendor and ask for a driver update
ditch vendors that supply lousy drivers
tell your users that, just because it is the only thing you can do with a USB device, that unplugging it doesn't solve any problems
make closing the port easy and accessible in your UI
glue the USB connector to the port so it can't be removed
The 5th bullet is also what gets programmers in trouble. Writing serial port code isn't easy, it is heavily asynchronous and the threadpool thread that runs the DataReceived event is difficult to deal with. When you can't diagnose the software problem you tend to blame the hardware. There's very little you can do with the hardware but unplug it. Bad Idea. Now you have two problems.
This Problem Exists in .Net 2 , 3 , 3.5 you can use framework 4 (problem does not exist in .net 4)
Till now I opened when I needed to send data, and closed right away.
I get random "Access to Port" errors (although I always close the port after I use it),
so I was thinking maybe to leave it always open.
What is the right approach of use, assuming that every minute or two I need to send data in some COM ports?
Thanks..
Calling SerialPort.Close() frequently is a mistake. Having another app steal the port away from you isn't exactly very desirable. But more problematic, and the problem you are having, is that Close() doesn't wait for a worker thread that is started by SerialPort to exit. That worker thread raises the DataReceived, PinChanged and ErrorReceived events. It takes "a while" for it to exit, could be between milliseconds and seconds. Calling Open() again will fail until that's done.
It's a flaw in the class, but induced by the common usage for serial ports. Apps don't normally close them until the app terminates. Including never, avoiding a common deadlock scenario. Do note that the MSDN article for Close warns about this:
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.
If you're worried about the opening/closing and other apps stealing the COM port away, you could use the approach used by Microsoft for the GPS intermediate driver in windows embedded, i.e. to write an aggregator, one which opens the port, keeps it open, then provides connection points for other apps to connect to.
How you create the connections is up to you: you can get right down deep in the hardware and write a virtual com port driver that's shareable, or you can do what I did and write a simple win32 socket service that allows client programs to connect via regular windows socket connections.
Maybe not a straight forward answer, but food for thought.
There is very little harm in leaving a serial port open, so yes, keep it open. It saves you the overhead of open/closing it.
I got a little problem with a USB Barcode Scanner.
I am using the Scanner with the "SerialPort" class:
this._barcodeScanner = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One) { Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 };
this._barcodeScanner.Open();
this._barcodeScanner.DataReceived += BarcodeScannerCallback;
If I unplug the USB Device while it´s opened via the "SerialPort" class, I can´t close the software properly and the virtual port stays open for all eternity or till I reboot the whole computer.
So my question is, is there any way to close the virtual port after I unplugged the device via C# code?
Greetings
[edit #1]
Alrighty, some more code:
This way I am checking every 10 seconds if the device is plugged in:
private bool CheckUsbDeviceAvailability()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSSerial_PortName WHERE PortName = '" + this.PortName + "'");
if (searcher.Get().Count > 0)
return true;
return false;
}
Thats the Callback-Event of the Serial Port:
void BarcodeScannerCallback(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(500);
string data = this._barcodeScanner.ReadExisting().Replace(Convert.ToChar(2), Convert.ToChar(32)).Trim();
if (data.StartsWith("AX"))
{
string[] arrData = data.Split('\n');
this._barcodeScanner.StopAvailabilityThread();
Barcode code = new Barcode(arrData[0].Replace("\r", ""));
if (CheckIfBarcodeExists(code))
this.UpdateBarcodeNode(code);
else
this.CreateBarcodeNode(code);
BarcodeScannerCallbackEvent(sender, e, code);
this._barcodeScanner.StartAvailabilityThread();
}
this._barcodeScanner.ComDevicePluggedIn = ScannerDevice.ComAvailabilityState.Available;
}
if it doesnt answer anymore it will fire the "DeviceNotAvailableEvent()":
void BarcodeScannerDeviceNotAvailableEvent()
{
this._barcodeScanner.Close();
this._barcodeScanner.Dispose();
}
I have overriden the Dispose Event of the "SerialPort" class so that it´s going to abort the Thread:
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
this._deviceAvailableThread.Abort();
}
base.Dispose(isDisposing);
}
Serial ports date from the stone age of computing. That's where you plugged in your ASR-33 teletype to start typing in your Fortran program. The electrical interface is very simple. So is the Windows API to use a serial port from your own code. Practically any runtime environment supports them.
USB has replaced serial port hardware completely. It has a much more advanced logical interface to the machine, supporting many different type of devices. And it supports Plug and Play, allowing the operating system to detect when a device is attached or removed as well as automatically installing the device driver, etcetera.
This flexibility comes at a price however, a USB device always needs a device driver to become usable. Device drivers are not created equal. Different drivers require different ways to talk to the device. Usually done through DeviceIoControl() or Read/WriteFile() but those are very opaque API functions. In the early days of USB, device manufacturers would supply a DLL that provided a rich API to hide the implementation details.
That did not work so well, manufacturers are not very good at writing good APIs and they sure don't like to support them. So a good solution would be to support a standard API, one that's available on any machine, supported by any runtime, documented and maintained by somebody else. Like the serial port API.
That did not work so well, manufacturers are not very good at writing device drivers that emulate serial ports. The biggest hang-up with the API is that it doesn't have any support for Plug and Play. The core support for it is missing, after all serial port hardware doesn't have the logical interface to support it. There is some support for detecting that a device is attached through the DTR hardware handshake line, but no support whatsoever for detecting that the port is no longer there.
Detaching the USB device is the problem. In an ideal world, the emulator built into the device driver would simply pretend that the serial port is still there until the last handle on the device is closed. That would be the logical implementation, given that there's no way to trigger a Plug and Play event. For some strange reason that seems to be difficult to implement. Most USB drivers take the crummy shortcut, they simply make the device disappear even while it is in use.
This plays havoc on any user mode code that uses the device. Which is typically written to assume it is a real serial port and real serial ports don't suddenly disappear. At least not without drawing a bright blue spark. What goes wrong is pretty unpredictable because it depends on how the driver responds to requests on a device that's no longer there. An uncatchable exception in a worker thread started by SerialPort was a common mishap. Sounds like your driver really gets it wrong, it generates an error return code on the MJ_CLOSE driver request. Which is kind of a logical thing to do for a driver, after all the device isn't there anymore, but quite unsolvable from your end. You have a handle and you can't close it. That's up a creek with no paddle.
Every major release of .NET had a small patch to the SerialPort classes to try to minimize the misery a bit. But there's a limited amount that Microsoft can do, catching all errors and pretending they didn't happen ultimately leads to class that provides no good diagnostic anymore, even with a good driver.
So practical approaches are:
always use the Remove Hardware Safely tray icon in Windows
use the latest version of .NET
contact the vendor and ask for a driver update
ditch vendors that supply lousy drivers
tell your users that, just because it is the only thing you can do with a USB device, that unplugging it doesn't solve any problems
make closing the port easy and accessible in your UI
glue the USB connector to the port so it can't be removed
The 5th bullet is also what gets programmers in trouble. Writing serial port code isn't easy, it is heavily asynchronous and the threadpool thread that runs the DataReceived event is difficult to deal with. When you can't diagnose the software problem you tend to blame the hardware. There's very little you can do with the hardware but unplug it. Bad Idea. Now you have two problems.
This Problem Exists in .Net 2 , 3 , 3.5 you can use framework 4 (problem does not exist in .net 4)
I've written some C# code that checks whether a device is present on any SerialPort by issuing a command on the port and listening for a reply. When I just set the port speed, open the port, get the serial stream and start processing, it works 100% of the time. However, some of our devices work at different speeds and I am trying to probe for a device at various speeds to autonegotiate a connection as well as detect device presence.
When I do all this in a single thread there are no problems. However, 3s timeout at ten speeds is 30s per serial port, and there may be several. Hence the desire to probe all ports concurrently.
Sometimes this works. Sometimes Vista bluescreens. When I use threads to probe all the ports simultaneously it nearly always bluescreens. When I force everything to run in one thread it never happens.
A USB-serial Prolific PL-2303 adaptor is in use with x64 drivers.
#Vinko - thanks for the tip on reading minidumps.
As near as I can tell, the crux of the problem is that by starting a new asynchronous I/O operation from a different thread it is possible to give a whole new meaning to overlapped I/O, inducing a race condition inside the driver. Since the driver executes in kernel mode, BLAM!
Epilogue
Except for kicking off, don't use BeginXxx outside of the callback handler and don't call BeginXxx until you've called EndXxx, because you'll induce a race condition in driver code that runs in kernel mode.
Postscript
I have found that this also applies to socket streams.
Having written Windows drivers for one of these sort of device once, my advice would be not to waste your time with WinDbg trying to prove what you already know - i.e. that the driver you're using is buggy.
If you can find a more up-to-date driver from the PL2302, then try that, but my recommendation is that if you have to use USB->Serial adaptors, the FTDI-based ones are the best. (They're not the one I wrote the drivers for, either...)
You can also disable "Automatic Restart" under System Properties\Advanced\Start and Recovery\Settings. Once you disable that, you can see the BSOD and look for the error message, e.g. IRQL_LESS_OR_EQUAL, by searching for that error name, you can usually narrow down to the source of the problem.
Btw, not many notebook comes with serial ports nowadays, so you must be using USB-Serial converter? If that's the case, the driver might have been an issue to start with, since most manufacturer wrote the serial port driver as virtual driver.
BSOD usually means buggy drivers.
What kind of HW ports do you use? I've had BSODs with SiLabs CP21xx USB to Serial converters drivers.
There are FTDI drivers that are stable under x64 vista and win7. I second the person who said to use FTDI chipsets only.
Most of the cheap serial to usb dongles at the shops near me (Toronto, Canada) seem to be FTDI chips. It's never on the box, so I buy one, and if it's good, I go buy a box full of them.
W