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

后端 未结 8 1038
再見小時候
再見小時候 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条回答
  • 2020-12-05 08:30

    After you determine a Serial Port device is the one you want (by looking at its Friendly Name, by checking its parent device etc.), the proper way to get the port's name would probably be:

    • invoke SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) to get the HKEY to the so-called device key
    • query this registry key for the REG_SZ value "PortName"
    • don't forget to close the HKEY :)

    However, this might require so much interop in C# it's not even funny, so I don't blame you if you keep to the string parsing solution.

    0 讨论(0)
  • 2020-12-05 08:31

    I built a library for serial port control. It can search the friendly name in registry. Here is the link.

    https://github.com/kcwongjoe/serial_port

    std::vector<SerialPortInfo> comPorts = SerialPort::getSerialPortList();
    std::cout << comPorts[0].friendlyName << std::endl;
    
    0 讨论(0)
  • 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<SerialPortDeviceDesc> GetSerialPortDevices()
        {
            var results = new List<SerialPortDeviceDesc>();
    
            // 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<SP_DEVINFO_DATA>();
            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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-05 08:39

    A long time ago I wrote a utility for a client to do just this, but for a GPS rather than a modem.

    I have just looked at it, and bits that jump-out as being possibly helpful are:

        GUID guid = GUID_DEVCLASS_PORTS;
    
    SP_DEVICE_INTERFACE_DATA interfaceData;
    ZeroMemory(&interfaceData, sizeof(interfaceData));
    interfaceData.cbSize = sizeof(interfaceData);
    
    SP_DEVINFO_DATA devInfoData;
    ZeroMemory(&devInfoData, sizeof(devInfoData));
    devInfoData.cbSize = sizeof(devInfoData);
    
    if(SetupDiEnumDeviceInfo(
        hDeviceInfo,            // Our device tree
        nDevice,            // The member to look for
        &devInfoData
        ))
    {
        DWORD regDataType;
    
        BYTE hardwareId[300];
        if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), NULL))
        {
    ...
    

    (You call this bit in a loop with incrementing nDevice)

    and then

    BYTE friendlyName[300];
            if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, friendlyName, sizeof(friendlyName), NULL))
            {
                strFriendlyNames += (LPCTSTR)friendlyName;
                strFriendlyNames += '\n';
            }
    

    which finds the name of the device.

    Hopefully that will help you in the right direction.

    0 讨论(0)
  • 2020-12-05 08:39

    The C++ version based on @Will Dean answer.

    #include <windows.h>
    #include <initguid.h>
    #include <devguid.h>
    #include <setupapi.h>
    
    void enumerateSerialPortsFriendlyNames()
    {
        SP_DEVINFO_DATA devInfoData = {};
        devInfoData.cbSize = sizeof(devInfoData);
    
        // get the tree containing the info for the ports
        HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS,
                                                   0,
                                                   nullptr,
                                                   DIGCF_PRESENT
                                                   );
        if (hDeviceInfo == INVALID_HANDLE_VALUE)
        {
            return;
        }
    
        // iterate over all the devices in the tree
        int nDevice = 0;
        while (SetupDiEnumDeviceInfo(hDeviceInfo,            // Our device tree
                                     nDevice++,            // The member to look for
                                     &devInfoData))
        {
            DWORD regDataType;
            DWORD reqSize = 0;
    
            // find the size required to hold the device info
            SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize);
            BYTE* hardwareId = new BYTE[(reqSize > 1) ? reqSize : 1];
            // now store it in a buffer
            if (SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId) * reqSize, nullptr))
            {
                // find the size required to hold the friendly name
                reqSize = 0;
                SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize);
                BYTE* friendlyName = new BYTE[(reqSize > 1) ? reqSize : 1];
                // now store it in a buffer
                if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, friendlyName, sizeof(friendlyName) * reqSize, nullptr))
                {
                    // device does not have this property set
                    memset(friendlyName, 0, reqSize > 1 ? reqSize : 1);
                }
                // use friendlyName here
                delete[] friendlyName;
            }
            delete[] hardwareId;
        }
    }
    
    0 讨论(0)
  • 2020-12-05 08:40

    Glad it worked.

    You could try:

    Regex.Match(tmpstring, @"COM\s\d+").ToString()

    for your string matching.

    As .NET style points, I'd add a "using System.Text", and I wouldn't start local variable names with capitals, and if I was feeling really virtuous, I would probably put the SetupDiDestroyDeviceInfoList in a finally{} clause.

    0 讨论(0)
提交回复
热议问题