通过编写串口助手工具学习MFC过程

因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉。这次通过做一个串口助手再次熟悉一下MFC,并做了一下记录,以便方便以后查阅。做的过程中多是遇到问题直接百度和谷歌搜索来的,所以很多都是不求甚解,知其然不知其所以然。另外做此工具只是为了熟悉了解,许多功能还没有完善!(开发工具VS2008)

(九)自动识别串口的方法

网上找了一下,找到两个介绍的较详细的,可用的方法,分别用的是“查找windows注册表”和“枚举设备”

一、windows注册表实现 自动识别串口

此方法只能获得端口号不能获取详细信息,和手动打开注册表查看是一样的,获得的名字就是COM1和COM2没有具体详细的信息。

实现Windows系统下自动识别串口需要调用三个Windows API函数,它们是:

1. 主要用于打开注册表串口项

LONG RegOpenKeyEx(
HKEY hKey,           //主键,即串口信息存放的文件夹
LPCTSTR lpSubKey,      //子键,串口所在的具体文件夹
DWORD ulOptions,       //保留值,不用管,必须设置为0
REGSAM samDesired,     //访问权限
PHKEY phkResult        //返回的串口句柄,以下两个函数使用
);

2、主要用于获得在当前串口注册表中有多少个串口

LONG RegQueryInfoKey(
HKEY hKey,              //RegOpenKeyEx的五个参数返回的子键句柄
LPTSTR lpClass,           //NULL
LPDWORD lpcClass,         //NULL
LPDWORD lpReserved,       //NULL
LPDWORD lpcSubKeys,       //子键的数量
LPDWORD lpcMaxSubKeyLen,    //最大子键的长度
LPDWORD lpcMaxClassLen,     //NULL
LPDWORD lpcValues,        //串口的数量
LPDWORD lpcMaxValueNameLen, //最大值名的长度
LPDWORD lpcMaxValueLen,     //最大串口的长度
LPDWORD lpcbSecurityDescriptor, //NULL
PFILETIME lpftLastWriteTime   //NULL
);

3、主要用于获得串口名,如"COM3"等

LONG RegEnumValue(
HKEY hKey,              //串口子键句柄
DWORD dwIndex,         //在注册表中的索引
LPTSTR lpValueName,        //值名
LPDWORD lpcValueName,  //值名的长度
LPDWORD lpReserved,        //NULL
LPDWORD lpType,             //串口的数据类型
LPBYTE lpData,          //串口名
LPDWORD lpcbData           //串口名的长度
);

自动识别串口的实现:

struct UartInfo
{
DWORD UartNum;
WCHAR UartName[];
};
 
//获取串口列表
BOOL EnumComs(struct UartInfo **UartCom, LPDWORD UartComNumber, CnuprogDlg *pMainDlg)
{
//LPCTSTR 即const char * *UartComNumber = ;
HKEY hNewKey;
LONG lResult=RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", , KEY_ALL_ACCESS, &hNewKey); if(lResult != ERROR_SUCCESS) 
{   
pMainDlg->AddToInfOut(_T("打开COM注册表失败!!!"),,);
return FALSE;
  
}
else
{
pMainDlg->AddToInfOut(_T("打开COM注册表成功!!!"),,);
} //DWORD即unsigned long
DWORD ValuesNumber;
DWORD MaxValueNameLen;
DWORD MaxValueLen;
CString str;
//检索指定的子键下有多少个值项
lResult = RegQueryInfoKey(
hNewKey,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&ValuesNumber,
&MaxValueNameLen,
&MaxValueLen,
NULL,
NULL
);
if(lResult != ERROR_SUCCESS)
{
RegCloseKey(hNewKey);
//pMainDlg->AddToInfOut(_T("检索连接在PC上的串口数量失败!!!"),1,1);
return FALSE;
}
else
{
// str.Format(_T("连接在PC上的串口数量是:%ld"), ValuesNumber);
// pMainDlg->AddToInfOut(str,1,1);
*UartCom =(struct UartInfo *)malloc( ValuesNumber * sizeof(struct UartInfo));
}
 
DWORD index;
DWORD uartindex = ;
//CHAR  ValueName[MAX_VALUE_NAME];
WCHAR  ValueName[];
//DWORD ValueNameSize = MAX_VALUE_NAME;
DWORD ValueNameSize;
DWORD DataType;
BYTE DataBuffer[];
DWORD DataLen = ;
 
//LPTSTR 即 char *, LPBYTE即 char *
//检索每个值项,获取值名,数据类型,数据
for(index = ; index < ValuesNumber; index++)
{
memset(ValueName, , sizeof(ValueName));
memset(DataBuffer, , sizeof(DataBuffer));
ValueNameSize = ;
DataLen = ;
lResult = RegEnumValue(hNewKey,index,ValueName,&ValueNameSize,NULL, &DataType, DataBuffer, &DataLen);
if (lResult == ERROR_SUCCESS )
{
switch(DataType)
{
case REG_NONE:
          // No value type               (0)
break;
case REG_SZ:
           //Unicode nul terminated string (1)
break;
case REG_EXPAND_SZ:
    // Unicode nul terminated string (2)
break;
case REG_BINARY:
       // Free form binary              (3)
break;
case REG_DWORD:
        // 32-bit number                (4)
break;
case REG_MULTI_SZ:
      // Multiple Unicode strings    (7)
break;
default:
break;
}
memcpy((*UartCom)[uartindex].UartName, DataBuffer, DataLen);
(*UartCom)[uartindex].UartNum = ValuesNumber;
uartindex++;
}
else if(lResult == ERROR_NO_MORE_ITEMS)
{
//pMainDlg->AddToInfOut(_T("检索串口完毕!!!"),1,1);
}
else
{
DWORD dw = GetLastError();
// str.Format(_T("检索串口出错: 0x%08x"), dw);
// pMainDlg->AddToInfOut(str,1,1);
return FALSE;
}
}
 
*UartComNumber = uartindex;
 
return TRUE;
}

结构体和函数

在主函数中的调用:

DWORD UartComNumber = ;
struct UartInfo *pUartCom;
BOOL bResult;
bResult = EnumComs(&pUartCom, &UartComNumber, pMainDlg);
DWORD index;
 
if(bResult)
{
pMainDlg->AddToInfOut(_T("获取串口列表成功"),,);
}
else
{
pMainDlg->AddToInfOut(_T("获取串口列表失败"),,);
}
 
for( index= ; index < UartComNumber; index++)
{  
pMainDlg->m_ComboBox.AddString(pUartCom[index].UartName);
}

主函数调用

二、使用玫举方法,自动识别串口

这个方法可以得到更详细的信息

实现方法如下:

BOOL  findCom()
{
HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
SP_DEVINFO_DATA spdata = {};
GUID guid = GUID_DEVINTERFACE_COMPORT; // empty();
// 得到所有设备HDEVINFO
hDevInfo = SetupDiGetClassDevs(&guid, , , DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if(hDevInfo == INVALID_HANDLE_VALUE){
return FALSE;
} spdata.cbSize = sizeof(spdata);
// 循环列举
for(int i=; SetupDiEnumDeviceInfo(hDevInfo, i, &spdata); i++){
char buff[] = {};
// 获取详细信息
if(SetupDiGetDeviceRegistryProperty(hDevInfo, &spdata, SPDRP_FRIENDLYNAME, NULL,
PBYTE(buff), _countof(buff), NULL))
{
printf("buff = %s \n",buff);
// Prolific com port (COMxx)
char* p = strstr(buff, "(COM");
if(p){
int id = atoi(p + );
//if(p != buff) *(p-1) = '\0';
//add(c_comport(id, buff));
}
}
}
// // 释放
SetupDiDestroyDeviceInfoList(hDevInfo); return TRUE;
}

findCom()

整个获取的buff的第一个COM是串口的名字(串口号),整个获取的buff就是COM的详细信息。Buff获取的信息为 ELTIMA Virtual Serial Port (COM1->COM2),所以串口名字是 COM1。

此方法主要是引自下面这个博文:http://blog.csdn.net/itcastcpp/article/details/7078719/

基于Visual C++之Windows核心编程代码分析(1)实现设备管理器枚举设备

我们进行Windows编程的时候,有些时候需要枚举设备,例如光盘,光驱,硬盘等等,

我们如何实现功能呢,请见代码分析

#include <windows.h>  
#include <setupapi.h>  
#include <stdio.h>  
#include <devguid.h>  
#include <regstr.h>  
/* 函数声明 */  
BOOL EnumPresentDevice( const GUID * InterfaceClassGuid );  
BOOL EnumAllDevice();  
/************************************* 
* BOOL EnumClassDevice( const GUID * InterfaceClassGuid ) 
* 功能    根据类型列举当前存在的设备 
* 参数    InterfaceClassGuid,所需列举设备接口类的GUID 
**************************************/  
BOOL EnumClassDevice( const GUID * InterfaceClassGuid )  
  
{  
    HDEVINFO DeviceInfoSet;  
    HDEVINFO NewDeviceInfoSet;  
  
    SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;  
    PSP_DEVICE_INTERFACE_DETAIL_DATA lpDeviceInterfaceDetailData;  
  
    DWORD dwBufferSize = ;  
    DWORD i;  
    // 创建空设备信息列表  
    DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL);  
  
    if(DeviceInfoSet == INVALID_HANDLE_VALUE)   
    {  
        printf("CreateDeviceInfoList failed: %d\n", GetLastError());  
        return ;  
    }  
  
    // 根据接口类型获得新的设备信息列表  
  
    NewDeviceInfoSet = SetupDiGetClassDevsEx(  
        InterfaceClassGuid,  
        NULL,  
        NULL,  
        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE,  
        DeviceInfoSet,// 之前创建的设备信息列表  
        NULL,  
        NULL  
        );  
    if(NewDeviceInfoSet == INVALID_HANDLE_VALUE)  
    {  
        printf( "SetupDiGetClassDevsEx failed: %d\n", GetLastError() );  
        return ;  
    }  
    // 设置 SP_DEVICE_INTERFACE_DATA 大小  
    DeviceInterfaceData.cbSize   
        = sizeof(SP_DEVICE_INTERFACE_DATA);  
  
    for (i=; ;i++)  
    {  
        // 列举接口信息  
        BOOL bResult = SetupDiEnumDeviceInterfaces(  
            NewDeviceInfoSet,  
            NULL,  
            InterfaceClassGuid,  
            i,  
            &DeviceInterfaceData  
            );  
        if(!bResult)  
        {  
            if ( GetLastError()!=NO_ERROR &&  
                GetLastError()!=ERROR_NO_MORE_ITEMS )  
            {  
                printf("ERROR: (%d)",GetLastError());  
                return FALSE;  
            }  
            break;  
        }  
        else  
        {  
            // 为PSP_DEVICE_INTERFACE_DETAIL_DATA结构分配内存,填充  
            lpDeviceInterfaceDetailData = HeapAlloc(  
                GetProcessHeap(), ,  
                sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA));  
            lpDeviceInterfaceDetailData->cbSize   
                = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);  
            dwBufferSize = lpDeviceInterfaceDetailData->cbSize;  
            // 获得接口详细信息  
            while(!SetupDiGetDeviceInterfaceDetail(  
                NewDeviceInfoSet,  
                &DeviceInterfaceData,  
                lpDeviceInterfaceDetailData,  
                dwBufferSize,  
                &dwBufferSize,  
                NULL))  
            {  
                // 如果内存空间不足,再次分配,直到可以成功调用  
                if(ERROR_INSUFFICIENT_BUFFER==GetLastError())  
                {  
                    lpDeviceInterfaceDetailData = HeapReAlloc(  
                        GetProcessHeap(), ,   
                        lpDeviceInterfaceDetailData, dwBufferSize);  
                    lpDeviceInterfaceDetailData->cbSize   
                        = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);  
                }                 
            }  
            // 显示信息  
            printf("DevicePath: %s\n",lpDeviceInterfaceDetailData->DevicePath);  
            // lpDeviceInterfaceDetailData->DevicePath可作为CreateFile的参数,进行IO控制  
              
            // 释放内存  
            HeapFree(GetProcessHeap(),,lpDeviceInterfaceDetailData);  
        }  
    }  
    SetupDiDestroyDeviceInfoList(DeviceInfoSet);  
    return TRUE;  
}  
/************************************* 
* BOOL EnumAllDevice( ) 
* 功能    列举当前存在的设备 
* 返回值   是否成功 
**************************************/  
BOOL EnumAllDevice()  
{  
    HDEVINFO hDevInfo;  
    SP_DEVINFO_DATA DeviceInfoData;  
    DWORD i;  
  
    printf("Displaying the Installed Devices\n\n");  
  
    // 得到所有设备 HDEVINFO   
    hDevInfo = SetupDiGetClassDevs(NULL,  
        , // 无类型  
        , // 无回调函数  
        DIGCF_PRESENT | DIGCF_ALLCLASSES );  
    if (hDevInfo == INVALID_HANDLE_VALUE)  
    {  
        return FALSE;  
    }  
    // 循环列举  
    DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);  
    for (i=;SetupDiEnumDeviceInfo(hDevInfo,i,  
        &DeviceInfoData);i++)  
    {  
        DWORD DataT;  
        LPTSTR buffer = NULL;  
        DWORD buffersize = ;  
  
        // 获取详细信息  
        while (!SetupDiGetDeviceRegistryProperty(  
            hDevInfo,  
            &DeviceInfoData,  
            SPDRP_DEVICEDESC,  
            &DataT,  
            (PBYTE)buffer,  
            buffersize,  
            &buffersize))  
        {  
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)  
            {  
                // 内存不足  
                if (buffer) HeapFree(GetProcessHeap(), , buffer);  
                buffer = (LPTSTR)HeapAlloc(GetProcessHeap(), ,  buffersize);  
            }  
            else  
                break;  
        }  
// 输出  
        printf("GUID:{%.8X-%.4X-%.4X--%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X} "  
            "Device: %s\n",  
            DeviceInfoData.ClassGuid.Data1,  
            DeviceInfoData.ClassGuid.Data2,  
            DeviceInfoData.ClassGuid.Data3,  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],  
            DeviceInfoData.ClassGuid.Data4[],buffer);  
  
        if (buffer) HeapFree(GetProcessHeap(), , buffer);  
    }  
  
    if ( GetLastError()!=NO_ERROR &&  
        GetLastError()!=ERROR_NO_MORE_ITEMS )  
    {  
        return FALSE;  
    }  
    //  释放  
    SetupDiDestroyDeviceInfoList(hDevInfo);  
    return TRUE;  
}  
  
int main( int argc, char *argv[ ], char *envp[ ] )  
{  
    // 列举所有设备  
    printf("Enumerating All Device\n\n");  
    EnumAllDevice();  
    // 列举磁盘分卷驱动器设备  
    printf("\n\nEnumerating Present Volume \n\n");  
    EnumClassDevice(&GUID_DEVINTERFACE_VOLUME);  
    return ;  

通过编写串口助手工具学习MFC过程——(九)自动识别串口的方法的更多相关文章

  1. 通过编写串口助手工具学习MFC过程--(十一)弹出模态型对话框

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  2. 通过编写串口助手工具学习MFC过程——(十)UpdateData()用法和编辑框的赋值、取值

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  3. 通过编写串口助手工具学习MFC过程——(八)遇到的一些问题

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  4. 通过编写串口助手工具学习MFC过程——(六)添加Edit编辑框控件

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  5. 通过编写串口助手工具学习MFC过程——(七)添加Tab Control控件

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  6. 通过编写串口助手工具学习MFC过程——(五)添加CheckBox复选框

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  7. 通过编写串口助手工具学习MFC过程——(四)添加ComboBox组合框

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  8. 通过编写串口助手工具学习MFC过程——(三)Unicode字符集的宽字符和多字节字符转换

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

  9. 通过编写串口助手工具学习MFC过程——(二)通过“打开串口”按钮了解基本操作

    通过编写串口助手工具学习MFC过程 因为以前也做过几次MFC的编程,每次都是项目完成时,MFC基本操作清楚了,但是过好长时间不再接触MFC的项目,再次做MFC的项目时,又要从头开始熟悉.这次通过做一个 ...

随机推荐

  1. Codeforces 939E Maximize ( 三分 || 二分 )

    题意 : 给出两个操作,① 往一个序列集合(初始为空)里面不降序地添加数字.② 找出当前序列集合的一个子集使得 (子集的最大元素) - (子集的平均数) 最大并且输出这个最大差值 分析 :  首先关注 ...

  2. Window7下安装Eclipse C/C++ Developer

    觉得自己写这个是有点脑残的.哈哈. 毕业之后,看的多的是Java.大多忘记C和C++的东西.虽说大学第一门计算机语言就是学的C.惭愧. 重温一下C的知识. 正题: 1.在Windows下安装Eclip ...

  3. 大哥带的Orchel数据库的盲注入bool型

    0X01判断闭合 ?username=SMITH' 错误 ?username=SMITH'' 正确 ?username=SMITH' and ascii(substr((select user fro ...

  4. kubernetes master 更换ip(单节点)

    问题分析 master ip地址变更以后,我们首先应该检查以下内容: /etc/kubernetes/manifests下面的config配置文件,替换里面对应的ip 相关的证书文件 客户端文件 解决 ...

  5. 一台linux机器远程mount另一台linux机器

    本机电脑系统是unbantu,要将另一台linux电脑上的文件mount到本机目录下.mount的原理是网络文件系统,即NFS,本机操作步骤如下 一,安装 nfs-common  : apt inst ...

  6. Git-Runoob:Git 基本操作

    ylbtech-Git-Runoob:Git 基本操作 1.返回顶部 1. Git 基本操作 Git 的工作就是创建和保存你项目的快照及与之后的快照进行对比.本章将对有关创建与提交你的项目快照的命令作 ...

  7. JS - defer 和 async

    普通 <script src="script.js"></script> 没有 defer 或 async,浏览器会立即加载并执行指定的脚本,"立 ...

  8. 分布式任务队列 Celery

    目录 目录 前言 简介 Celery 的应用场景 架构组成 Celery 应用基础 前言 分布式任务队列 Celery,Python 开发者必备技能,结合之前的 RabbitMQ 系列,深入梳理一下 ...

  9. webpack打包文件解析

    /** * 对于没有代码分割的,webpack会打包生成main.js一个大的自执行函数 * 函数参数是一个对象,键值分别是路径和模块的函数 * 函数内部定义了一些方法,包括__webpack_req ...

  10. delphi xe2 64位嵌入汇编问题 https://bbs.csdn.net/topics/390333981

    Function xxx(xxx):xxx;assembler;asm  XOR RAX , RAX  ...end;这样的可以. 0 0 引用 ・ 举报 ・ 管理 5t4rk   回复于 2013- ...