How to scan for COM ports in C#?

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.


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"]);
       }
}

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:

enter image description here

Tags:

C#

Serial Port