Sinatr answered correctly, it is stale data in the registry that remains stale until the opened port is closed and the resources released.
SerialPort.Close()
does signal to release the resources, but you probably have to force a garbage collection. (I had to for my app.)
So something like:
//EDIT: this actually isn't consistent, and I wouldn't recommend.
// I recommend the notes following the EDIT below.
try
{
if (port != null)
port.Close(); //this will throw an exception if the port was unplugged
}
catch (Exception ex) //of type 'System.IO.IOException'
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}
port = null;
EDIT:
So, it turns out this was terribly inconsistent, even on the same machine. The Nuget library SerialPortStream is an independent implementation of Microsoft's SerialPort
, and gracefully catches all the bugs I had except detecting when the USB device was unplugged.
My solution is now checking when the USB device is plugged back in, evident when there are duplicate entries in SerialPortStream.GetPortNames()
. Closing the port fully closes it, so calling the garbage collector isn't necessary anymore.
I use the following function to routinely check the connected serial ports:
private List<string> m_portList;
public event EventHandler<string[]> PortListChanged;
public void CheckForAddedDevices()
{
string[] portNames = SerialPortStream.GetPortNames();
if (portNames == null || portNames.Length == 0)
{
if (m_portList.Count > 0)
{
m_portList.Clear();
PortListChanged?.Invoke(this, null);
}
}
else
{
if (m_portList.Count != portNames.Length)
{
m_portList.Clear();
m_portList.AddRange(portNames);
//check for duplicate serial ports (when usb is plugged in again)
for (int i = 0; i < m_portList.Count - 1; i++)
{
for (int j = i + 1; j < m_portList.Count; j++)
{
if (String.Compare(m_portList[i], m_portList[j]) == 0)
{
m_portList.Clear();
Close();
}
}
}
PortListChanged?.Invoke(this, m_portList.ToArray());
}
else
{
bool anyChange = true;
foreach (var item in portNames)
{
anyChange = true;
for (int i = 0; i < m_portList.Count; i++)
{
if (String.Compare(m_portList[i], item) == 0)
{
anyChange = false;
break;
}
}
if (anyChange)
break;
}
if (anyChange)
{
m_portList.Clear();
m_portList.AddRange(portNames);
//check for duplicate serial ports (when usb is plugged in again)
for (int i = 0; i < m_portList.Count - 1; i++)
{
for (int j = i + 1; j < m_portList.Count; j++)
{
if (String.Compare(m_portList[i], m_portList[j]) == 0)
{
m_portList.Clear();
Close();
}
}
}
PortListChanged?.Invoke(this, m_portList.ToArray());
}
}
}
}