1、用于监听Windows消息
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;//窗口过程 if (hwndSource != null) hwndSource.AddHook(new HwndSourceHook(DeveiceChanged)); //挂钩
2、勾子函数
public const int WM_DEVICECHANGE = 0x219; //Windows消息编号 COM消息 public const int DBT_DEVICEARRIVAL = 0x8000; public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
//钩子函数 private IntPtr DeveiceChanged(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WM_DEVICECHANGE) { ComboBoxComReset(); switch (wParam.ToInt32()) { case DBT_DEVICEARRIVAL://设备插入 break;
case DBT_DEVICEREMOVECOMPLETE: //设备卸载 if(PortIsOpen) { PortIsOpen = false; ControlChange(true); } break;
default: break; } } return IntPtr.Zero; }
问题:在不调试情况下运行,串口开启的状态下,拔掉串口设备,报关闭串口异常,随后闪退。调试下运行无闪退现象。 分析:具体原因分析不出,因为工程较复杂,线程较多,debug情况下无法再现,所以不好排查原因。初步分析是在串口关闭之后,引起一些关联线程异常,但debug情况下没有收到任何异常提醒,原因不明。
解决:因为调试的角度没有问题,只能从其他角度解决这个问题。根本原因在使用过程中插拔设备导致,所以我在MainWindow.cs下作了插拔检测,用捕捉Windows消息的方式。设备插拔会有Windows消息传出,我捕捉到之后直接执行关闭串口与打开串口操作。
下钩子捕捉DeviceChange,我执行一次插拔,会捕捉到三条WM_DEVICECHANGE消息,不明原因,但闪退现象没有再出现。
问题:由于我的数据发送需求量较大,对准确度的需求也非常高,并且传输速度也有一定要求,但手上设备又只能是USB转串口传输。所以自然地就会碰到丢帧问题。目前碰到两种情况:1.接收到的数据包被截断 2.数据包整包丢失 分析:我的串口接收是SerialPort的DataRecieved事件。自定的上下位机传输协议的长度确定。
我在接受事件里的操作是串口缓存区数据个数大于包数就全取出来做数据匹配,正常情况下收到的都是几个整包。
出先断包的现象,初步怀疑是USB驱动的问题。主要现象是 第一次接收到 一个完整的包+下个包的前部分 下次收到余下部分的数据。 所以如果我取出来的数据里有不完整部分,会被舍弃,导致数据丢失。于是我每次只从缓存区取包长的整数倍的长度的数据出来,断帧部分存着等它的下半部分来了一起取。
事实上这样的操作确实解决了数据的大部分丢失问题,但是当串口不再有数据进来时,通知事件一直没有被触发,此时留在串口接收缓存区的剩余内容就一直无法取出来。
目前分析看来,串口的接收事件触发要满足两点:1.串口接收时钟 2.有数据进入。
我运行到最后只有时钟没有数据进入 此时我留存在缓存区里的数据就一直无法被取出。
解决:最后我也没找到Serialport类里有什么接口或属性与这问题有关,所以采取了最笨的方法,直接抛弃串口接收事件,不采用触发的形式,而是用一个接收线程去循环查询缓存区内容。线程比较耗时,死循环内有加1毫秒sleep阻塞。目前没有出什么大问题。丢数据的情况也没有再发生。只是对无端被占去的时间片资源有些耿耿于怀。