C# 串口获取更详细信息 设备描述、PID、VID

C#提供了标准的serial库,如何获取串口列表不在这里谈论,但并没有提供获取更多串口信息的方法,不能做到获取详细信息 设备描述、PID、VID等,如上图:

不多说,上代码:

    public struct PORT_INFO
    {
        public string port_name;
        public string description;
        public string hardware_id;
    }
   private const short INVALID_HANDLE_VALUE = -1;
    public const uint DIGCF_DEFAULT = 0x00000001;  // only valid with DIGCF_DEVICEINTERFACE
    public const uint DIGCF_PRESENT = 0x00000002;
    public const uint DIGCF_ALLCLASSES = 0x00000004;
    public const uint DIGCF_PROFILE = 0x00000008;
    public const uint DIGCF_DEVICEINTERFACE = 0x00000010;
    private const int MAX_DEV_LEN = 256;//返回值最大长度
    private const int SPDRP_FRIENDLYNAME = (0x0000000C);// FriendlyName (R/W)
    private const int SPDRP_DEVICEDESC = (0x00000000);// DeviceDesc (R/W)
    private const int SPDRP_HARDWAREID = (0x00000001);// HardwareID (R/W)
    private const int DICS_FLAG_GLOBAL = 0x00000001;
    public struct SP_DEVINFO_DATA
    {
        public uint cbSize;
        public Guid ClassGuid;
        public uint DevInst;
        public IntPtr Reserved;
    }
    [DllImport("SetupAPI.dll")]
    public static extern bool SetupDiEnumDeviceInfo(
        IntPtr DeviceInfoSet,
        uint MemberIndex,
        ref SP_DEVINFO_DATA DeviceInfoData
    );
    [DllImport("SetupAPI.dll")]
    public static extern IntPtr SetupDiGetClassDevs(
        ref Guid ClassGuid,
        uint Enumerator,
        IntPtr hwndParent,
        uint Flags
    );
    [DllImport("SetupAPI.dll")]
    private static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
    [DllImport("setupapi.dll")]
    private static extern IntPtr SetupDiOpenDevRegKey(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Scope,
        uint HwProfile,
        uint KeyType,
        uint samDesired
        );
    [DllImport("setupapi.dll")]
    private static extern bool SetupDiGetDeviceRegistryPropertyW(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Property,
        ref uint PropertyRegDataType,
        byte[] PropertyBuffer,
        uint PropertyBufferSize,
        IntPtr RequiredSize
        );
    [DllImport("ADVAPI32.dll", CharSet = CharSet.Unicode, BestFitMapping = false)]
    internal static extern int RegQueryValueEx(IntPtr hKey, string lpValueName,
                int[] lpReserved, ref int lpType, [Out] byte[] lpData,
                ref int lpcbData);

    [DllImport("ADVAPI32.dll", SetLastError = false)]
    internal static extern int RegCloseKey(IntPtr handle);
    public static List<PORT_INFO> list_ports()
    {
        Guid GUID_DEVCLASS_PORTS = new Guid("4d36e978-e325-11ce-bfc1-08002be10318");
        Guid GUID_DEVCLASS_MODEM = new Guid("4d36e96d-e325-11ce-bfc1-08002be10318");
        Guid GUID_DEVINTERFACE_COMPORT = new Guid("86E0D1E0-8089-11D0-9CE4-08003E301F73");
        Guid GUID_DEVINTERFACE_MODEM = new Guid("2c7089aa-2e0e-11d1-b114-00c04fc2aae4");
        List<PORT_INFO> ports = new List<PORT_INFO>();
        Guid[] ClassGuid = new Guid[4];
        ClassGuid[0] = GUID_DEVCLASS_PORTS;
        ClassGuid[1] = GUID_DEVCLASS_MODEM;
        ClassGuid[2] = GUID_DEVINTERFACE_COMPORT;
        ClassGuid[3] = GUID_DEVINTERFACE_MODEM;
        uint[] dwFlag = new uint[4];
        dwFlag[0] = DIGCF_PRESENT;
        dwFlag[1] = DIGCF_PRESENT;
        dwFlag[2] = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
        dwFlag[3] = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE;
        List<string> temp_portname_list = new List<string>();//用于判断是否有重复的
        for (int index = 0; index < ClassGuid.Length; index++)
        {
            IntPtr hDevInfo = (IntPtr)INVALID_HANDLE_VALUE;
            //函数返回一个包含本机上所有被请求的设备信息的设备信息集句柄
            hDevInfo = SetupDiGetClassDevs(ref ClassGuid[index], 0, IntPtr.Zero, dwFlag[index]);
            if (hDevInfo == (IntPtr)INVALID_HANDLE_VALUE)
            {
                return ports;
            }
            SP_DEVINFO_DATA DeviceInfoData = new SP_DEVINFO_DATA();
            DeviceInfoData.cbSize = (uint)Marshal.SizeOf(new SP_DEVINFO_DATA());
            //在64位系统上cbSize 是32 32位系统上是28,如果不对则会读取出错
            DeviceInfoData.DevInst = 0;
            DeviceInfoData.ClassGuid = Guid.Empty;
            DeviceInfoData.Reserved = IntPtr.Zero;
            //枚举设备信息
            uint i = 0;
            while (SetupDiEnumDeviceInfo(hDevInfo, i++, ref DeviceInfoData))
            {
                //Get port name
                const uint DIREG_DEV = 0x00000001;
                const uint KEY_READ = 0x00020019;
                //打开枚举成功的设备注册表句柄hkey,并获取该设备对应的相关信息 DeviceInfoData
                IntPtr hkey = SetupDiOpenDevRegKey(
                    hDevInfo,
                    ref DeviceInfoData,
                    DICS_FLAG_GLOBAL,
                    0,
                    DIREG_DEV,
                    KEY_READ);
                //根据句柄 和关键词获取 portName
                string portName = GetStringValue(hkey, "PortName");
                //关闭注册表句柄
                RegCloseKey(hkey);
                if (portName.Length == 0 || portName.ToString().Contains("LPT")) continue;//并口跳过
                if (temp_portname_list.IndexOf(portName) >= 0) continue;//重复的跳过
                temp_portname_list.Add(portName);
                // Get port friendly name 从DeviceInfoData中获取DeviceName信息
                byte[] DeviceName = new byte[MAX_DEV_LEN];
                uint PropertyRegDataType = 0;
                if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, ref DeviceInfoData, SPDRP_FRIENDLYNAME,
                    ref PropertyRegDataType, DeviceName, MAX_DEV_LEN, IntPtr.Zero))
                {
                    DeviceName = new byte[MAX_DEV_LEN];
                }
                // Get DeviceDsc 从DeviceInfoData中获取DeviceDsc信息
                byte[] DeviceDsc = new byte[MAX_DEV_LEN];
                if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, ref DeviceInfoData, SPDRP_DEVICEDESC,
                    ref PropertyRegDataType, DeviceDsc, MAX_DEV_LEN, IntPtr.Zero))
                {
                    DeviceDsc = new byte[MAX_DEV_LEN];
                }
                // Get hardware ID 从DeviceInfoData中获取 hardware ID 信息
                byte[] hardwareID = new byte[MAX_DEV_LEN];
                if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, ref DeviceInfoData, SPDRP_HARDWAREID,
                    ref PropertyRegDataType, hardwareID, MAX_DEV_LEN, IntPtr.Zero))
                {
                    hardwareID = new byte[MAX_DEV_LEN];
                }
                PORT_INFO temp_port;
                temp_port.port_name = portName.Split('\0').Length > 0 ? portName.Split('\0')[0] : "";
                var str_arry = Encoding.Unicode.GetString(DeviceDsc).Split('\0');
                temp_port.description = str_arry.Length > 0 ? str_arry[0] : "";
                str_arry = Encoding.Unicode.GetString(hardwareID).Split('\0');
                temp_port.hardware_id = str_arry.Length > 0 ? str_arry[0] : "";
                ports.Add(temp_port);
            }
            SetupDiDestroyDeviceInfoList(hDevInfo);//
        }
        return ports;
    }

    public static string GetStringValue(IntPtr hkey, string valName)
    {
        int type = 0;
        int datasize = 0;
        int ret = RegQueryValueEx(hkey, valName, null, ref type, null, ref datasize);
        if (ret == 0)
            if (type == 1)
            {
                byte[] blob = new byte[datasize];
                ret = RegQueryValueEx(hkey, valName, null, ref type, blob, ref datasize);
                UnicodeEncoding unicode = new UnicodeEncoding();
                return unicode.GetString(blob);
            }
        return null;
    }

函数调用了windows steupAPI 里的接口获取了串口列表信息

另外,指定PID、VID获取对应串口的方法:

    /// <summary>
    /// 根据给定的PID VID 搜寻 对应的串口
    /// </summary>
    /// <param name="pid"></param> PID 注意进制,如 0x5656
    /// <param name="vid"></param> VID 注意进制,如 0x5656
    /// <returns></returns> 返回的是符合 PID 和VID 的串口名称列表
    public string[] GetCOMFromPIDVID(int pid, int vid)
    {
        List<PORT_INFO> COM_ports = list_ports();
        string pid_s = pid.ToString("X4");
        string vid_s = vid.ToString("X4");
        ArrayList list = new ArrayList();
        foreach (var port in COM_ports)
        {
            if (port.hardware_id.Contains(pid_s) && port.hardware_id.Contains(vid_s))
            {
                list.Add(port.port_name);
            }
        }
        return (string[])list.ToArray(typeof(string));
    }

完整demo工程

https://download.csdn.net/download/m0_54012127/88487604?spm=1001.2014.3001.5503

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值