如何在C#中发现已知PID和VID的虚拟COM端口名称

How to discover the virtual COM port name knowing the PID and VID in C#

如果我知道 PID 和 VID,我正在尝试找到查找 COM 端口名称的正确方法。到目前为止,我写了解决方法,但我不认为没有更优雅和正确的方法。顺便说一句(我知道我可以使用 REGEX)。这只是为了测试解决方法。

我知道有很多 space 需要改进,我不要求代码审查

欢迎任何想法:)

namespace ConsoleApplication1
{
    using System;
    using System.Globalization;
    using System.Collections.Generic;
    using System.Management; 
    using System.Reflection;

    class Program
    {
        static void Main(string[] args)
        {
            VCOMDetect VCOMPorts = new VCOMDetect(0x0483, 0xA27D);


            Console.WriteLine("BootPort: {0}", VCOMPorts.BootPort() ?? "Not detected");
            Console.WriteLine("Oscilloscope Port: {0}", VCOMPorts.OscilloscopePort() ?? "Not detected");
            Console.WriteLine("Serial/USB Port: {0}", VCOMPorts.SerialPort() ?? "Not detected");
            Console.WriteLine("Programming Port: {0}", VCOMPorts.ProgPort() ?? "Not detected");

            Console.Read();
        }

    }


    class VCOMDetect
    {

        private const string USB_BOOTLOADER_SERIAL   = "000000000b00";
        private const string USB_OSCILLOSCOPE_SERIAL = "000000000c00";
        private const string USB_VCOM_SERIAL         = "000000000d00";
        private const string USB_PRG_SERIAL          = "000000000e00";

        private List<VCOM_USBDeviceInfo> PortsList;

        public VCOMDetect(UInt16 vid, UInt16 pid)
        {
            PortsList = GetUSBDevices(vid, pid);
        }

        public string BootPort()
        {
            foreach(VCOM_USBDeviceInfo VCOM in PortsList)
            {
                if (VCOM.Serial.ToLower() == USB_BOOTLOADER_SERIAL.ToLower()) return VCOM.COMPort;
            }
            return null;
        }

        public string OscilloscopePort()
        {
            foreach (VCOM_USBDeviceInfo VCOM in PortsList)
            {
                if (VCOM.Serial.ToLower() == USB_OSCILLOSCOPE_SERIAL.ToLower()) return VCOM.COMPort;
            }
            return null;
        }

        public string SerialPort()
        {
            foreach (VCOM_USBDeviceInfo VCOM in PortsList)
            {
                if (VCOM.Serial.ToLower() == USB_VCOM_SERIAL.ToLower()) return VCOM.COMPort;
            }
            return null;
        }

        public string ProgPort()
        {
            foreach (VCOM_USBDeviceInfo VCOM in PortsList)
            {
                if (VCOM.Serial.ToLower() == USB_PRG_SERIAL.ToLower()) return VCOM.COMPort;
            }
            return null;
        }


        private List<VCOM_USBDeviceInfo> GetUSBDevices(UInt16 vid, UInt16 pid)
        {
            List<VCOM_USBDeviceInfo> VCOM_devices = new List<VCOM_USBDeviceInfo>();

            ManagementObjectCollection collection;
            using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
                collection = searcher.Get();

            foreach (var device in collection)
            {
                var USBInfo = new VCOM_USBDeviceInfo((string)device.GetPropertyValue("DeviceID"));

                if (USBInfo.PID == 0 || USBInfo.VID == 0) continue;
                if (USBInfo.PID != pid || USBInfo.VID != vid) continue;

                USBInfo.Caption = (string)device.GetPropertyValue("Caption");
                if (USBInfo.COMPort == "") continue;

                USBInfo.PnpDeviceID = (string)device.GetPropertyValue("PNPDeviceID");
                USBInfo.Description = (string)device.GetPropertyValue("Description");
                VCOM_devices.Add(USBInfo);
            }

            collection.Dispose();
            return VCOM_devices;
        }
    }

    class VCOM_USBDeviceInfo
    {
        private UInt16 _PID, _VID;
        private string _Caption;
        private void _ResetData()
        {
            this.PID = 0;
            this.VID = 0;
            this.COMnumber = -1;
            this.COMPort = "";
            this.Serial = "";
        }

        public VCOM_USBDeviceInfo(string DeviceID)
        {
            int VIDIndex = DeviceID.IndexOf("VID_");
            int PIDIndex = DeviceID.IndexOf("PID_");
            int VIDIndexEnd = -1;
            int PIDIndexEnd = -1;

            string PIDSubstring, VIDSubstring;

            if (PIDIndex == -1 || VIDIndex == -1)
            {
                _ResetData();
            }
            else
            {
                bool result = true;

                PIDSubstring = DeviceID.Substring(PIDIndex + 4);
                VIDSubstring = DeviceID.Substring(VIDIndex + 4);

                PIDIndexEnd = PIDSubstring.IndexOf("\");
                VIDIndexEnd = VIDSubstring.IndexOf("&");

                if(PIDIndexEnd == -1 || VIDIndexEnd == -1)
                {
                    _ResetData();
                }
                else
                {

                    result = result && UInt16.TryParse(PIDSubstring.Substring(0, PIDIndexEnd), NumberStyles.AllowHexSpecifier, null, out _PID) && UInt16.TryParse(VIDSubstring.Substring(0, VIDIndexEnd), NumberStyles.AllowHexSpecifier, null, out _VID);
                    if(!result)
                    {
                        _ResetData();
                    }
                    else
                    {
                        PID = _PID;
                        VID = _VID;
                        Serial = PIDSubstring.Substring(PIDIndexEnd + 1);
                    }
                }

            }

        }

        public string DeviceID { get; set; }
        public string PnpDeviceID { get; set; }
        public string Description { get; set; }
        public string Caption
        {
            get
            {
                return _Caption;
            }
            set
            {
                int COMindex = value.IndexOf("(COM");
                string tmpCOMPort = COMindex == -1 ? "" : value.Substring(COMindex + 1, 4);
                if(COMPort == null || COMPort.Length == 0)
                {
                    COMPort = tmpCOMPort;
                }
                else
                {
                    if(COMPort != tmpCOMPort)
                    {
                        Console.WriteLine("Inconsistent COM port information");
                    }
                }
                _Caption = value;

            }
        }

        public UInt16 PID { get; set; }
        public UInt16 VID { get; set; }
        public string Serial { get; set; }
        public int COMnumber { get; set; }
        public string COMPort { get; set; }
    }

}

它完成了工作 - 但我不喜欢它

其实我觉得你的代码看起来不错。是的,我会使用正则表达式,并且在某些地方可以压缩内容。但是,这些东西无助于提高性能或做任何其他事情。只是,主要是让代码更小。我还假设此应用仅在 Windows 上 运行。

无论如何,这段代码有帮助吗:

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Text.RegularExpressions;

namespace PortNames
{
    class Program
    {
        static List<string> ComPortNames(String VID, String PID)
        {
            RegistryKey rk1 = Registry.LocalMachine;
            RegistryKey rk2 = rk1.OpenSubKey("SYSTEM\CurrentControlSet\Enum");

            String pattern = String.Format("^VID_{0}.PID_{1}", VID, PID);
            Regex _rx = new Regex(pattern, RegexOptions.IgnoreCase);
            List<string> ports = new List<string>();

            foreach (String s3 in rk2.GetSubKeyNames())
            {
                RegistryKey rk3 = rk2.OpenSubKey(s3);
                foreach (String s in rk3.GetSubKeyNames())
                {
                    if (_rx.Match(s).Success)
                    {
                        RegistryKey rk4 = rk3.OpenSubKey(s);
                        foreach (String s2 in rk4.GetSubKeyNames())
                        {
                            RegistryKey rk5 = rk4.OpenSubKey(s2);
                            RegistryKey rk6 = rk5.OpenSubKey("Device Parameters");
                            ports.Add((string)rk6.GetValue("PortName"));
                        }
                    }
                }
            }
            return ports;
        }

        static void Main(string[] args)
        {
            List<string> names = ComPortNames("0403", "6001");
            if (names.Count > 0) foreach (String s in SerialPort.GetPortNames()) { Console.WriteLine(s); }

            Console.ReadLine();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text.RegularExpressions;

namespace PortNames
{
    class Program
    {
        private const string vidPattern = @"VID_([0-9A-F]{4})";
        private const string pidPattern = @"PID_([0-9A-F]{4})";

        struct ComPort // custom struct with our desired values
        {
            public string name;
            public string vid;
            public string pid;
            public string description;
        }

        private static List<ComPort> GetSerialPorts()
        {
            using (var searcher = new ManagementObjectSearcher
                ("SELECT * FROM WIN32_SerialPort"))
            {
                var ports = searcher.Get().Cast<ManagementBaseObject>().ToList();
                return ports.Select(p =>
                {
                    ComPort c = new ComPort();
                    c.name = p.GetPropertyValue("DeviceID").ToString();
                    c.vid = p.GetPropertyValue("PNPDeviceID").ToString();
                    c.description = p.GetPropertyValue("Caption").ToString();

                    Match mVID = Regex.Match(c.vid, vidPattern, RegexOptions.IgnoreCase);
                    Match mPID = Regex.Match(c.vid, pidPattern, RegexOptions.IgnoreCase);

                    if (mVID.Success)
                        c.vid = mVID.Groups[1].Value;
                    if (mPID.Success)
                        c.pid = mPID.Groups[1].Value;

                    return c;

                }).ToList();
            }
        }
        static void Main(string[] args)
        {
            List<ComPort> ports = GetSerialPorts();
            //if we want to find one device
            ComPort com = ports.FindLast(c => c.vid.Equals("0483") && c.pid.Equals("5740"));
            //or if we want to extract all devices with specified values:
            List<ComPort> coms = ports.FindAll(c => c.vid.Equals("0483") && c.pid.Equals("5740"));

            Console.ReadLine();
        }
    }
}