Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to scan for COM ports in C#?

Tags:

c#

serial-port

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 COM ports. Creating and populating the dropdown list is not a problem. I just need to know how to scan for the available COM ports using C#.

like image 423
Jim Fell Avatar asked Mar 30 '10 20:03

Jim Fell


People also ask

How do I scan for COM ports?

You'll use the netstat program to identify open ports, and then use the nmap program to get information about the state of a machine's ports on a network. When you're done you'll be able to identify common ports and scan your systems for open ports.

What is a SYN scan?

SYN scanning is a tactic that a malicious hacker can use to determine the state of a communications port without establishing a full connection. This approach, one of the oldest in the repertoire of hackers, is sometimes used to perform a denial-of-service (DoS) attack. SYN scanning is also known as half-open scanning.

Which method of port scanning is the most popular?

Port Scanning Protocols The most commonly used method of TCP scanning is synchronized acknowledged (SYN) scans. SYN scanning involves creating a partial connection to the host on the target port by sending a SYN packet and then evaluating the response from the host.

What is SYN scan in Nmap?

SYN scan is the default and most popular scan option for good reason. It can be performed quickly, scanning thousands of ports per second on a fast network not hampered by intrusive firewalls. SYN scan is relatively unobtrusive and stealthy, since it never completes TCP connections.


2 Answers

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

like image 101
Kamil Avatar answered Sep 30 '22 02:09

Kamil


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.

like image 31
Randolpho Avatar answered Sep 30 '22 00:09

Randolpho