DarioSantarelli.Blog(this);

[C#] How to programmatically find a COM port by friendly name

Posted by dariosantarelli on October 18, 2010

When using the SerialPort.GetPortNames() method, you are querying the current computer for a list of valid serial port names. For example, you can use this method to determine whether “COM1” and “COM2” are valid serial ports in your computer. The port names are obtained from the system registry (if the registry contains stale or otherwise incorrect data then this method will return incorrect data). The limit of this approach is that you get just an array of port names (e.g. { “COM1”,”COM2” … }) and nothing else! If the com ports are physical, there’s no problem but what about virtual ports connected for example through an USB adapter? Well, you can determine if a port is valid but you don’t know exactly which COM number was assigned to your device. So you need more information! In the system Device Manager, you can see the COM port friendly name under the "Ports (COM & LPT)" heading. This means that the right COM port number can be found by using WMI 🙂
A solution to this need comes from WMI Code Creator tool which allows you to generate VBScript, C#, and VB .NET code that uses WMI to complete a management task such as querying for management data, executing a method from a WMI class, or receiving event notifications using WMI.
A suitable WMI query is “SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0”.
Here is a code example showing how to enumerate the information of the COM ports currently available on your system (including the friendly name of course) by executing the query above.

using System.Management;

internal class ProcessConnection {

   public static ConnectionOptions ProcessConnectionOptions()

   {

     ConnectionOptions options = new ConnectionOptions();

     options.Impersonation = ImpersonationLevel.Impersonate;

     options.Authentication = AuthenticationLevel.Default;

     options.EnablePrivileges = true;

     return options;

   }

 

   public static ManagementScope ConnectionScope(string machineName, ConnectionOptions options, string path)

   {

     ManagementScope connectScope = new ManagementScope();

     connectScope.Path = new ManagementPath(@"\\" + machineName + path);

     connectScope.Options = options;

     connectScope.Connect();

     return connectScope;

   }

}

 

public class COMPortInfo

{

   public string Name { get; set; }

   public string Description { get; set; }

 

   public COMPortInfo() { }     

 

   public static List<COMPortInfo> GetCOMPortsInfo()

   {

     List<COMPortInfo> comPortInfoList = new List<COMPortInfo>();

 

     ConnectionOptions options = ProcessConnection.ProcessConnectionOptions();

     ManagementScope connectionScope = ProcessConnection.ConnectionScope(Environment.MachineName, options, @"\root\CIMV2");

 

     ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");

     ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(connectionScope, objectQuery);

 

     using (comPortSearcher)

     {

       string caption = null;

       foreach (ManagementObject obj in comPortSearcher.Get())

       {

         if (obj != null)

         {

           object captionObj = obj["Caption"];

           if (captionObj != null)

           {

              caption = captionObj.ToString();

              if (caption.Contains("(COM"))

              {

                COMPortInfo comPortInfo = new COMPortInfo();

                comPortInfo.Name = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")",

                                                     string.Empty);

                comPortInfo.Description = caption;

                comPortInfoList.Add(comPortInfo);

              }

           }

         }

       }

     } 

     return comPortInfoList;

   }
}

Finally you can easily get the com port list in this way…

foreach (COMPortInfo comPort in COMPortInfo.GetCOMPortsInfo())

{

  Console.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description));

}

Other solutions?

  • A first alternative is SetupAPI. You can find a complete example here.
  • Secondly, you can try to use DevCon (a Microsoft tool that allows "device management" from the command line): you could use the

    System.Diagnostics.Process class to parse the standard output of the command line “>devcon find =ports”.

36 Responses to “[C#] How to programmatically find a COM port by friendly name”

  1. Karsten said

    Thanks a lot, the best solution I’ve found so far

  2. Harshad said

    Thanks a lot 🙂

  3. Steffen said

    Can not run because:
    Error by ConnectionOptions “could not be found”.
    Is that a Visual Studio 2008 Express Problem or must other usings etc.?
    Thanks for answer.
    Steffen

  4. Stefan said

    Thank you very much for this code. I would like to propose a change on the Query though, as you are only using the Caption field and only Captions containing “(COM”:

    “SELECT Caption FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0 AND Caption like ‘%(COM%'”

    Regards,
    Stefan Hommersom

  5. Alexander Hayman said

    Thanks for the code. This has been extremely helpful.

  6. jitu said

    thank u so much. great work.

  7. Matthias said

    great! just copied the code, added a reference to System.Management and it worked!

  8. Mupeg Sadalbari said

    So frickin cool! Thanks man. I like to build projects that generally incorporate a centralized control computer with one or more microcontrolers attached via virtual serial over usb (arduinos for sensors and motor control, etc). It has been really a pain to start up my control software without knowing exactly what port each of my boards is on and this is very clean solution. Thanks!

  9. Christian said

    Hello there.

    Searched for a while and used and extended your example.

    I had the exact problem where i needed to get the COM Port of an USB to Serial Adapter by the name of the device. I did however, not want to extract the COM number from the string as in your example.
    My solution was as this:

    – Use WHERE Description=”my device as in devicemanager” condition to only select my connected device
    – Store the DeviceID
    – Search registry for HKEY_LOCAL_MACHINE\System\CurrentControlSet\Enum\\Device Parameters\PortName

    Works like a charm and i get the PortNumber directly from the associated Deviceentry without substringing it from the caption.

    • Arie said

      Search registry for(in win7 may be others also) HKEY_LOCAL_MACHINE\DEVICEMAP\SERIALCOMM here you can find the associated USB# com port#

  10. Rick said

    Thank you very much!!!

    This solved my problem figuring out when the user unplugs the USB transmission key and the registry didn’t update properly. Thanks again for sharing your code.

    Rick

  11. Syam said

    what happens or to do if virtual com port is not showing in the device manager, and still the device is attached.

    In fact am using a GSM modem, the modem will work or will be shown in the device manager for some time, and after my communications with the modem, when it gets idle, these com ports are getting removed automatically from the device manager.

    How can i keep them alive continually, or is there any method to reconnect automatically

    If anyone can help on this

  12. gaurav said

    Sir,
    is there any way to do it with out the WMI because it take 40 -50 for WMI query to executed

  13. yemane said

    Thank you Very much ! Working fine for me

  14. Bill said

    Thanks a bunch for writing and posting this. I focus more on embedded designs, and when it came time to connect my gizmo to a PC, it was an unpleasant surprise that it showed up under different COM’s. This worked great.

  15. Deepak said

    Its working…

  16. […] [C#] How to programmatically find a COM port by friendly name « DarioSantarelli.Blog(this);. […]

  17. piyush agarwal said

    hey when i run it and take its exe file to 64bit computer the it not gives any response other wise it work great on 32bit computer. please give me some suggestion to works it on 64 bit pc

  18. JR said

    outstanding example!! Thanks for your time in putting it together!!

  19. Sam said

    Mr. dariosantarelli Great job… very very thankful of you….

  20. niceshot85 said

    Thanks for the code, but I’m getting two errors:

    Error 1 The type or namespace name ‘List’ could not be found (are you missing a using directive or an assembly reference?) (line 30)

    Error 2 The name ‘Environment’ does not exist in the current context (line 74)

    😦

  21. Graham said

    Top stuff.
    Saved me a bunch of time, thank you.

  22. […] would like to thank Dario Santarelli and his blog post for the foundation of this […]

  23. Rock on — thanks! I’ve refactored it to fit my needs — here is what I ended up with… 🙂

    using System;
    using System.Collections.Generic;
    using System.Management; // need to add System.Management to your project references.

    namespace UsbScanConsole
    {
    class Program
    {
    static void Main()
    {
    var comPorts = ComPorts.Get();
    foreach (var port in comPorts)
    {
    Console.WriteLine(“{0}, {1}”, port.PortNumber, port.Description);
    }

    Console.Read();
    }

    ///
    /// Gets the list of devices on COM ports
    ///
    ///
    /// var comPorts = ComPorts.Get();
    /// foreach (var port in comPorts)
    /// {
    /// Console.WriteLine(“{0}, {1}”, port.PortNumber, port.Description);
    /// }
    ///
    public class ComPorts
    {
    public string PortNumber { get; set; }
    public string Description { get; set; }

    public static List Get()
    {
    List list = new List();

    //———————————————————————-
    // Query the WMI for PnP devices – in which we’ll find COM devices
    //———————————————————————-
    ManagementObjectSearcher searcher =
    new ManagementObjectSearcher(“\\root\\CIMV2”,
    “SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0”);

    //———————————————————————-
    // Only extract the items that have COM specifications
    //———————————————————————-
    using (searcher)
    {
    foreach (var item in searcher.Get())
    {
    var managementObject = (ManagementObject) item;
    if (managementObject == null) continue;

    var captionObject = managementObject[“Caption”];
    if (captionObject == null) continue;

    string caption = captionObject.ToString();
    if (!caption.Contains(“(COM”)) continue;

    ComPorts comPortInfo = new ComPorts();
    comPortInfo.PortNumber = caption.Substring(
    caption.LastIndexOf(“(COM”)).Replace(“(“, string.Empty).
    Replace(“)”, string.Empty).Replace(“COM”,string.Empty);
    comPortInfo.Description = caption;

    list.Add(comPortInfo);
    }
    }

    return list;
    }
    }
    }
    }

  24. aymanxoxo said

    you are great man … thank you very very much

  25. Cristopher Díaz said

    Excellent!

  26. Vlad said

    Thank you so much for posting this, you saved me so much trouble!

  27. Ducko said

    Adding my thanks for posting this! I’m using VS 2015 on Win10. I’m new to C# so didn’t realize I had to actually add the System.Management to References in addition to the “using” statement. When I did add the reference it worked.

  28. Muhammad Farhan said

    Excellent work!! Thank you so much for posting this.

  29. Mohammad said

    Thank you! 🙂

  30. John Happy said

    Works great. Using Visual Studio 2015 on a Windows 10 box. Converted to VB using the Telerik Code Converter website (C# to VB). Pasted the class code to a new class item and pasted the ‘foreach’ statement within the Load event on a windows form item. Put the port description list in a listbox without any trouble. It picked up my usb to serial com port without any trouble.

  31. greaatttt. thank you very much bradaaa

  32. […] initial code generated from the tool took me to this link which gave me a detailed industrial code snippet which could be reused in my case with a few […]

  33. It has been really one of the top blogs i have checked out. It was very informative.Looking ahead for more blogs of this in near coming future

  34. Jethro Bryann Alipao said

    Good code! Keep it up, mate!

Leave a reply to Steffen Cancel reply