WPF实现串口热插拔 (提供百度网盘源代码)
为什么实现串口热插拔:
在工业控制、仪器连接等上位机应用场景中,USB串口设备的实时插拔检测是一个常见需求。当设备被意外拔除或重新插入时,应用程序需要立即响应,更新界面状态或执行相应的处理逻辑。
很多人首先会想到使用轮询方式:定期扫描系统串口列表来检测变化。这种方法虽然实现简单,但存在明显缺陷:检测不及时、系统资源浪费,且在频繁插拔设备时可能导致界面卡顿。
实际上,Windows系统本身提供了一套完善的设备消息通知机制。通过监听系统广播的WM_DEVICECHANGE
消息,我们能够实时获知USB串口设备的插入和移除事件,从而实现真正的高效热插拔检测。
我将基于WPF框架,分享一个完整的串口热插拔检测实现方案。
实际的效果:
主要代码:
程序执行步骤:
主窗体加载时会调用Window_Loaded,这个函数添加了Windows消息处理的钩子函数,Windows有消息时会调用这个钩子函数,然后进一步判断是否是设备发生了变化,是的话再去判断是插入还是拔出,再去更新串口列表。
namespace MySerialPort
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public string[] PortNames;public const int WM_DEVICECHANGE = 0x219; //设备改变消息编号public const int DBT_DEVICEARRIVAL = 0x8000; //设备插入消息编号public const int DBT_DEVICEREMOVECOMPLETE = 0x8004; //设备移除完成消息编号private SerialPort serialPort;public MainWindow(){InitializeComponent();}/// <summary>/// 主窗体加载事件/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Window_Loaded(object sender, RoutedEventArgs e){HwndSource? hwndSource = PresentationSource.FromVisual(this) as HwndSource;if (hwndSource != null){hwndSource.AddHook(new HwndSourceHook(WindowEventHandler));PortNames = SerialPort.GetPortNames();UpdateSerialPort(PortNames);}}/// <summary>/// 串口插拔检测/// </summary>/// <param name="hwnd"></param>/// <param name="msg"></param>/// <param name="wParam"></param>/// <param name="lParam"></param>/// <param name="handled"></param>/// <returns></returns>private IntPtr WindowEventHandler(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled){if (msg == WM_DEVICECHANGE){switch (wParam.ToInt32()){case DBT_DEVICEARRIVAL://设备插入 PortNames = SerialPort.GetPortNames();Debug.WriteLine("有串口插入!");UpdateSerialPort(PortNames);break;case DBT_DEVICEREMOVECOMPLETE: //设备拔出完成PortNames = SerialPort.GetPortNames();Debug.WriteLine("有串口拔出!");UpdateSerialPort(PortNames);break;default:break;}}return IntPtr.Zero;}/// <summary>/// 串口列表更新/// </summary>/// <param name="PortNames"></param>public void UpdateSerialPort(string[] PortNames){CMBPort.Items.Clear();for (int i = 0; i < PortNames.Length; i++){CMBPort.Items.Add(PortNames[i]);}}}
}
源代码链接:
通过网盘分享的文件:MySerialPort_2.zip
链接: https://pan.baidu.com/s/1KwZ8aBwel174yLOd8X7M_Q?pwd=xcgh 提取码: xcgh