You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

System.IO.Ports:如何让GetPortNames()获取隐藏串口?

获取包含隐藏串口的完整列表

SerialPort.GetPortNames()仅能检测系统中已启用的串口,无法识别设备管理器里的隐藏串口,且该方法无参数可调整。你尝试的WMI查询返回空,可通过以下几种方法获取完整串口列表:

方法1:调整WMI查询(包含隐藏设备)

默认WMI查询不会返回隐藏设备,需修改查询逻辑,同时覆盖不同状态的设备。

using System.Management;

// 枚举所有含COM标识的PnP设备(含隐藏)
var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE Caption LIKE '%(COM%'");
foreach (ManagementObject obj in searcher.Get())
{
    string caption = obj["Caption"]?.ToString();
    string status = obj["Status"]?.ToString();
    Console.WriteLine($" - {caption} (状态: {status})");
}

若仍无结果,可尝试重启WMI服务(执行命令winmgmt /reset),或确认程序以管理员权限运行。

方法2:读取注册表获取所有串口

Windows会将所有串口信息(含隐藏)存储在注册表中,可直接读取对应路径获取:

using Microsoft.Win32;

// 读取USB类下的串口设备
RegistryKey usbKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\USB");
if (usbKey != null)
{
    foreach (string subKeyName in usbKey.GetSubKeyNames())
    {
        using (RegistryKey subKey = usbKey.OpenSubKey(subKeyName))
        {
            if (subKey != null)
            {
                foreach (string deviceKeyName in subKey.GetSubKeyNames())
                {
                    using (RegistryKey deviceKey = subKey.OpenSubKey(deviceKeyName))
                    {
                        if (deviceKey != null)
                        {
                            using (RegistryKey deviceParams = deviceKey.OpenSubKey("Device Parameters"))
                            {
                                string portName = deviceParams?.GetValue("PortName")?.ToString();
                                if (!string.IsNullOrEmpty(portName) && portName.StartsWith("COM"))
                                {
                                    Console.WriteLine($" - {portName}");
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

// 读取Serial服务下的串口信息
RegistryKey serialKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\Serial\Enum");
if (serialKey != null)
{
    foreach (string valueName in serialKey.GetValueNames())
    {
        string portInfo = serialKey.GetValue(valueName)?.ToString();
        if (!string.IsNullOrEmpty(portInfo))
        {
            int comIndex = portInfo.IndexOf("COM");
            if (comIndex != -1)
            {
                string portName = portInfo.Substring(comIndex);
                int endIndex = portName.IndexOfAny(new char[] { ' ', '(', ')' });
                if (endIndex != -1) portName = portName.Substring(0, endIndex);
                Console.WriteLine($" - {portName}");
            }
        }
    }
}

注意:此方法需要管理员权限,否则可能无法访问部分注册表项。

方法3:使用SetupAPI枚举设备(最可靠)

通过调用Windows原生SetupAPI可枚举所有设备(含隐藏),无需依赖WMI,可靠性更高:

using System;
using System.Runtime.InteropServices;

public class SerialPortEnumerator
{
    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, uint Enumerator, IntPtr hwndParent, uint Flags);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, uint MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, uint Property, out uint PropertyRegDataType, IntPtr PropertyBuffer, uint PropertyBufferSize, out uint RequiredSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    private const uint DIGCF_ALLCLASSES = 0x00000004;
    private const uint DIGCF_PRESENT = 0x00000002;
    private const uint SPDRP_FRIENDLYNAME = 0x0000000C;

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVINFO_DATA
    {
        public uint cbSize;
        public Guid ClassGuid;
        public uint DevInst;
        public IntPtr Reserved;
    }

    public static void GetAllSerialPorts()
    {
        Guid serialPortGuid = new Guid("{4d36e978-e325-11ce-bfc1-08002be10318}"); // 串口类GUID
        IntPtr deviceInfoSet = SetupDiGetClassDevs(ref serialPortGuid, 0, IntPtr.Zero, DIGCF_ALLCLASSES | DIGCF_PRESENT);

        if (deviceInfoSet == IntPtr.Zero)
        {
            Console.WriteLine("无法获取设备信息集");
            return;
        }

        SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA();
        deviceInfoData.cbSize = (uint)Marshal.SizeOf(deviceInfoData);

        uint index = 0;
        while (SetupDiEnumDeviceInfo(deviceInfoSet, index, ref deviceInfoData))
        {
            uint regDataType;
            uint requiredSize;
            SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, SPDRP_FRIENDLYNAME, out regDataType, IntPtr.Zero, 0, out requiredSize);
            
            IntPtr buffer = Marshal.AllocHGlobal((int)requiredSize);
            if (SetupDiGetDeviceRegistryProperty(deviceInfoSet, ref deviceInfoData, SPDRP_FRIENDLYNAME, out regDataType, buffer, requiredSize, out requiredSize))
            {
                string friendlyName = Marshal.PtrToStringAuto(buffer);
                if (!string.IsNullOrEmpty(friendlyName) && friendlyName.Contains("(COM"))
                {
                    Console.WriteLine($" - {friendlyName}");
                }
            }
            Marshal.FreeHGlobal(buffer);
            index++;
        }

        SetupDiDestroyDeviceInfoList(deviceInfoSet);
    }
}

// 调用示例
SerialPortEnumerator.GetAllSerialPorts();

内容的提问来源于stack exchange,提问作者SiL3NC3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 06:40:22