【转】如何在VC下检测当前存在的串口及串口热拔插

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

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

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

1 初始化时检测串口

[cpp] view plaincopy

  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函数如下定义:

[cpp] view plaincopy

  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函数如下:

[cpp] view plaincopy

  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 打开串口

代码如下:

[cpp] view plaincopy

  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)中添加:

[cpp] view plaincopy

  1. ON_WM_DEVICECHANGE()

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

[cpp] view plaincopy

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

第三步:实现函数

[cpp] view plaincopy

  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函数如下:

[cpp] view plaincopy

  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文件中包含头文件

[cpp] view plaincopy

  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

时间: 2024-11-10 06:35:10

【转】如何在VC下检测当前存在的串口及串口热拔插的相关文章

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

本文转自:http://www.ibm.com/developerworks/cn/linux/l-mleak/ 本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨.其中包括 C++ 中的 new 和 delete 的基本原理,内存检测子系统的实现原理和具体方法,以及内存泄漏检测的高级话题.作为内存检测子系统实现的一部分,提供了一个具有更好的使用特性的互斥体(Mutex)类. 1.开发背景 在 windows 下使用 VC 编程时,我们通常需要 DEBUG 模式下运行程

如何在Linux下使用Rsync

如何在Linux下使用Rsync 吐槽 昨天对scp进行总结之后看到最后有说到Rsync,俗语有云:好奇心害死猫.抱着学习的态度将Rsync给找了出来,然后进行了一些简单的学习.下面介绍一些个常用的命令.上篇的scp:12个scp传输文件的栗子. 简介 rsync是类unix系统下的数据镜像备份工具——remote sync.一款快速增量备份工具 Remote Sync,远程同步 支持本地复制,或者与其他SSH.rsync主机同步. 对于各种组织和公司,数据对他们是最重要的,即使对于电子商务,数

如何在Linux下禁用IPv6

如何在Linux下禁用IPv6 echo 1 > /proc/sys/net/ipv6/conf/all/disable_ipv6                            禁用IPv6(包括回环接口) echo 1 > /proc/sys/net/ipv6/conf/default/disable_ipv6                     禁用IPv6(默认) vim /etc/sysctl.conf                                    

VC++下封装ADO类以及使用方法

操作系统:windows 7软件环境:visual studio 2008 .Microsoft SQL 2005本次目的:介绍一个已经封装的ADO类,简单说明怎么导入使用 首先声明一下,这个封装的ADO类是在[vc知识库 ]下载的,因为最近在数据库课程设计,所以对vc++下使用ADO连接数据库不是很了解,故若是本文有错误的地方的,请不吝指出.具体的ADO类各个封装功能请进入[原文地址 ]查看.在此仅介绍使用此ADO封装类的入门,如连接数据库,显示记录等.一个测试例子如下: 使用步骤:1.先从[

如何在Linux下发送外部邮件

Linux自带mail命令的测试 步骤1: 通过mail命令发送邮件,发现无法发到外网邮箱,从网上找到相关说明,查看mail和mailx的版本 [[email protected] ~]# rpm -qa|grep mailxmailx-8.1.1-44.2.2 必须要 12以上的版本才可以向外部发邮件.(参考) 步骤2: 下载mailx-12.4并安装.下载地址:参考. 解压:tar -jxvf mailx-12.4.tar.gz2 安装:make; 可以参照这个流程进行,该流程已经验证可行.

如何在Eclipse下,实现ant的web项目修改保存后,实时部署,直接刷新即可看到结果

最近碰到了一个老项目,是ant的web项目,把项目导入到Eclipse以后,发现修改了文件之后,要先执行build.xml,再把打包好的war丢到Tomcat下,再刷新才能看到效果.由于以前没用过ant,所以自己研究了一套办法(如果ant确实有像Eclipse下修改后直接刷新就可看到结果的方法,还望众客官不吝赐教). 本项目参考了以下4个帖子: 帖子1:  http://blog.csdn.net/futurelight/article/details/624950 帖子2: http://we

如何在Linux下拷贝一个目录呢

cp -af newadmin/movie/.   uploadfile/mallvideo/ 如何在Linux下拷贝一个目录呢?这好像是再简单不过的问题了. 比如要把/home/usera拷贝到/mnt/temp,首先想到的就是 cp -R /home/usera/* /mnt/temp 但是这样有一个问题,/home/usera下的隐藏文件都不会被拷贝,子目录下的隐藏文件倒是会的. 那如何才是正确的方法呢?有人说用-a选项,有人说用find加管道. 其实没这么复杂,Google了之后,学了一

VC++下编译 程序“减肥”

在vc6 和 vs 2008下 编译 以下代码,不更改任何编译设置(vc6  40k , s2008 7k). 一.vc6下,Release 模式 编译处理. 1.去掉不必要的 链接库  工程(Project)-->设置(Settings)-->链接(link)属性页-->对象库/模块(object/library modules) 去掉所有的lib. 选择使用 MSVCRT.LIB kernel32.lib user32.lib. 可以忽略不必要的警告,比如 LINK:warning

如何在metalink下搜索经过oracle database认证的平台版本

在部署oracle产品前,首先要确定当前版本的平台是否经过oracle的认证,推荐在经过认证的平台上部署oracle产品.没有经过认证的,不建议马上部署oracle产品. 首先 ,登录进去metalink,如下图 然后,找到如下窗口 输入要查询的产品和发行版本,并选择平台名字.如上图,就是oracle database 11.2.0.3.0 在平台aix 6.1上是否经过认证.点击搜索 如果经过相应平台认证,就会提示  已在XXX 上通过认证. 如何在metalink下搜索经过oracle da