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

后端 未结 8 1044
再見小時候
再見小時候 2020-12-05 08:09

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 Mo

8条回答
  •  萌比男神i
    2020-12-05 08:34

    Based off a combination of answer here is a solution that gets the COM number, VID / PID and friendly name etc.

    Here is some example code for getting the list of connected devices.

    public static class SerialPortUtils
    {
        private static Guid GUID_DEVCLASS_PORTS = new Guid(0x4d36e978u, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18);
    
        private unsafe static bool GetPortRegistryProperty(HDEVINFO classHandle, SP_DEVINFO_DATA* deviceInfo, uint spdrp, out string result)
        {
            DWORD size;
            SetupAPI.SetupDiGetDeviceRegistryPropertyW(classHandle, deviceInfo, spdrp, null, null, 0, &size);
            if (size == 0)
            {
                result = null;
                return false;
            }
    
            var resultBuffer = new byte[(int)size];
            fixed (byte* resultBufferPtr = resultBuffer)
            {
                if (SetupAPI.SetupDiGetDeviceRegistryPropertyW(classHandle, deviceInfo, spdrp, null, resultBufferPtr, size, null))
                {
                    result = Encoding.Unicode.GetString(resultBufferPtr, (int)size - sizeof(char));
                    return true;
                }
                else
                {
                    result = null;
                    return false;
                }
            }
        }
    
        public unsafe static List GetSerialPortDevices()
        {
            var results = new List();
    
            // get present ports handle
            var classHandle = SetupAPI.SetupDiGetClassDevsW(ref GUID_DEVCLASS_PORTS, null, IntPtr.Zero, SetupAPI.DIGCF_PRESENT);
            if (classHandle == Common.INVALID_HANDLE_VALUE || classHandle == HDEVINFO.Zero) throw new Exception("SetupDiGetClassDevsW failed");
    
            // enumerate all ports
            var deviceInfo = new SP_DEVINFO_DATA();
            uint deviceInfoSize = (uint)Marshal.SizeOf();
            deviceInfo.cbSize = deviceInfoSize;
            uint index = 0;
            while (SetupAPI.SetupDiEnumDeviceInfo(classHandle, index, &deviceInfo))
            {
                // get port name
                string portName;
                HKEY regKey = SetupAPI.SetupDiOpenDevRegKey(classHandle, &deviceInfo, SetupAPI.DICS_FLAG_GLOBAL, 0, SetupAPI.DIREG_DEV, WinNT.KEY_READ);
                if (regKey == Common.INVALID_HANDLE_VALUE || regKey == IntPtr.Zero) continue;
                using (var regHandle = new SafeRegistryHandle(regKey, true))
                using (var key = RegistryKey.FromHandle(regHandle))
                {
                    portName = key.GetValue("PortName") as string;
                    if (string.IsNullOrEmpty(portName)) continue;
                }
    
                // get registry values
                if (!GetPortRegistryProperty(classHandle, &deviceInfo, SetupAPI.SPDRP_FRIENDLYNAME, out string friendlyName)) continue;
                if (!GetPortRegistryProperty(classHandle, &deviceInfo, SetupAPI.SPDRP_HARDWAREID, out string hardwareID)) continue;
    
                // add device
                results.Add(new SerialPortDeviceDesc(friendlyName, portName, hardwareID));
    
                // setup for next device
                ++index;
                deviceInfo = new SP_DEVINFO_DATA();
                deviceInfo.cbSize = deviceInfoSize;
            }
    
            // finish
            SetupAPI.SetupDiDestroyDeviceInfoList(classHandle);
            return results;
        }
    }
    

    Here is the SerialPortDeviceDesc class

    public enum SerialPortType
    {
        Unknown,
        COM
    }
    
    public class SerialPortDeviceDesc
    {
        public readonly string friendlyName, portName, hardwareID;
        public readonly string vid, pid;
        public readonly int portNumber = -1;
        public readonly SerialPortType portType = SerialPortType.Unknown;
    
        public SerialPortDeviceDesc(string friendlyName, string portName, string hardwareID)
        {
            this.friendlyName = friendlyName;
            this.portName = portName;
            this.hardwareID = hardwareID;
    
            if (portName.StartsWith("COM") && int.TryParse(portName.Substring("COM".Length), out portNumber))
            {
                portType = SerialPortType.COM;
            }
            else
            {
                portNumber = -1;
            }
    
            var rx = Regex.Match(hardwareID, @"VID_(\w*)&PID_(\w*)", RegexOptions.IgnoreCase);
            if (rx.Success)
            {
                vid = rx.Groups[1].Value;
                pid = rx.Groups[2].Value;
            }
        }
    }
    

提交回复
热议问题