【转】如何在VC下检测当前存在的串口及串口热拔插
当我们在用VS进行串口编程时,在打开串口前,经常想知道当前PC上存在多少个串口,哪些串口可用?哪些串口已经打开了,最好是在一个Combo Box中列表系统当前所有可用的串口以供选择,然而如何获取系统当前可用的串口有哪些呢?
这里介绍的方法也是最简单也是最笨的一种方法,即一个一个去试,试完了就知道了。至于还有没有其它更好的方法,暂不在本文所讨论的范围之内。
一个在对话框的OnInitDialog函数内做如下操作:
1 初始化时检测串口
- BOOL Ctbox_debug_viewDlg::OnInitDialog()
- {
- CDialogEx::OnInitDialog();
- // Add "About..." menu item to system menu.
- // IDM_ABOUTBOX must be in the system command range.
- ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
- ASSERT(IDM_ABOUTBOX < 0xF000);
- CMenu* pSysMenu = GetSystemMenu(FALSE);
- if (pSysMenu != NULL)
- {
- BOOL bNameValid;
- CString strAboutMenu;
- bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
- ASSERT(bNameValid);
- if (!strAboutMenu.IsEmpty())
- {
- pSysMenu->AppendMenu(MF_SEPARATOR);
- pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
- }
- }
- // Set the icon for this dialog. The framework does this automatically
- // when the application's main window is not a dialog
- SetIcon(m_hIcon, TRUE); // Set big icon
- SetIcon(m_hIcon, FALSE); // Set small icon
- // TODO: Add extra initialization here
- AddCom();//向组合框中添加串口设备
- m_CombolPort.SetCurSel(0);
- //...
- }
AddCom函数如下定义:
- void Ctbox_debug_viewDlg::AddCom(void)
- {
- EnumerateSerialPorts(ports,portse,portsu);
- unsigned short uicounter;
- unsigned short uisetcom;
- CString str;
- //获取可用串口个数
- uicounter = portse.GetSize();
- //如果个数大于0
- if(uicounter > 0)
- {
- //初始化串口列表框
- for(int i=0; i<uicounter; i++)
- {
- uisetcom = portse.ElementAt(i);
- str.Format(_T("COM%d "),uisetcom);
- m_CombolPort.AddString(str);
- }
- }
- }
EnumerateSerialPorts函数如下:
- void Ctbox_debug_viewDlg::EnumerateSerialPorts(CUIntArray& ports, CUIntArray& portse, CUIntArray& portsu)
- {
- //清除串口数组内容
- ports.RemoveAll();
- portse.RemoveAll();
- portsu.RemoveAll();
- //因为至多有255个串口,所以依次检查各串口是否存在
- //如果能打开某一串口,或打开串口不成功,但返回的是 ERROR_ACCESS_DENIED错误信息,
- //都认为串口存在,只不过后者表明串口已经被占用
- //否则串口不存在
- for (int i=1; i<256; i++)
- {
- //Form the Raw device name
- CString sPort;
- sPort.Format(_T("\\\\.\\COM%d"), i);
- //Try to open the port
- BOOL bSuccess = FALSE;
- HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
- if (hPort == INVALID_HANDLE_VALUE)
- {
- DWORD dwError = GetLastError();
- if (dwError == ERROR_ACCESS_DENIED)
- {
- bSuccess = TRUE;
- portsu.Add(i); //已占用的串口
- }
- }
- else
- {
- //The port was opened successfully
- bSuccess = TRUE;
- portse.Add(i); ////可用的串口
- //Don't forget to close the port, since we are going to do nothing with it anyway
- CloseHandle(hPort);
- }
- //Add the port number to the array which will be returned
- if (bSuccess)
- ports.Add(i); //所有存在的串口
- }
- }
如上操作即可将系统当前可用的所有串口添加到CombolPort所对应的Combol Box中了。
2 打开串口
代码如下:
- void Ctbox_debug_viewDlg::OnBnClickedBtOpen()
- {
- // TODO: Add your control notification handler code here
- if(m_mscomm.get_PortOpen())
- {
- m_mscomm.put_PortOpen(FALSE);
- GetDlgItem(IDC_BT_OPEN)->SetWindowText(_T("打开"));
- ShowInfo(_T("关闭串口成功!"));
- m_OpenStatus =false;
- return;
- }
- UpdateData(TRUE);
- m_OpenStatus =true;
- //当前端口号
- int curPort =portse.ElementAt(m_CombolPort.GetCurSel());
- m_mscomm.put_CommPort(curPort);//端口号
- m_mscomm.put_InBufferSize(1024);//接收缓冲区
- m_mscomm.put_OutBufferSize(1024);//发送缓冲区
- m_mscomm.put_InputLen(0);//设置当前接收区数据长度为0,表示全部读取
- m_mscomm.put_InputMode(1);//以二进制方式读写数据
- m_mscomm.put_RThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件
- //波特率
- DWORD baudrate;
- switch(m_CombolBaudrate.GetCurSel())
- {
- case 0:
- baudrate =115200;
- break;
- case 1:
- baudrate =9600;
- break;
- default:
- ASSERT(FALSE);
- break;
- }
- CString setting;
- setting.Format(_T("%d,n,8,1"),baudrate);
- m_mscomm.put_Settings(setting/*_T("115200,n,8,1")*/);//波特率,无校验,8个数据位,1个停止1位
- m_mscomm.put_PortOpen(TRUE);//打开串口
- GetDlgItem(IDC_BT_OPEN)->SetWindowText(_T("关闭"));
- ShowInfo(_T("打开串口成功!"));
- }
3 串口热拔插时检测串口
这里主要利用Cwnd的ON_WM_DEVICECHANGE消息来处理。
ON_WM_DEVICECHANGE消息在VS2010中好像只能通过手动来添加,反正我没找到可以通过对话的形式来添加的,后续有知道的兄台麻烦告知我一下。
因此,首先得手动添加ON_WM_DEVICECHANGE消息:
第一步:在消息映射BEGIN_MESSAGE_MAP(Ctbox_debug_viewDlg, CDialogEx)中添加:
- ON_WM_DEVICECHANGE()
第二步:在头文件类的定义中添加函数声明:
- afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);
第三步:实现函数
- BOOL Ctbox_debug_viewDlg::OnDeviceChange(UINT nEventType,DWORD dwData)
- {
- //DEV_BROADCAST_DEVICEINTERFACE* dbd = (DEV_BROADCAST_DEVICEINTERFACE*) dwData;
- switch (nEventType)
- {
- case DBT_DEVICEREMOVECOMPLETE://移除设备
- case DBT_DEVICEARRIVAL://添加设备
- RefreshCom();//刷新组合框的内容
- break;
- default:
- break;
- }
- return TRUE;
- }
RefreshCom函数如下:
- void Ctbox_debug_viewDlg::RefreshCom(void)
- {
- int count =m_CombolPort.GetCount();
- for(int i=0;i<count;i++)
- {
- m_CombolPort.DeleteString(count -1 -i);
- }
- AddCom();
- m_CombolPort.SetCurSel(0);
- }
第四步:在.cpp文件中包含头文件
- #include <Dbt.h>
这是因为DEV_BROADCAST_DEVICEINTERFACE,DBT_DEVICEREMOVECOMPLETE,DBT_DEVICEARRIVAL这几个东东在头文件Dbt.h中定义的,这样才能编译通过。
而AddCom函数已经在之前讲到过,回过头去看看。
这里的思想是通过检测到设备的插入和拔出时刷新组合框的内容,是通过重新测试串口的方式来实现的。
另:需要注意的是,当插入和拔出设备时,系统会检测到两次"设备改变事件",因此会两次调用OnDeviceChange函数,第一次调用时传入的函数nEventType的值固定为0x07,第二次调用时nEventType才是上述代码switch中所定义的事件,这与网上所说的需要注册是相悖的,不知道为什么网上有些文章会说一定需要注册什么的才能检测到设备改变的事件,反正我这里不需要,我用的是VS2010.
完!
见:http://blog.csdn.net/flydream0/article/details/8086976
【转】如何在VC下检测当前存在的串口及串口热拔插的更多相关文章
- 如何在linux下检测内存泄漏
之前的文章应用 Valgrind 发现 Linux 程序的内存问题中介绍了利用Linux系统工具valgrind检测内存泄露的简单用法,本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节. ...
- 如何在linux下检测内存泄漏(转)
本文转自:http://www.ibm.com/developerworks/cn/linux/l-mleak/ 本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨.其中包括 ...
- 如何在linux下检测(自身)IP冲突
最近遇到一个需求,或者说是一个用户现场问题. 我们设备先安装,设置dhcp模式获取ip进行联网,后来又安装了其他设备,但该设备是手动设置的静态ip地址,正好与我们设备冲突,造成网络故障. 那我们就需要 ...
- 如何在WINDOWS下编译BOOST C++库 .
如何在WINDOWS下编译BOOST C++库 cheungmine 2008-6-25 写出来,怕自己以后忘记了,也为初学者参考.使用VC8.0和boost1.35.0. 1)下载boost ...
- 教你如何在Drcom下使用路由器上校园网(以广东工业大学、极路由1S HC5661A为例)
免责声明: 在根据本教程进行实际操作时,如因您操作失误导致出现的一切意外,包括但不限于路由器变砖.故障.数据丢失等情况,概不负责: 该技术仅供学习交流,请勿将此技术应用于任何商业行为,所产生的法律责任 ...
- 如何在Linux下使用Rsync
如何在Linux下使用Rsync 吐槽 昨天对scp进行总结之后看到最后有说到Rsync,俗语有云:好奇心害死猫.抱着学习的态度将Rsync给找了出来,然后进行了一些简单的学习.下面介绍一些个常用的命 ...
- Chrome出了个小bug:论如何在Chrome下劫持原生只读对象
Chrome出了个小bug:论如何在Chrome下劫持原生只读对象 概述 众所周知,虽然JavaScript是个很灵活的语言,浏览器里很多原生的方法都可以随意覆盖或者重写,比如alert.但是为了保证 ...
- 在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除。
在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除. 作者:邵盛松 2009-09-05 前言 1关于的BLOB(Binary)数据的存储和读取功能主要参考了MSDN上的一篇& ...
- 如何在Chrome下Debug Mocha的测试
简介 经过前两篇文章的介绍,相信读者对Mocha应该有一定的认知了,本文重点讲述如何在Chrome下Debug Mocha Test, 方便你在测试fail的时候troubleshooting. 关键 ...
随机推荐
- RabbiMQ原理与SpringBoot使用
RabbiMQ介绍 具体代码可参考我的github:https://github.com/UniqueDong/springboot-study 一.使用场景 RabbitMQ是一个消息中间件,所以最 ...
- 求n位水仙花数
求n位水仙花数 A.两个关键 1.n位水仙花数的范围是什么? n位水仙花数的范围是[10n-1,10n) 2.如何判断是否为水仙花数 核心操作: 2-1.如何得到每一位? A.核心思想 对得到的数进行 ...
- python爬虫——web前端基础(3)
超链接的使用------>>>> 链接的引用使用的是<a>标记. <a>标记的基本语法:<a href="链接地址" ta ...
- STP-10-RPVST+
RPVST+(快速每VLAN生成树+)是一种以每个VLAN为基础,分别运行RSTP的形式,类似于PVST+.它拥有之前所描述的PVST+的优势,这为RSTP带来了亚秒级的收敛速度.因此,RPVST+和 ...
- [題解](水)luogu_P1372又是畢業季1
被入門難度的題虐...... 作者: kkksc03 吉祥物 更新时间: 2013-07-14 19:00 在Ta的博客查看 78 By lzn 数论水题一道. 首先,若可能的最大公约数为a ...
- HDU-1827-Summer Holiday(强连通分量,贪心)
链接:https://vjudge.net/problem/HDU-1827 题意: 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所 ...
- url、src与href属性的区别
http://blog.csdn.net/rickgreen/article/details/54943500
- postgresql修改数据库名
alter database abc rename to cba;
- cachecloud:Redis云管理平台
https://github.com/sohutv/cachecloud 一.CacheCloud是做什么的 CacheCloud提供一个Redis云管理平台:实现多种类型(Redis Standal ...
- Json 后台转对象的方式或者获取属性值方式。
类似这类的 json字符串 后台转成 model 或者取其中一个属性值. 需要去掉前后引号 以及将转义字符去掉.空格代替 resoult = resoult.Substring(0, resoult. ...