C++ C#自动获得特定串口 获得串口列表

121 篇文章 4 订阅
46 篇文章 1 订阅

目的:自动获得特定串口。 

0、C++自动获得特定串口 读设备管理器 计算机管理 串口列表 

 

// PrintDeviceInfo.cpp : 定义控制台应用程序的入口点。
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <Windows.h>
#include <setupapi.h>
#pragma comment(lib, "setupapi.lib")
//获取特定串口号 示例Qualcomm HS-USB Diagnostics 9091 (COM20)
int getSpecialComNum(char *in)
{
	char out[100] = { 0 };
	sscanf_s(in, "Qualcomm HS-USB Diagnostics 9091 (COM%[0-9])", out,sizeof(out)); //不是%d哦
	return atoi(out);
}
//从设备信息中 获取特定串口号  @return <=0无效
int  getSpecialComNumFromDevInfo()
{
	HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
	if (hDevInfo == INVALID_HANDLE_VALUE)
	{
		printf("SetupDiGetClassDevs Err:%d", GetLastError());
		return -2;
	};

	SP_CLASSIMAGELIST_DATA _spImageData = { 0 };
	_spImageData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
	SetupDiGetClassImageList(&_spImageData);

	SP_DEVINFO_DATA spDevInfoData = { 0 };
	spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++)	
	{
		char  szBuf[MAX_PATH] = { 0 };
		int  wImageIdx = 0;
		short  wItem = 0;
		if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &spDevInfoData, SPDRP_CLASS, NULL, (PBYTE)szBuf, MAX_PATH, 0))
		{
			continue;
		};
		if (strcmp(szBuf, "Ports") != 0) //只取端口
		{
			continue;
		}
		printf("Class1:%s\r\n", szBuf);
		if (SetupDiGetClassImageIndex(&_spImageData, &spDevInfoData.ClassGuid, &wImageIdx))
		{
			char  szName[MAX_PATH] = { 0 };
			DWORD  dwRequireSize;
				
			if (!SetupDiGetClassDescription(&spDevInfoData.ClassGuid, (PWSTR)szBuf, MAX_PATH, &dwRequireSize))
			{
				continue;
			};
			wprintf(L"Class:%s\r\n", szBuf);

			if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)szName, MAX_PATH - 1, 0))
			{
				wprintf(L"FriendlyName:%s\r\n\r\n", szName);
				if (int comNum=getSpecialComNum(szName) > 0)
				{
					return comNum;
				}
			}
			else  if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)szName, MAX_PATH - 1, 0))
			{
				wprintf(L"Device:%s\r\n\r\n", szName);
			}
		}	
	}
	SetupDiDestroyClassImageList(&_spImageData);
	return - 1;
}

int  main(int  argc, char* argv[])
{
	printf("Locale is: %s\n", setlocale(LC_ALL, "chs"));
	printf("串口号:%d\n",getSpecialComNumFromDevInfo());
	//PrintDevicesInfo2();
	getchar();
	return  0;
}

1、C++注册表方式

#include <iostream>
#include <windows.h>
//***********************
// 枚举所有的串口,以及名称
//return 特定的串口号 或-1失败 
//***********************
int EnumAllComm()
{
	HKEY hkey;
	int result;
	int i = 0;
	result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Hardware\\DeviceMap\\SerialComm", NULL, KEY_READ, &hkey);
	if (ERROR_SUCCESS == result)   //打开串口注册表   
	{
		do
		{
			TCHAR portName[0x100] = { 0 };//portName是注册表名称(不是设备管理器里的前缀),commName就是值 串口名字COMN
			TCHAR commName[0x100] = {0};
			DWORD dwSize = sizeof(portName) / sizeof(TCHAR);
			DWORD dwLong = dwSize;
			result = RegEnumValue(hkey, i, portName, &dwLong, NULL, NULL, (LPBYTE)commName, &dwSize);
			if (ERROR_NO_MORE_ITEMS == result)	{break;	}  			//   枚举串口				 	
			printf("%d %s %s\n", i, portName, commName); //显示名称及值

			if (strcmp(portName, "\\Device\\QCUSB_COM5_2") == 0) //特定串口
			{
				return atoi(commName + 3);//去掉COM只取号 正常返回
			}
			i++;
		} while (TRUE);
		RegCloseKey(hkey); //关闭注册表
	}
	return -1;//没找到特定串口
}
int main()
{
    std::cout << "Hello World!\n";
	std::cout << "**************************Special COM:"<<EnumAllComm()<<"\n";
	std::cout << "Hello World! end\n";
}

 注册表的key在不同的电脑上是否会变化?

2.C++直接打开试

//默认只找倒数第一个
int getCommNum()
{
	HANDLE hCom;
	int i;	
	BOOL flag;
	char str[100] = {0};
	flag = FALSE;
	for (i = 30; i >= 1; i--)//此程序支持N个串口
	{
		sprintf(str,"\\\\.\\COM%d",i);
		//printf("%s%s",str,"\n"); 
		hCom = CreateFile(str, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
		if (INVALID_HANDLE_VALUE != hCom)
		{//能打开该串口,则添加该串口
			CloseHandle(hCom);
			return i;
		}
	}
	return -1;
}

3、USB VID PID MI +串口前缀

#define MY_USB_PID_VID_F200	_T("VID_05C6&PID_9018")  //\\6&1DC4E91E&3
#define MY_USB_PID_VID_F210	_T("VID_18D1&PID_4001") //\\&MI_046&4592401&0&0004
#define MY_USB_PID_VID_F210_ELSE _T("VID_18D1&PID_4EE8")//这个在adb打开时存在
//获取特定串口号 示例Qualcomm HS-USB Diagnostics 9091 (COM20)
string getSpecialComNum(const char *in)
{
	logger.INFO_F(FUN_LINE+in);
	CString temp(in);
	if (StrStr(temp, "Qualcomm HS-USB Android GPS 9018") == NULL && StrStr(temp, "USB 串行设备") == NULL)
	{
		return "";
	}
	int ret=getContentInBracket(temp);
	if (ret != 0) { return ""; }
	temp.Replace("COM","");
	logger.INFO_F(FUN_LINE +" OK, COM"+ temp.GetBuffer());
	return temp;

	//char out[100] = { 0 };
	//sscanf_s(in, "Qualcomm HS-USB Android GPS 9018 (COM%[0-9])", out, sizeof(out)); //不是%d哦
	//return out;
}
//从设备信息中 获取特定串口号  @return <=0无效
int  getSpecialComNumFromDevInfo()
{
	HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
	if (hDevInfo == INVALID_HANDLE_VALUE)
	{
		printf("SetupDiGetClassDevs Err:%d", GetLastError());
		return -2;
	};

	SP_CLASSIMAGELIST_DATA _spImageData = { 0 };
	_spImageData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
	SetupDiGetClassImageList(&_spImageData);

	SP_DEVINFO_DATA spDevInfoData = { 0 };
	spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++)
	{
		char  szBuf[MAX_PATH] = { 0 };
		int  wImageIdx = 0;
		short  wItem = 0;
		if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &spDevInfoData, SPDRP_CLASS, NULL, (PBYTE)szBuf, MAX_PATH, 0))
		{
			continue;
		};
		if (strcmp(szBuf, "Ports") != 0) //只取端口
		{
			continue;
		}
		printf("Class1:%s\r\n", szBuf);


		// PID_VID 识别 筛选出实际串口
		DWORD nSize = 0;
		TCHAR				szDis[MAX_PATH] = { 0x00 };// 存储设备实例ID
		if (!SetupDiGetDeviceInstanceId(hDevInfo, &spDevInfoData, szDis, sizeof(szDis), &nSize)) { break; }
		// 根据设备信息寻找VID PID一致的设备
		CString strTemp;
		strTemp.Format(_T("%s"), szDis);
		logger.INFO_F(FUN_LINE+ szDis);
		//strTemp.MakeUpper();
		if ((strTemp.Find(MY_USB_PID_VID_F200, 0) == -1)  && (strTemp.Find(MY_USB_PID_VID_F210, 0) == -1)) //没找到
		{
			logger.INFO_F(FUN_LINE+"USB_PID_VID mismatch.");
			continue;
		}
		logger.INFO_F(FUN_LINE+"PID_VID Check OK.");


		if (SetupDiGetClassImageIndex(&_spImageData, &spDevInfoData.ClassGuid, &wImageIdx))
		{
			char  szName[MAX_PATH] = { 0 };
			DWORD  dwRequireSize;

			if (!SetupDiGetClassDescriptionW(&spDevInfoData.ClassGuid, (PWSTR)szBuf, MAX_PATH, &dwRequireSize))
			{
				continue;
			};
			wprintf(L"Class:%s\r\n", szBuf);

			if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &spDevInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)szName, MAX_PATH - 1, 0))
			{
				wprintf(L"FriendlyName:%s\r\n\r\n", szName);
				int comNum = atoi(getSpecialComNum(wideCharToMultiByte((wchar_t *)szName)).c_str()); //根据特殊前缀来识别
				if (comNum > 0)
				{
					return comNum;
				}
				logger.ERROR_F(FUN_LINE+" Com prefix mismatch.");
			}
			else  if (SetupDiGetDeviceRegistryProperty(hDevInfo, &spDevInfoData, SPDRP_DEVICEDESC, NULL, (PBYTE)szName, MAX_PATH - 1, 0))
			{
				wprintf(L"Device:%s\r\n\r\n", szName);
			}
			else
			{
				logger.ERROR_F(FUN_LINE);
			}
		}
		else
		{
			logger.ERROR_F(FUN_LINE);
		}
	}
	SetupDiDestroyClassImageList(&_spImageData);
	logger.ERROR_F(FUN_LINE);
	return -1;
}

//是否插了设备  @return <=0无效
int  isHaveDevice()
{
	HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES);
	if (hDevInfo == INVALID_HANDLE_VALUE)
	{
		printf("SetupDiGetClassDevs Err:%d", GetLastError());
		return -2;
	};

	SP_CLASSIMAGELIST_DATA _spImageData = { 0 };
	_spImageData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
	SetupDiGetClassImageList(&_spImageData);

	SP_DEVINFO_DATA spDevInfoData = { 0 };
	spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++)
	{
		char  szBuf[MAX_PATH] = { 0 };
		int  wImageIdx = 0;
		short  wItem = 0;
		if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &spDevInfoData, SPDRP_CLASS, NULL, (PBYTE)szBuf, MAX_PATH, 0))
		{
			continue;
		};
		if (strcmp(szBuf, "Ports") != 0) //只取端口
		{
			continue;
		}
		printf("Class1:%s\r\n", szBuf);


		// PID_VID 识别 筛选出实际串口
		DWORD nSize = 0;
		TCHAR				szDis[MAX_PATH] = { 0x00 };// 存储设备实例ID
		if (!SetupDiGetDeviceInstanceId(hDevInfo, &spDevInfoData, szDis, sizeof(szDis), &nSize)) { break; }
		// 根据设备信息寻找VID PID一致的设备
		CString strTemp;
		strTemp.Format(_T("%s"), szDis);
		logger.INFO_F(FUN_LINE + szDis);
		//strTemp.MakeUpper();
		if ((strTemp.Find(MY_USB_PID_VID_F200, 0) == -1) && (strTemp.Find(MY_USB_PID_VID_F210, 0) == -1) && (strTemp.Find(MY_USB_PID_VID_F210_ELSE, 0) == -1)) //没找到
		{
			logger.INFO_F(FUN_LINE + "USB_PID_VID mismatch.");
			continue;
		}
		logger.INFO_F(FUN_LINE + "PID_VID Check OK.");
		return 0;
	}
	SetupDiDestroyClassImageList(&_spImageData);
	logger.ERROR_F(FUN_LINE);
	return -1;
}

4、C#自动获得特定串口 枚举【计算机管理】表

 C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;

namespace FT_M20
{
    class MySerialPort
    {
        public static string strConvertToHexStr(string str)
        {
            string strHex = "";
            foreach (byte b in str)
            {
                strHex += String.Format("{0:X2} ", b);
            }
            return strHex;
        }
        public static byte[] hexConvertToByteArray(String str)
        {
            str = str.Replace(" ", "");
            byte[] b = new byte[str.Length / 2];
            for (int i = 0; i < str.Length; i = i + 2)
            {
                b[i / 2] = (byte)Convert.ToInt32(str.Substring(i, 2), 16);   //将十六进制“10”转换为十进制i
            }
            return b;
        }
        /// <summary>
        /// Get the target com num.
        /// </summary>
        /// <returns></returns>
        public static string GetComName()
        {
            string[] strArr = GetHarewareInfo(HardwareEnum.Win32_PnPEntity, "Name");
            foreach (string s in strArr)
            {
                //Quectel USB Serial - 1 Port(COM7)
                if (s.Contains("COM"))
                {
                    if (s.Contains("Quectel USB Serial-1"))
                    {
                        //Log(s);
                        return  return "COM"+ Regex.Match(s, @"\(COM(?<port>\d+)").Groups["port"].Value; //从(COM20)提取串口号
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Get the system devices information with windows api.
        /// </summary>
        /// <param name="hardType">Device type.</param>
        /// <param name="propKey">the property of the device.</param>
        /// <returns></returns>
        public static string[] GetHarewareInfo(HardwareEnum hardType, string propKey)
        {

            List<string> strs = new List<string>();
            try
            {
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from " + hardType))
                {
                    var hardInfos = searcher.Get();
                    foreach (var hardInfo in hardInfos)
                    {
                        if (hardInfo.Properties[propKey].Value != null)
                        {
                            String str = hardInfo.Properties[propKey].Value.ToString();
                            strs.Add(str);
                        }

                    }
                }
                return strs.ToArray();
            }
            catch
            {
                return null;
            }
            finally
            {
                strs = null;
            }
        }//end of func GetHarewareInfo().

        /// <summary>
        /// 枚举win32 api
        /// </summary>
        public enum HardwareEnum
        {
            // 硬件
            Win32_Processor, // CPU 处理器
            Win32_PhysicalMemory, // 物理内存条
            Win32_Keyboard, // 键盘
            Win32_PointingDevice, // 点输入设备,包括鼠标。
            Win32_FloppyDrive, // 软盘驱动器
            Win32_DiskDrive, // 硬盘驱动器
            Win32_CDROMDrive, // 光盘驱动器
            Win32_BaseBoard, // 主板
            Win32_BIOS, // BIOS 芯片
            Win32_ParallelPort, // 并口
            Win32_SerialPort, // 串口
            Win32_SerialPortConfiguration, // 串口配置
            Win32_SoundDevice, // 多媒体设置,一般指声卡。
            Win32_SystemSlot, // 主板插槽 (ISA & PCI & AGP)
            Win32_USBController, // USB 控制器
            Win32_NetworkAdapter, // 网络适配器
            Win32_NetworkAdapterConfiguration, // 网络适配器设置
            Win32_Printer, // 打印机
            Win32_PrinterConfiguration, // 打印机设置
            Win32_PrintJob, // 打印机任务
            Win32_TCPIPPrinterPort, // 打印机端口
            Win32_POTSModem, // MODEM
            Win32_POTSModemToSerialPort, // MODEM 端口
            Win32_DesktopMonitor, // 显示器
            Win32_DisplayConfiguration, // 显卡
            Win32_DisplayControllerConfiguration, // 显卡设置
            Win32_VideoController, // 显卡细节。
            Win32_VideoSettings, // 显卡支持的显示模式。

            // 操作系统
            Win32_TimeZone, // 时区
            Win32_SystemDriver, // 驱动程序
            Win32_DiskPartition, // 磁盘分区
            Win32_LogicalDisk, // 逻辑磁盘
            Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。
            Win32_LogicalMemoryConfiguration, // 逻辑内存配置
            Win32_PageFile, // 系统页文件信息
            Win32_PageFileSetting, // 页文件设置
            Win32_BootConfiguration, // 系统启动配置
            Win32_ComputerSystem, // 计算机信息简要
            Win32_OperatingSystem, // 操作系统信息
            Win32_StartupCommand, // 系统自动启动程序
            Win32_Service, // 系统安装的服务
            Win32_Group, // 系统管理组
            Win32_GroupUser, // 系统组帐号
            Win32_UserAccount, // 用户帐号
            Win32_Process, // 系统进程
            Win32_Thread, // 系统线程
            Win32_Share, // 共享
            Win32_NetworkClient, // 已安装的网络客户端
            Win32_NetworkProtocol, // 已安装的网络协议
            Win32_PnPEntity,//all device
        }
    }
}

或者

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄人软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值