How to scan for COM ports in C#?

前端 未结 3 767
梦谈多话
梦谈多话 2021-02-14 07:19

Does C# provide an effective means of scanning the available COM ports? I would like to have a dropdown list in my application wherein the user can select one of the detected C

相关标签:
3条回答
  • 2021-02-14 07:26

    After few approaches I wrote something like this:

    using System;
    using System.Collections.Generic;
    using System.IO.Ports;
    using System.Linq;
    using System.Management;
    using System.Text.RegularExpressions;
    
    namespace Julo.SerialComm
    {
        public static class SerialPorts
        {
            public static List<SerialPortInfo> GetSerialPortsInfo()
            {
                var retList = new List<SerialPortInfo>();
    
                // System.IO.Ports.SerialPort.GetPortNames() returns port names from Windows Registry
                var registryPortNames = SerialPort.GetPortNames().ToList();
    
                var managementObjectSearcher = new ManagementObjectSearcher(@"SELECT * FROM Win32_PnPEntity");
                var managementObjectCollection = managementObjectSearcher.Get();
    
                foreach (var n in registryPortNames)
                {
                    Console.WriteLine($"Searching for {n}");
    
                    foreach (var p in managementObjectCollection)
                    {
                        if (p["Caption"] != null)
                        {
                            string caption = p["Caption"].ToString();
                            string pnpdevid = p["PnPDeviceId"].ToString();
    
                            if (caption.Contains("(" + n + ")"))
                            {
                                Console.WriteLine("PnPEntity port found: " + caption);
                                var props = p.Properties.Cast<PropertyData>().ToArray();
                                retList.Add(new SerialPortInfo(n, caption, pnpdevid));
                                break;
                            }
                        }
                    }
                }
               
                retList.Sort();
    
                return retList;
            }
    
            public class SerialPortInfo : IComparable
            {
                public SerialPortInfo() {}
    
                public SerialPortInfo(string name, string caption, string pnpdeviceid)
                {
                    Name = name;
                    Caption = caption;
                    PNPDeviceID = pnpdeviceid;
    
                    // build shorter version of PNPDeviceID for better reading
                    // from this: BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0000\7&11A88E8E&0&000000000000_0000000C
                    // to this:  BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0000
                    try
                    {
                        // split by "\" and take 2 elements
                        PNPDeviceIDShort = string.Join($"\\", pnpdeviceid.Split('\\').Take(2)); 
                    }
                    // todo: check if it can be split instead of using Exception
                    catch (Exception)
                    {
                        // or just take 32 characters if split by "\" is impossible
                        PNPDeviceIDShort = pnpdeviceid.Substring(0, 32) + "...";
                    }
                }
    
                /// <summary>
                /// COM port name, "COM3" for example
                /// </summary>
                public string Name { get; }
                /// <summary>
                /// COM port caption from device manager
                /// "Intel(R) Active Management Technology - SOL (COM3)" for example
                /// </summary>
                public string Caption { get; }
                /// <summary>
                /// PNPDeviceID from device manager
                /// "PCI\VEN_8086&DEV_A13D&SUBSYS_224D17AA&REV_31\3&11583659&0&B3" for example
                /// </summary>
                public string PNPDeviceID { get; }
    
                /// <summary>
                /// Shorter version of PNPDeviceID
                /// "PCI\VEN_8086&DEV_A13D&SUBSYS_224D17AA&REV_31" for example
                /// </summary>
                public string PNPDeviceIDShort { get; }
    
                /// <summary>
                /// Comparer required to sort by COM port properly (number as number, not string (COM3 before COM21))
                /// </summary>
                /// <param name="obj"></param>
                /// <returns></returns>
                public int CompareTo(object obj)
                {
                    try
                    {
                        int a, b;
                        string sa, sb;
    
                        sa = Regex.Replace(Name, "[^0-9.]", "");
                        sb = Regex.Replace(((SerialPortInfo)obj).Name, "[^0-9.]", "");
    
                        if (!int.TryParse(sa, out a))
                            throw new ArgumentException(nameof(SerialPortInfo) + ": Cannot convert {0} to int32", sa);
                        if (!int.TryParse(sb, out b))
                            throw new ArgumentException(nameof(SerialPortInfo) + ": Cannot convert {0} to int32", sb);
    
                        return a.CompareTo(b);
                    }
                    catch (Exception)
                    {
                        return 0;
                    }
                }
    
                public override string ToString()
                {
                    return string.Join(Environment.NewLine, Name, Caption, PNPDeviceID);
                }
            }
        }
    }
    

    I'm using it to show detailed serial port lists like this:

    0 讨论(0)
  • 2021-02-14 07:27

    System.IO.Ports is the namespace you want.

    SerialPort.GetPortNames will list all serial COM ports.

    Unfortunately, parallel ports are not supported directly from C#, as they're very infrequently used except in legacy situations. That said, you can list them by querying the following registry key:

    HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\PARALLEL PORTS
    

    See the Microsoft.Win32 namespace for details.

    0 讨论(0)
  • 2021-02-14 07:36

    Use WMI through the System.Management namespace. A quick Google finds this code:

    using System;
    using System.Management;
    
    public class Foo 
    {
        public static void Main() 
        {
           var instances = new ManagementClass("Win32_SerialPort").GetInstances();
           foreach ( ManagementObject port in instances )
           {
               Console.WriteLine("{0}: {1}", port["deviceid"], port["name"]);
           }
    }
    
    0 讨论(0)
提交回复
热议问题