所以我有一个代码来检测插入方法的设备
SerialPort.GetPortNames();
无论如何,一切正常,除非我打开一个现有的端口(通过从列表中选择它)
port = new SerialPort(portname, 9600);
port.Open();
然后,如果设备被拔掉,它不会从列表中删除..我认为这是因为端口没有关闭..
但我无法弄清楚为什么它仍然在列表中如果我不手动关闭它,即使设备已拔下..
port.Close();
因为如果我打开一个不在列表中的端口,它就不会出现在列表中..
有人能解释一下这种行为吗?
答案 0 :(得分:6)
完全由USB设备驱动程序模拟串行端口。在端口打开时拔出端口通常是一个非常糟糕的主意。即使您的SerialPort对象在端口上打开了句柄,也有很多驱动程序使端口消失。这往往会导致生成DataReceived,PinChanged和ErrorReceived事件的工作线程崩溃。该异常不可捕获,因为它发生在工作线程上,终止您的程序。有些司机甚至拒绝尝试关闭端口,因此无法干净地结束您的程序。
听起来你有一个不错的驱动程序,只要你不调用Close()就可以保持模拟端口的存活。这是一件好事,不是问题。不要指望在用户的计算机上工作,你无法预测他们的设备会得到什么样的驱动程序。购买建议是一个好主意。
长话短说,串口是非常原始的设备,可以追溯到计算的石器时代。它们没有即插即用的支持,所以发生的事情是完全不可预测的。只有理智的事情是在设备使用时永远不要拔掉电缆。这不难做:)更多关于它在this answer中造成的麻烦。
答案 1 :(得分:1)
这个主题可能很有趣:COM port disappears when unplugging USB。您是否尝试过Dispose SerialPort对象?
答案 2 :(得分:0)
它可能是陈旧数据效果,因为SerialPort
是still using该com-port(它没有处理,注册表未更新等):
端口名称是从系统注册表获取的(例如,HKEY_LOCAL_MACHINE \ HARDWARE \ DEVICEMAP \ SERIALCOMM)。如果注册表包含陈旧或其他不正确的数据,则GetPortNames方法将返回不正确的数据。
当您使用USB转串口适配器时,一旦拔掉它,您将开始获得“拒绝访问”或类似此异常的情况,如果您尝试在打印前打开一些内容。您可以尝试Close
然后GetPortNames
返回正确的列表。
答案 3 :(得分:0)
Sinatr正确回答,注册表中的陈旧数据保持陈旧,直到关闭打开的端口并释放资源为止。
SerialPort.Close()
确实发出了释放资源的信号,但是您可能必须强制进行垃圾回收。 (我必须为我的应用程序。)
类似这样:
//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;
编辑:
因此,事实证明,即使在同一台机器上,这也非常不一致。 Nuget库SerialPortStream是Microsoft SerialPort
的独立实现,可以优雅地捕获除检测USB设备何时拔出外的所有错误。
我的解决方案现在是检查何时重新插入USB设备,尤其是在SerialPortStream.GetPortNames()
中有重复的条目时。关闭端口会完全关闭它,因此不再需要调用垃圾收集器。
我使用以下功能来例行检查连接的串行端口:
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());
}
}
}
}