VC++ 动态检测串口的热插拔

VC++ 动态检测串口的热插拔

VC++ 动态检测串口的热插拔(一)通过遍历实现

在串口编程中经常需要知道串口号,用来配置串口,可是没有好的办法,只能进到设备管理器中去看,那么如何能够实现软件的自动检测串口号,并且可支持热插拔检测那?

下面将讲述两种方法来实现这种效果:一种是遍历设备列表中的所有串口0-255,二是通过读去注册表来实现检测

在这篇文章中将只讲述循环遍历方法的实现,在下一篇文章中将讲述利用注册表方法的实现

---------------------------------------------------

第一种方法是一种比较简单也比较笨的方法,对于每一个串口一个一个的去试,试完了也就知道了,计算机一般支持0-255即256个串口,可是利用CreateFile创建串口,只能成功创建COM0-COM9串口设备,而COM10及以上的串口创建CreateFile就会返回-1,因为10及以上已经超出的设备的命名规范,需要使用\$device\COM10方式,作为参数传递给CreateFile。

You   can   use   paths   longer   than   MAX_PATH   characters   by   calling   the   wide   (W)   version   of  CreateFile   and   prepending   "\\?\"   to   the   path.   The   "\\?\"   tells   the   function   to   turn   off   path  parsing.   This   lets   you   use   paths   that   are   nearly   32,000   Unicode   characters   long.   However,  each   component   in   the   path   cannot   be   more   than   MAX_PATH   characters   long.   You   must  use   fully-qualified   paths   with   this   technique.   This   also   works   with   UNC   names.   The   "\\?\"   is  ignored   as   part   of   the   path.   For   example,   "\\?\C:\myworld\private"   is   seen   as  "C:\myworld\private",   and   "\\?\UNC\tom_1\hotstuff\coolapps"   is   seen   as   "\\tom_1\hotstuff\coolapps".

1.遍历所有串口源码:

OnInitDialog初始化窗口

 

[cpp]  view plain copy
  1. BOOL CDetectComDlg::OnInitDialog()  
  2.  
  3.     CDialog::OnInitDialog();  
  4.   
  5.     ASSERT((IDM_ABOUTBOX 0xFFF0) == IDM_ABOUTBOX);  
  6.     ASSERT(IDM_ABOUTBOX 0xF000);  
  7.   
  8.     CMenu* pSysMenu GetSystemMenu(FALSE);  
  9.     if (pSysMenu != NULL)  
  10.      
  11.         CString strAboutMenu;  
  12.         strAboutMenu.LoadString(IDS_ABOUTBOX);  
  13.         if (!strAboutMenu.IsEmpty())  
  14.          
  15.             pSysMenu->AppendMenu(MF_SEPARATOR);  
  16.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);  
  17.          
  18.      
  19.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  20.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  21.   
  22.     DWORD sStyle m_ListShow.GetExtendedStyle();  
  23.     sStyle |= LVS_EX_GRIDLINES;  
  24.     sStyle |= LVS_EX_FULLROWSELECT;  
  25.     m_ListShow.SetExtendedStyle(sStyle);  
  26.     m_ListShow.InsertColumn(0,_T("索引"),LVCFMT_LEFT,100);  
  27.     m_ListShow.InsertColumn(1,_T("串口号"),LVCFMT_LEFT,100);  
  28.   
  29.     TraversalCom(); //遍历Com口  
  30.     return TRUE;   
  31.  
TraversalCom函数

 

 

[cpp]  view plain copy
  1. void CDetectComDlg::TraversalCom(void 
  2.  
  3.     EnumerateSerialPorts(ports,portse,portsu);  
  4.     unsigned short Counter;  
  5.     unsigned short Setcom;  
  6.     CString str;  
  7.   
  8.     //获取可用串口个数  
  9.     Counter portse.GetSize();   
  10.     //如果个数大于0  
  11.     if(Counter 0)  
  12.      
  13.         //初始化串口列表框  
  14.         for(int i=0; i
  15.          
  16.             Setcom portse.ElementAt(i);  
  17.             str.Format("%d",i);  
  18.             m_ListShow.InsertItem(i,str);  
  19.             str.Format(_T("COM%d "),Setcom);  
  20.             m_ListShow.SetItemText(i,1,str);  
  21.          
  22.      
  23.  
EnumerateSerialPorts函数

 

 

[cpp]  view plain copy
  1. void CDetectComDlg::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.     for (int i=1; i<256; i++)  
  11.      
  12.         //Form the Raw device name  
  13.         CString sPort;  
  14.         sPort.Format(_T("\\\\.\\COM%d"), i);  
  15.   
  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.   
  23.             if (dwError == ERROR_ACCESS_DENIED)  
  24.              
  25.                 bSuccess TRUE;  
  26.                 portsu.Add(i);       //已占用的串口  
  27.              
  28.          
  29.         else  
  30.          
  31.             //The port was opened successfully  
  32.             bSuccess TRUE;  
  33.             portse.Add(i);      可用的串口  
  34.             //Don't forget to close the port, since we are going to do nothing with it anyway  
  35.             CloseHandle(hPort);  
  36.          
  37.   
  38.         //Add the port number to the array which will be returned  
  39.         if (bSuccess)  
  40.             ports.Add(i);   //所有存在的串口  
  41.      
  42.  

这时再刚登陆窗口时便可罗列出可用串口。

 

2.检测串口的热插拔

这里主要利用Cwnd的ON_WM_DEVICECHANGE消息来处理。
ON_WM_DEVICECHANGE消息在VS是通过手动添加的

注意:此消息只有顶层窗口可以捕获到
因此,首先得手动添加ON_WM_DEVICECHANGE消息:
第一步:在消息映射BEGIN_MESSAGE_MAP(Ctbox_debug_viewDlg, CDialogEx)中添加:

 

[cpp]  view plain copy
  1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);  

第二步:在cpp文件中添加函数声明

 

 

[cpp]  view plain copy
  1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);  

第三步:实现
[cpp]  view plain copy
  1. BOOL CDetectComDlg::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.         ReDetectCom();//刷新列表框的内容  
  9.         break 
  10.   
  11.     default 
  12.         break 
  13.      
  14.     return TRUE;  
  15.  
ReDetectCom的内容

 

 

[cpp]  view plain copy
  1. void CDetectComDlg::ReDetectCom(void 
  2.  
  3.     m_ListShow.DeleteAllItems();  
  4.     TraversalCom();  
  5.  

第四步包含头文件

 

由于DEV_BROADCAST_DEVICEINTERFACE,DBT_DEVICEREMOVECOMPLETE,DBT_DEVICEARRIVAL这几个东东在头文件Dbt.h中定义的,所以包含Dbt.h头文件

 

[cpp]  view plain copy
  1. #include   

至此遍历方法实现检测串口的方法已经实现,在下一篇中将介绍如何读取注册表实现串口的自动检测

 

源码:遍历方法的实现:遍历方法的实现



VC++ 动态检测串口的热插拔(二)通过注册表实现


在上一篇文章中讲述了如何通过循环遍历的方法获取可用串口,可是这样的方法过于暴力,难免会想有没有其他的办法那,嘿嘿,那是肯定会有的,不管什么问题,解决问题的方法永远都不止一种。下面讲述如何通过注册表来获取可用串口。

大家都知道,通过设备管理器我们可以看到可用串口号的列表,windows肯定有自己管理各种设备的方法,那就是大家所熟悉的注册表,注册表中记录各种设备信息以及其他重要信息。在HKEY_LOCAL_MACHINE下逐级展开到Hardware\\DeviceMap\\SerialComm,这里记录的就是串口信息。只要通过简单的注册表读取操作我们就可以得到串口列表。

这里将展示给大家,通过注册表读取,并将结果展示到列表框中的例子。

1遍历串口源码如下:

OnInitDialog中如下:

 

[cpp]  view plain copy
  1. BOOL CDetectComDlg::OnInitDialog()  
  2.  
  3.     CDialog::OnInitDialog();  
  4.   
  5.     ASSERT((IDM_ABOUTBOX 0xFFF0) == IDM_ABOUTBOX);  
  6.     ASSERT(IDM_ABOUTBOX 0xF000);  
  7.   
  8.     CMenu* pSysMenu GetSystemMenu(FALSE);  
  9.     if (pSysMenu != NULL)  
  10.      
  11.         CString strAboutMenu;  
  12.         strAboutMenu.LoadString(IDS_ABOUTBOX);  
  13.         if (!strAboutMenu.IsEmpty())  
  14.          
  15.             pSysMenu->AppendMenu(MF_SEPARATOR);  
  16.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);  
  17.          
  18.      
  19.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  20.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  21.   
  22.     DWORD sStyle m_ListShow.GetExtendedStyle();  
  23.     sStyle |= LVS_EX_GRIDLINES;  
  24.     sStyle |= LVS_EX_FULLROWSELECT;  
  25.     m_ListShow.SetExtendedStyle(sStyle);  
  26.     m_ListShow.InsertColumn(0,_T("索引"),LVCFMT_LEFT,100);  
  27.     m_ListShow.InsertColumn(1,_T("串口号"),LVCFMT_LEFT,100);  
  28.     TraversalCom();  
  29.     return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE  
  30.  

TraversalCom()函数如下:

 

 

[html]  view plain copy
  1. void CDetectComDlg::TraversalCom()  
  2.  
  3.     HKEY   hKey;  
  4.   
  5.     if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Hardware\\DeviceMap\\SerialComm"), NULL, KEY_READ, &hKey)==ERROR_SUCCESS)  
  6.      
  7.         TCHAR       szPortName[256], szComName[256];  
  8.         DWORD       dwLong, dwSize;  
  9.         int         nCount  0 
  10.         while(true)  
  11.          
  12.             dwLong  dwSize    256;  
  13.             if(RegEnumValue(hKey, nCount, szPortName, &dwLong, NULL, NULL, (PUCHAR)szComName, &dwSize)==ERROR_NO_MORE_ITEMS)  
  14.                 break;  
  15.             CString str;  
  16.             str.Format("%d",nCount);  
  17.             m_ListShow.InsertItem(nCount,str);  
  18.             str.Format(_T("%s "),szComName);  
  19.             m_ListShow.SetItemText(nCount,1,str);  
  20.             nCount++;  
  21.          
  22.         RegCloseKey(hKey);  
  23.           
  24.      
  25.  

这时再刚登陆窗口时便可罗列出可用串口。

 

 

2.检测串口的热插拔

这里主要利用Cwnd的ON_WM_DEVICECHANGE消息来处理。
ON_WM_DEVICECHANGE消息在VS是通过手动添加的

注意:此消息只有顶层窗口可以捕获到
因此,首先得手动添加ON_WM_DEVICECHANGE消息:
第一步:在消息映射BEGIN_MESSAGE_MAP(Ctbox_debug_viewDlg, CDialogEx)中添加:

[cpp]  view plain copy
  1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);  

第二步:在cpp文件中添加函数声明
[cpp]  view plain copy
  1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);  
第三步:实现

 

[html]  view plain copy
  1. BOOL CDetectComDlg::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.         ReDetectCom();//刷新列表框的内容  
  9.         break;  
  10.   
  11.     default:  
  12.         break;  
  13.      
  14.     return TRUE;  
  15.  

RefreshCom的内容

 

 

[cpp]  view plain copy
  1. void CDetectComDlg::RefreshCom(void 
  2.  
  3.     m_ListShow.DeleteAllItems();  
  4.     TraversalCom();  
  5.  
至此,通过注册表的方法便已实现。

 

源码:通过注册表实现

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值