当我们在用VS进行串口编程时,在打开串口前,经常想知道当前PC上存在多少个串口,哪些串口可用?哪些串口已经打开了,最好是在一个Combo Box中列表系统当前所有可用的串口以供选择,然而如何获取系统当前可用的串口有哪些呢?

这里介绍的方法也是最简单也是最笨的一种方法,即一个一个去试,试完了就知道了。至于还有没有其它更好的方法,暂不在本文所讨论的范围之内。

一个在对话框的OnInitDialog函数内做如下操作:

1 初始化时检测串口

  1. BOOL Ctbox_debug_viewDlg::OnInitDialog()
  2. {
  3. CDialogEx::OnInitDialog();
  4. // Add "About..." menu item to system menu.
  5. // IDM_ABOUTBOX must be in the system command range.
  6. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  7. ASSERT(IDM_ABOUTBOX < 0xF000);
  8. CMenu* pSysMenu = GetSystemMenu(FALSE);
  9. if (pSysMenu != NULL)
  10. {
  11. BOOL bNameValid;
  12. CString strAboutMenu;
  13. bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
  14. ASSERT(bNameValid);
  15. if (!strAboutMenu.IsEmpty())
  16. {
  17. pSysMenu->AppendMenu(MF_SEPARATOR);
  18. pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  19. }
  20. }
  21. // Set the icon for this dialog.  The framework does this automatically
  22. //  when the application's main window is not a dialog
  23. SetIcon(m_hIcon, TRUE);         // Set big icon
  24. SetIcon(m_hIcon, FALSE);        // Set small icon
  25. // TODO: Add extra initialization here
  26. AddCom();//向组合框中添加串口设备
  27. m_CombolPort.SetCurSel(0);
  28. //...
  29. }

AddCom函数如下定义:

  1. void Ctbox_debug_viewDlg::AddCom(void)
  2. {
  3. EnumerateSerialPorts(ports,portse,portsu);
  4. unsigned short uicounter;
  5. unsigned short uisetcom;
  6. CString str;
  7. //获取可用串口个数
  8. uicounter = portse.GetSize();
  9. //如果个数大于0
  10. if(uicounter > 0)
  11. {
  12. //初始化串口列表框
  13. for(int i=0; i<uicounter; i++)
  14. {
  15. uisetcom = portse.ElementAt(i);
  16. str.Format(_T("COM%d "),uisetcom);
  17. m_CombolPort.AddString(str);
  18. }
  19. }
  20. }

EnumerateSerialPorts函数如下:

  1. void Ctbox_debug_viewDlg::EnumerateSerialPorts(CUIntArray& ports, CUIntArray& portse, CUIntArray& portsu)
  2. {
  3. //清除串口数组内容
  4. ports.RemoveAll();
  5. portse.RemoveAll();
  6. portsu.RemoveAll();
  7. //因为至多有255个串口,所以依次检查各串口是否存在
  8. //如果能打开某一串口,或打开串口不成功,但返回的是 ERROR_ACCESS_DENIED错误信息,
  9. //都认为串口存在,只不过后者表明串口已经被占用
  10. //否则串口不存在
  11. for (int i=1; i<256; i++)
  12. {
  13. //Form the Raw device name
  14. CString sPort;
  15. sPort.Format(_T("\\\\.\\COM%d"), i);
  16. //Try to open the port
  17. BOOL bSuccess = FALSE;
  18. HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
  19. if (hPort == INVALID_HANDLE_VALUE)
  20. {
  21. DWORD dwError = GetLastError();
  22. if (dwError == ERROR_ACCESS_DENIED)
  23. {
  24. bSuccess = TRUE;
  25. portsu.Add(i);       //已占用的串口
  26. }
  27. }
  28. else
  29. {
  30. //The port was opened successfully
  31. bSuccess = TRUE;
  32. portse.Add(i);      ////可用的串口
  33. //Don't forget to close the port, since we are going to do nothing with it anyway
  34. CloseHandle(hPort);
  35. }
  36. //Add the port number to the array which will be returned
  37. if (bSuccess)
  38. ports.Add(i);   //所有存在的串口
  39. }
  40. }

如上操作即可将系统当前可用的所有串口添加到CombolPort所对应的Combol Box中了。

2 打开串口

代码如下:

  1. void Ctbox_debug_viewDlg::OnBnClickedBtOpen()
  2. {
  3. // TODO: Add your control notification handler code here
  4. if(m_mscomm.get_PortOpen())
  5. {
  6. m_mscomm.put_PortOpen(FALSE);
  7. GetDlgItem(IDC_BT_OPEN)->SetWindowText(_T("打开"));
  8. ShowInfo(_T("关闭串口成功!"));
  9. m_OpenStatus =false;
  10. return;
  11. }
  12. UpdateData(TRUE);
  13. m_OpenStatus =true;
  14. //当前端口号
  15. int curPort =portse.ElementAt(m_CombolPort.GetCurSel());
  16. m_mscomm.put_CommPort(curPort);//端口号
  17. m_mscomm.put_InBufferSize(1024);//接收缓冲区
  18. m_mscomm.put_OutBufferSize(1024);//发送缓冲区
  19. m_mscomm.put_InputLen(0);//设置当前接收区数据长度为0,表示全部读取
  20. m_mscomm.put_InputMode(1);//以二进制方式读写数据
  21. m_mscomm.put_RThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件
  22. //波特率
  23. DWORD baudrate;
  24. switch(m_CombolBaudrate.GetCurSel())
  25. {
  26. case 0:
  27. baudrate =115200;
  28. break;
  29. case 1:
  30. baudrate =9600;
  31. break;
  32. default:
  33. ASSERT(FALSE);
  34. break;
  35. }
  36. CString setting;
  37. setting.Format(_T("%d,n,8,1"),baudrate);
  38. m_mscomm.put_Settings(setting/*_T("115200,n,8,1")*/);//波特率,无校验,8个数据位,1个停止1位
  39. m_mscomm.put_PortOpen(TRUE);//打开串口
  40. GetDlgItem(IDC_BT_OPEN)->SetWindowText(_T("关闭"));
  41. ShowInfo(_T("打开串口成功!"));
  42. }

3 串口热拔插时检测串口

这里主要利用Cwnd的ON_WM_DEVICECHANGE消息来处理。

ON_WM_DEVICECHANGE消息在VS2010中好像只能通过手动来添加,反正我没找到可以通过对话的形式来添加的,后续有知道的兄台麻烦告知我一下。

因此,首先得手动添加ON_WM_DEVICECHANGE消息:

第一步:在消息映射BEGIN_MESSAGE_MAP(Ctbox_debug_viewDlg, CDialogEx)中添加:

  1. ON_WM_DEVICECHANGE()

第二步:在头文件类的定义中添加函数声明:

  1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);

第三步:实现函数

  1. BOOL Ctbox_debug_viewDlg::OnDeviceChange(UINT nEventType,DWORD dwData)
  2. {
  3. //DEV_BROADCAST_DEVICEINTERFACE* dbd = (DEV_BROADCAST_DEVICEINTERFACE*) dwData;
  4. switch (nEventType)
  5. {
  6. case DBT_DEVICEREMOVECOMPLETE://移除设备
  7. case DBT_DEVICEARRIVAL://添加设备
  8. RefreshCom();//刷新组合框的内容
  9. break;
  10. default:
  11. break;
  12. }
  13. return TRUE;
  14. }

RefreshCom函数如下:

  1. void Ctbox_debug_viewDlg::RefreshCom(void)
  2. {
  3. int count =m_CombolPort.GetCount();
  4. for(int i=0;i<count;i++)
  5. {
  6. m_CombolPort.DeleteString(count -1 -i);
  7. }
  8. AddCom();
  9. m_CombolPort.SetCurSel(0);
  10. }

第四步:在.cpp文件中包含头文件

  1. #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下检测当前存在的串口及串口热拔插的更多相关文章

  1. 如何在linux下检测内存泄漏

    之前的文章应用 Valgrind 发现 Linux 程序的内存问题中介绍了利用Linux系统工具valgrind检测内存泄露的简单用法,本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节. ...

  2. 如何在linux下检测内存泄漏(转)

    本文转自:http://www.ibm.com/developerworks/cn/linux/l-mleak/ 本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨.其中包括 ...

  3. 如何在linux下检测(自身)IP冲突

    最近遇到一个需求,或者说是一个用户现场问题. 我们设备先安装,设置dhcp模式获取ip进行联网,后来又安装了其他设备,但该设备是手动设置的静态ip地址,正好与我们设备冲突,造成网络故障. 那我们就需要 ...

  4. 如何在WINDOWS下编译BOOST C++库 .

    如何在WINDOWS下编译BOOST C++库 cheungmine 2008-6-25   写出来,怕自己以后忘记了,也为初学者参考.使用VC8.0和boost1.35.0.   1)下载boost ...

  5. 教你如何在Drcom下使用路由器上校园网(以广东工业大学、极路由1S HC5661A为例)

    免责声明: 在根据本教程进行实际操作时,如因您操作失误导致出现的一切意外,包括但不限于路由器变砖.故障.数据丢失等情况,概不负责: 该技术仅供学习交流,请勿将此技术应用于任何商业行为,所产生的法律责任 ...

  6. 如何在Linux下使用Rsync

    如何在Linux下使用Rsync 吐槽 昨天对scp进行总结之后看到最后有说到Rsync,俗语有云:好奇心害死猫.抱着学习的态度将Rsync给找了出来,然后进行了一些简单的学习.下面介绍一些个常用的命 ...

  7. Chrome出了个小bug:论如何在Chrome下劫持原生只读对象

    Chrome出了个小bug:论如何在Chrome下劫持原生只读对象 概述 众所周知,虽然JavaScript是个很灵活的语言,浏览器里很多原生的方法都可以随意覆盖或者重写,比如alert.但是为了保证 ...

  8. 在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除。

    在VC下采用ADO实现BLOB(Binary)数据的存储,读取,修改,删除. 作者:邵盛松 2009-09-05 前言 1关于的BLOB(Binary)数据的存储和读取功能主要参考了MSDN上的一篇& ...

  9. 如何在Chrome下Debug Mocha的测试

    简介 经过前两篇文章的介绍,相信读者对Mocha应该有一定的认知了,本文重点讲述如何在Chrome下Debug Mocha Test, 方便你在测试fail的时候troubleshooting. 关键 ...

随机推荐

  1. 进击JavaScript核心 --- (1)基本数据类型

    ES5之前提供了 5种基本数据类型 和 1种引用数据类型 基本数据类型:Undefined, Null, String, Number, Boolean 引用数据类型:Object ES6开始引入了一 ...

  2. 常用的js工具函数

    JS选取DOM元素的方法注意:原生JS选取DOM元素比使用jQuery类库选取要快很多1.通过ID选取元素document.getElementById('myid');2.通过CLASS选取元素do ...

  3. 安装redis服务器

    安装redis服务器 Windows环境下安装: 第一步:下载压缩包(地址:https://github.com/MicrosoftArchive/redis/releases) 第二步:解压并打开 ...

  4. Hive进阶_Hive的子查询

    - 集合中如果含null数据,不可使用not in, 可以使用in- hive只支持where和from子句中的子查询- 主查询和自查询可以不是同一张表 select e.ename from emp ...

  5. Hive_Hive的数据模型_分区表

    Hive的数据模型之分区表 准备数据表: create table sampledata (sid int, sname string, gender string, language int, ma ...

  6. PHP&Java 调用C#的WCF

    步骤一:用C#声明WCF [ServiceContract] public interface IService1 { [OperationContract] void DoWork(); [Oper ...

  7. 「干货分享」模块化编程和maven配置实践一则

    ​ 封面 说到模块化编程,对我个人而言首先起因于团队协作的需要,也就是组织架构结构特点来决定,而不是跟风求得自我认同,看看我们团队的组织结构: ​ 其中: 基础平台部职责: 1.AI实验室:语音,图像 ...

  8. Jquery3

    动画 动画动画效果一:show(时间),hide(时间)说明:时间的单位为毫秒方法toggle(时间):使用动画切换显示与隐藏动画效果二:slideDown(时间),slideUp(时间)切换:sli ...

  9. cocos2dx贝塞尔曲线--使用PS辅助规划动作路径

    bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ...

  10. HBase数据模型(1)

    HBase数据模型(1) HBase数据模型(2) 1.0 HBase的特性 Table HBase以表(Table)的方式组织数据,数据存储在表中. Row/Column 行(Row)和列(Colu ...