windowsserial-portdevice-manager

How do I get the friendly name of a COM port in Windows?


I have a GSM modem connected via USB. The modem creates 2 serial ports. The first is automatically attached to the modem, the second shows in Device Manager as "HUAWEI Mobile Connect - 3G PC UI Interface (COM6)"

The second port is used to get vital information from the modem, such as signal quality; to send and receive text messages; and a whole host of other functions.

I am writing an application that will wrap up some of the features provided by the second port. What I need is a sure fire method of identifying which COM port is the spare one. Iterating the ports and checking a response to "ATE0" is not sufficient. The modem's port is usually the lower numbered one, and when a dial up connection is not active, it will respond to "ATE0" the same as the second port.

What I was thinking of doing is iterating the ports and checking their friendly name, as it shows in Device Manager. That way I can link the port in my application to the port labelled "HUAWEI Mobile Connect - 3G PC UI Interface (COM6)" in Device Manager. I've just not found any information yet that will allow me to get that name programmatically.


Solution

  • The information posted by Will Dean was most helpful. This is the code that eventually worked for me. Everything in the PInvoke class was taken verbatim from http://www.pinvoke.net . I did have to change a data type here or there to make it work (like when using an enum instead of a uint) but it should be easy to figure out.

    internal static string GetComPortByDescription(string Description)
    {
        string Result = string.Empty;
        Guid guid = PInvoke.GUID_DEVCLASS_PORTS;
        uint nDevice = 0;
        uint nBytes = 300;
        byte[] retval = new byte[nBytes];
        uint RequiredSize = 0;
        uint PropertyRegDataType = 0;
    
        PInvoke.SP_DEVINFO_DATA devInfoData = new PInvoke.SP_DEVINFO_DATA();
        devInfoData.cbSize = Marshal.SizeOf(typeof(PInvoke.SP_DEVINFO_DATA));
    
        IntPtr hDeviceInfo = PInvoke.SetupDiGetClassDevs(
            ref guid, 
            null, 
            IntPtr.Zero, 
            PInvoke.DIGCF.DIGCF_PRESENT);
    
        while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData))
        {
            if (PInvoke.SetupDiGetDeviceRegistryProperty(
                    hDeviceInfo, 
                    ref devInfoData, 
                    PInvoke.SPDRP.SPDRP_FRIENDLYNAME,
                    out PropertyRegDataType, 
                    retval, 
                    nBytes, 
                    out RequiredSize))
            {
                if (System.Text.Encoding.Unicode.GetString(retval).Substring(0, Description.Length).ToLower() ==
                    Description.ToLower())
                {
                    string tmpstring = System.Text.Encoding.Unicode.GetString(retval);
                    Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM"));
                } // if retval == description
            } // if (PInvoke.SetupDiGetDeviceRegistryProperty( ... SPDRP_FRIENDLYNAME ...
        } // while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData))
    
        PInvoke.SetupDiDestroyDeviceInfoList(hDeviceInfo);
        return Result;
    }
    

    I think the line Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); is a little clumsy, suggestions on how to clean it up would be appreciated.

    Thanks for your help with this matter Will, without you, I'd still be searching google.