By sebo

2012-07-12 19:03:51 8 Comments

My project requires detection of a specific device when it is connected to USB. The only way I can identify this device is by its description/device name, not the com port. What I have found to perform the correct function is using a WMI query and checking the name property:

ManagementObjectSearcher searcher = new ManagementObjectSearcher("Select * from WIN32_SerialPort");
            foreach (ManagementObject port in searcher.Get())
                deviceName = (string)foundPort.GetPropertyValue("Name"); 

I initially tested this by connecting my phone, and the query returned the phone found on COM3 as expected. Then, I connected another device (a USB to serial converter, which more closely resembles the device I need this project for) and the query simply did not find it. It only finds the phone. This device does, however, show up on port COM4 in Device Manager. To spite me even more, the SerialPort class finds both devices, but it does not provide the information I need to identify the device:

    string[] tempPorts = SerialPort.GetPortNames();

I have read numerous threads on SO and elsewhere and cannot find a satisfactory solution. Could someone please clarify why the WIN32_SerialPort query does not find my other device? Is it not considered a win32 serial port for some reason? And, could someone please point me in the direction of a solution to this problem?


@chapter12 2020-01-24 19:53:18

Alex's answer really helped me out. But I had to adjust my query based on my machine...

I had to query "root\CIMV2", but I had to select all rows from a different table: "SELECT * FROM Win32_SerialPort".

For anyone struggling to figure out how to use WMI or the Management Object Searcher, the WMI Code Creator by Microsoft really just saved me. Using the app, you can query WMI for different information in order to figure out what to put into your Management Object Searcher query.

Link might expire in the future but here it is in 2020:

@Christian Findlay 2018-12-28 07:16:12

Seeing that you want to search by "Name", I think you will need to iterate through all connected devices and query them to get the product name.

Here is code to iterate through WinUSB devices:

  public async Task<IEnumerable<DeviceDefinition>> GetConnectedDeviceDefinitions(uint? vendorId, uint? productId)
        return await Task.Run<IEnumerable<DeviceDefinition>>(() =>
            var deviceDefinitions = new Collection<DeviceDefinition>();
            var spDeviceInterfaceData = new SpDeviceInterfaceData();
            var spDeviceInfoData = new SpDeviceInfoData();
            var spDeviceInterfaceDetailData = new SpDeviceInterfaceDetailData();
            spDeviceInterfaceData.CbSize = (uint)Marshal.SizeOf(spDeviceInterfaceData);
            spDeviceInfoData.CbSize = (uint)Marshal.SizeOf(spDeviceInfoData);

            var guidString = ClassGuid.ToString();
            var copyOfClassGuid = new Guid(guidString);

            var i = APICalls.SetupDiGetClassDevs(ref copyOfClassGuid, IntPtr.Zero, IntPtr.Zero, APICalls.DigcfDeviceinterface | APICalls.DigcfPresent);

            if (IntPtr.Size == 8)
                spDeviceInterfaceDetailData.CbSize = 8;
                spDeviceInterfaceDetailData.CbSize = 4 + Marshal.SystemDefaultCharSize;

            var x = -1;

            while (true)

                var isSuccess = APICalls.SetupDiEnumDeviceInterfaces(i, IntPtr.Zero, ref copyOfClassGuid, (uint)x, ref spDeviceInterfaceData);
                if (!isSuccess)
                    var errorCode = Marshal.GetLastWin32Error();
                    if (errorCode == APICalls.ERROR_NO_MORE_ITEMS)

                    throw new Exception($"Could not enumerate devices. Error code: {errorCode}");

                isSuccess = APICalls.SetupDiGetDeviceInterfaceDetail(i, ref spDeviceInterfaceData, ref spDeviceInterfaceDetailData, 256, out _, ref spDeviceInfoData);
                WindowsDeviceBase.HandleError(isSuccess, "Could not get device interface detail");

                //Note this is a bit nasty but we can filter Vid and Pid this way I think...
                var vendorHex = vendorId?.ToString("X").ToLower().PadLeft(4, '0');
                var productIdHex = productId?.ToString("X").ToLower().PadLeft(4, '0');
                if (vendorId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(vendorHex)) continue;
                if (productId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(productIdHex)) continue;

                var deviceDefinition = GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath);



            return deviceDefinitions;

For each of these devices you can query the device like this:

        var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var defaultInterfaceHandle);
        HandleError(isSuccess, "Couldn't initialize device");

        var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
        isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, EnglishLanguageID, out _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
        HandleError(isSuccess, "Couldn't get device descriptor");

        if (_UsbDeviceDescriptor.iProduct > 0)
            //Get the product name
            var buffer = new byte[256];
            isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.USB_STRING_DESCRIPTOR_TYPE, _UsbDeviceDescriptor.iProduct, 1033, buffer, (uint)buffer.Length, out var transfered);
            HandleError(isSuccess, "Couldn't get product name");

            Product = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));
            Product = Product.Substring(0, Product.Length - 1);

public static partial class WinUsbApiCalls
    public const uint DEVICE_SPEED = 1;
    public const byte USB_ENDPOINT_DIRECTION_MASK = 0X80;
    public const int WritePipeId = 0x80;

    /// <summary>
    /// Not sure where this constant is defined...
    /// </summary>
    public const int DEFAULT_DESCRIPTOR_TYPE = 0x01;
    public const int USB_STRING_DESCRIPTOR_TYPE = 0x03;

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_ControlTransfer(IntPtr InterfaceHandle, WINUSB_SETUP_PACKET SetupPacket, byte[] Buffer, uint BufferLength, ref uint LengthTransferred, IntPtr Overlapped);

    [DllImport("winusb.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool WinUsb_GetAssociatedInterface(SafeFileHandle InterfaceHandle, byte AssociatedInterfaceIndex, out SafeFileHandle AssociatedInterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, ushort LanguageID, out USB_DEVICE_DESCRIPTOR deviceDesc, uint BufferLength, out uint LengthTransfered);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_GetDescriptor(SafeFileHandle InterfaceHandle, byte DescriptorType, byte Index, UInt16 LanguageID, byte[] Buffer, UInt32 BufferLength, out UInt32 LengthTransfered);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_Free(SafeFileHandle InterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_Initialize(SafeFileHandle DeviceHandle, out SafeFileHandle InterfaceHandle);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_QueryDeviceInformation(IntPtr InterfaceHandle, uint InformationType, ref uint BufferLength, ref byte Buffer);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_QueryInterfaceSettings(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, out USB_INTERFACE_DESCRIPTOR UsbAltInterfaceDescriptor);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_QueryPipe(SafeFileHandle InterfaceHandle, byte AlternateInterfaceNumber, byte PipeIndex, out WINUSB_PIPE_INFORMATION PipeInformation);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_ReadPipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_SetPipePolicy(IntPtr InterfaceHandle, byte PipeID, uint PolicyType, uint ValueLength, ref uint Value);

    [DllImport("winusb.dll", SetLastError = true)]
    public static extern bool WinUsb_WritePipe(SafeFileHandle InterfaceHandle, byte PipeID, byte[] Buffer, uint BufferLength, out uint LengthTransferred, IntPtr Overlapped);

@AlexS 2014-05-14 10:24:41

How to list all serial ports:

There are several System-Defined Device Setup Classes available to hardware vendors. Properly written drivers for COM-Ports should use the Ports (COM & LPT ports)-class (guid: 4d36e978-e325-11ce-bfc1-08002be10318). Probably this class is used by the device manager as well.

So you can use the following query to list every serial port you also see in the devicemanager:

ManagementObjectSearcher searcher = new ManagementObjectSearcher(
    "SELECT * FROM Win32_PnPEntity WHERE ClassGuid=\"{4d36e978-e325-11ce-bfc1-08002be10318}\""
foreach (ManagementObject queryObj in searcher.Get())
    // do what you like with the Win32_PnpEntity

See this detailed description of the Win32_PnPEntity-class. You should have everything you need for identifying your device.

For determining the port number I examine the name property and extract it. Until now this works fine, but I don't know if the port number is garanteed to be included in the name. I haven't found any serial port device until now, that doesn't have the port number included in the name.

The above query finds every serial port device, no matter if it is a bluetooth SPP, a FTDI-chip, a port on the mainboard, an extension card or a virtual serial port generated by some modem driver (i.e. Globetrotter GTM66xxW).

To determine the type of connection (bluetooth, usb, etc.) you can examine the deviceid (have a look at the first part of the deviceid). There you can also extract the bt-mac address (be careful with that: the deviceid looks different at least on Windows 7 and Windows XP).

Regarding why some devices are not listed with Win32_SerialPort:

I suspect it depends on the driver implementation, since I have some usb-devices that get their ports listed and some that don't.

@Pithikos 2015-04-02 10:07:56

To get all devices listed use this query instead: "SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM[0-9]%'"

@AlexS 2015-04-02 13:07:37

@Pithikos I already mentioned that in my answer, although I didn't provide any code for that. Since I hadn't found any official statement, that the poort number will always be included in the name, I decided against filtering with LIKE.

@Pithikos 2015-04-02 13:40:30

That's true. I guess the best solution would be a combination of the two.

@AlexS 2015-06-23 07:09:51

@Pithikos Probably the LIKE-condition will be slower than filtering the ClassGuid and the LIKE-condition is not neccessary.

@topshot 2016-10-11 15:39:08

If you had 4 identical scanners attached how could you tell which was which (since Windows often reassigns these virtual COM ports for no reason) if they were used at 4 operations?

@AlexS 2016-10-11 21:01:14

@topshot You could try to distinguish the devices by DeviceId, HardwareId or PnPDeviceId. Just have a look at Win32_PnpEntity linked in my answer.

@Guru Josh 2016-11-04 22:36:17

On the issue of speed, I did 3 separate stopwatch tests on 100,000 iterations. The "Name LIKE '%(COM[0-9]%'" method was actually marginally quicker on all 3 tests than the 'WHERE ClassGuid" method.

@AlexS 2016-11-08 14:25:23

@GuruJosh That's interesting. However I mentioned the guid-approach, since it will list all COM-devices like the device manager does. Devices not listet as COM-Ports in the device manager should also not be returned by this query.

@Lauraducky 2018-02-05 02:05:06

This approach worked much better for me than the WIN32_SerialPort approach, which was VERY slow and listed devices which don't come up on Device Manager. This approach is faster and better.

@Tom 2019-05-18 06:10:18

If you need the com port name like COM4 for opening the port in your program you can extract the com port name via this link…. comPortName=item["Name"].ToString().Substring(start, end - start);

@Jay 2012-07-12 23:44:33

I think i see what you are trying to do, look at this code made using WMICodeCreator ( link to WMICodeCreator ) from this article

//Below is code pasted from WMICodeCreator
    ManagementObjectSearcher searcher =
        new ManagementObjectSearcher("root\\WMI",
        "SELECT * FROM MSSerial_PortName");

    foreach (ManagementObject queryObj in searcher.Get())
        Console.WriteLine("MSSerial_PortName instance");
        Console.WriteLine("InstanceName: {0}", queryObj["InstanceName"]);

        Console.WriteLine("MSSerial_PortName instance");
        Console.WriteLine("PortName: {0}", queryObj["PortName"]);

        //If the serial port's instance name contains USB 
        //it must be a USB to serial device
        if (queryObj["InstanceName"].ToString().Contains("USB"))
            Console.WriteLine(queryObj["PortName"] + " 
            is a USB to SERIAL adapter/converter");
catch (ManagementException e)
    MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);

@sebo 2012-07-13 00:49:58

I had come across this post earlier but the call to Get() with this query failed with some odd errors. I think I got something like "Management not supported" and then after tweaking it I got "Permission Denied". As I said in the comment above, I already found my solution and I did it by using a query to Win32_PnPEntity, and then narrowing down my search by looking for entities whose name property contained "USB Serial Port (COM".

Related Questions

Sponsored Content

12 Answered Questions

[SOLVED] How to find all serial devices (ttyS, ttyUSB, ..) on Linux without opening them?

  • 2010-03-27 16:56:46
  • Thomas Tempelmann
  • 382861 View
  • 111 Score
  • 12 Answer
  • Tags:   linux serial-port

4 Answered Questions

[SOLVED] List of SerialPorts queried using WMI differs from devicemanager?

  • 2013-11-07 16:07:56
  • AlexS
  • 14702 View
  • 10 Score
  • 4 Answer
  • Tags:   wmi

1 Answered Questions

[SOLVED] How to detect two USB devices connected to same USB hub in c#

1 Answered Questions

[SOLVED] Mapping USB device name to com port in C#?

  • 2014-03-18 10:26:07
  • ChewToy
  • 8197 View
  • 3 Score
  • 1 Answer
  • Tags:   c# .net windows usb

2 Answered Questions

Sponsored Content