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#.
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.
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.
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.
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.
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With