Tuesday, October 20, 2009

COM Port Listing in C#

Ok, here is the problem.
How does one get a listing of COM ports in C# ?

The short answer is...

String[] portNames = System.IO.Ports.SerialPort.GetPortNames();

Like most short answers it is correct but not useful.
The resulting list is a series of entries like "COM14". In my application I want the
list to have the long port description like "Prolific USB-to-Serial Bridge (COM16)"

This is tricky. There can be regular serial ports and there can be USB dongles with serial ports.

So what you do instead is first list the ports and make a list of them with both the simple name
and a friendly name that are the same.
Then you look through the plug n play devices for COM ports and get the Name from that.
Like this...


using System.Management;
using System.IO;

Then ...


private void SetupCOMPortInformation()
{
String[] portNames = System.IO.Ports.SerialPort.GetPortNames();
foreach (String s in portNames)
{
// s is like "COM14"
COMPortInfo ci = new COMPortInfo();
ci.portName = s;
ci.friendlyName = s;
ComPortInformation.Add(ci);
}

String[] usbDevs = GetUSBCOMDevices();
foreach (String s in usbDevs)
{
// Name will be like "USB Bridge (COM14)"
int start = s.IndexOf("(COM") + 1;
if (start >= 0)
{
int end = s.IndexOf(")", start + 3);
if (end >= 0)
{
// cname is like "COM14"
String cname = s.Substring(start, end - start);
for (int i = 0; i < ComPortInformation.Count; i++)
{
if (ComPortInformation[i].portName == cname)
{
ComPortInformation[i].friendlyName = s;
}
}
}
}
}
}

static string[] GetUSBCOMDevices()
{
List list = new List();

ManagementObjectSearcher searcher2 = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity");
foreach (ManagementObject mo2 in searcher2.Get())
{
string name = mo2["Name"].ToString();
// Name will have a substring like "(COM12)" in it.
if (name.Contains("(COM"))
{
list.Add(name);
}
}
// remove duplicates, sort alphabetically and convert to array
string[] usbDevices = list.Distinct().OrderBy(s => s).ToArray();
return usbDevices;
}



And we need the list element class...


public class COMPortInfo
{
public String portName;
public String friendlyName;
}



There you are.

Oh, and as extra credit. This code lets you list every possible Management class.



private static void ListAllManagementClasses()
{
string cimRoot = "root\\";
ManagementClass nsClass = new ManagementClass(
new ManagementScope(@"root"),
new ManagementPath("__namespace"),
null);
foreach (ManagementObject ns in nsClass.GetInstances())
{
try
{
Console.WriteLine(cimRoot + ns["Name"].ToString());
ManagementClass newClass = new ManagementClass(cimRoot + ns["Name"].ToString());
EnumerationOptions options = new EnumerationOptions();
options.EnumerateDeep = true; // set to false if only the root classes are needed
ManagementObjectCollection moc = newClass.GetSubclasses(options);
foreach (ManagementObject o in moc)
{
if (o["__SuperClass"] == null)
Console.WriteLine(o["__Class"]);
else
Console.WriteLine("\t" + o["__Class"]);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
}
}


No comments: