如何在 Windows 中获取 COM 端口的友好名称?

发布于 2024-07-09 08:04:56 字数 492 浏览 8 评论 0原文

我有一个通过 USB 连接的 GSM 调制解调器。 调制解调器创建 2 个串行端口。 第一个端口自动连接到调制解调器,第二个端口在设备管理器中显示为“HUAWEI Mobile Connect - 3G PC UI 接口(COM6)”。

第二个端口用于从调制解调器获取重要信息,例如信号质量; 发送和接收短信; 以及一系列其他功能。

我正在编写一个应用程序,它将包含第二个端口提供的一些功能。 我需要一种可靠的方法来识别哪个 COM 端口是备用端口。 迭代端口并检查对“ATE0”的响应是不够的。 调制解调器的端口通常是编号较低的端口,当拨号连接未激活时,它将与第二个端口相同地响应“ATE0”。

我想做的是迭代端口并检查它们的友好名称,如设备管理器中所示。 这样我就可以将应用程序中的端口链接到设备管理器中标有“HUAWEI Mobile Connect - 3G PC UI Interface (COM6)”的端口。 我只是还没有找到任何信息可以让我以编程方式获取该名称。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

故笙诉离歌 2024-07-16 08:04:56

很久以前,我为客户端编写了一个实用程序来执行此操作,但针对的是 GPS 而不是调制解调器。

我刚刚查看了它,跳出的可能有帮助的位是:(

    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, ®DataType, hardwareId, sizeof(hardwareId), NULL))
    {
...

您在递增 nDevice 的循环中调用此位)

,然后

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

找到设备的名称。

希望这能帮助您朝着正确的方向前进。

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, ®DataType, 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.

音盲 2024-07-16 08:04:56

确定串行端口设备是您想要的设备后(通过查看其友好名称、检查其父设备等),获取端口名称的正确方法可能是:

  • 调用SetupDiOpenDevRegKey(hDevInfo, devInfoData) , DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) 获取所谓设备密钥的 HKEY
  • REG_SZ 值“PortName”
  • 查询此注册表项以获取 不要忘记关闭 HKEY :)

但是,这可能需要 C# 中的大量互操作,这一点都不好笑,所以如果您坚持使用字符串解析解决方案,我不会责怪您。

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.

雨轻弹 2024-07-16 08:04:56

Will Dean 发布的信息非常有帮助。 这是最终对我有用的代码。 PInvoke 类中的所有内容均逐字取自 http://www.pinvoke.net 。 我确实必须在这里或那里更改数据类型才能使其工作(例如使用枚举而不是 uint 时),但它应该很容易弄清楚。

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

我认为行 Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); 有点笨拙,有关如何清理它的建议将不胜感激。

感谢您对此事的帮助,如果没有您,我仍然会在谷歌上搜索。

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.

深海里的那抹蓝 2024-07-16 08:04:56

C++ 版本基于@Will Dean 的回答。

#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, ®DataType, 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;
    }
}

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, ®DataType, 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;
    }
}
冷弦 2024-07-16 08:04:56

很高兴它起作用了。

您可以尝试:

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

进行字符串匹配。

作为 .NET 风格点,我会添加一个“using System.Text”,并且我不会以大写字母开头局部变量名称,如果我感觉真的很善良,我可能会将 SetupDiDestroyDeviceInfoList 放在 finally{} 子句中。

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.

权谋诡计 2024-07-16 08:04:56

我建立了一个用于串行端口控制的库。 它可以在注册表中搜索友好名称。 链接在这里。

https://github.com/kcwongjoe/serial_port

std::vector<SerialPortInfo> comPorts = SerialPort::getSerialPortList();
std::cout << comPorts[0].friendlyName << std::endl;

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;
瘫痪情歌 2024-07-16 08:04:56

使用了LiGenChen发布的方法。 ComPortSetupAPISetupDiClassGuids 方法给出了最佳时间和友好名称。

Used the method posted by LiGenChen. The method ComPortSetupAPISetupDiClassGuids gave the best time and friendly name.

橘味果▽酱 2024-07-16 08:04:56

这里基于答案的组合是一个获取 COM 号、VID / PID 和友好名称等的解决方案。

这里是一些用于获取已连接设备列表的示例代码。

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

这是 SerialPortDeviceDesc 类

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

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;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文