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”.

About these ads

25 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;
    }
    }
    }
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: