如何通过友好名称打开串口?

发布于 2024-09-03 15:18:41 字数 93 浏览 3 评论 0原文

友好名称 = 显示在“设备管理器”中“端口(COM 和 LPT)”下的名称。

编辑:下面提供了两种解决方案。一种使用 WMI,另一种使用 SetupAPI。

friendly name = the name that appears in "Device Manager" under "Ports (COM & LPT).

EDIT: two solutions provided below. One with WMI and another with SetupAPI.

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

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

发布评论

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

评论(8

好听的两个字的网名 2024-09-10 15:18:41

贴出今晚的代码,供大家欣赏:

public class SetupDiWrap
{
    static public string ComPortNameFromFriendlyNamePrefix(string friendlyNamePrefix)
    {
        const string className = "Ports";
        Guid[] guids = GetClassGUIDs(className);

        System.Text.RegularExpressions.Regex friendlyNameToComPort =
            new System.Text.RegularExpressions.Regex(@".? \((COM\d+)\)$");  // "..... (COMxxx)" -> COMxxxx

        foreach (Guid guid in guids)
        {
            // We start at the "root" of the device tree and look for all
            // devices that match the interface GUID of a disk
            Guid guidClone = guid;
            IntPtr h = SetupDiGetClassDevs(ref guidClone, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);
            if (h.ToInt32() != INVALID_HANDLE_VALUE)
            {
                int nDevice = 0;
                while (true)
                {
                    SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
                    da.cbSize = (uint)Marshal.SizeOf(da);

                    if (0 == SetupDiEnumDeviceInfo(h, nDevice++, ref da))
                        break;

                    uint RegType;
                    byte[] ptrBuf = new byte[BUFFER_SIZE];
                    uint RequiredSize;
                    if (SetupDiGetDeviceRegistryProperty(h, ref da,
                        (uint)SPDRP.FRIENDLYNAME, out RegType, ptrBuf,
                        BUFFER_SIZE, out RequiredSize))
                    {
                        const int utf16terminatorSize_bytes = 2;
                        string friendlyName = System.Text.UnicodeEncoding.Unicode.GetString(ptrBuf, 0, (int)RequiredSize - utf16terminatorSize_bytes);

                        if (!friendlyName.StartsWith(friendlyNamePrefix))
                            continue;

                        if (!friendlyNameToComPort.IsMatch(friendlyName))
                            continue;

                        return friendlyNameToComPort.Match(friendlyName).Groups[1].Value;
                    }
                } // devices
                SetupDiDestroyDeviceInfoList(h);
            }
        } // class guids

        return null;
    }

    /// <summary>
    /// The SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVINFO_DATA
    {
        /// <summary>Size of the structure, in bytes.</summary>
        public uint cbSize;
        /// <summary>GUID of the device interface class.</summary>
        public Guid ClassGuid;
        /// <summary>Handle to this device instance.</summary>
        public uint DevInst;
        /// <summary>Reserved; do not use.</summary>
        public uint Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVICE_INTERFACE_DATA
    {
        public Int32 cbSize;
        public Guid interfaceClassGuid;
        public Int32 flags;
        private UIntPtr reserved;
    }

    const int BUFFER_SIZE = 1024;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct SP_DEVICE_INTERFACE_DETAIL_DATA
    {
        public int cbSize;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
        public string DevicePath;
    }

    private enum SPDRP
    {
        DEVICEDESC = 0x00000000,
        HARDWAREID = 0x00000001,
        COMPATIBLEIDS = 0x00000002,
        NTDEVICEPATHS = 0x00000003,
        SERVICE = 0x00000004,
        CONFIGURATION = 0x00000005,
        CONFIGURATIONVECTOR = 0x00000006,
        CLASS = 0x00000007,
        CLASSGUID = 0x00000008,
        DRIVER = 0x00000009,
        CONFIGFLAGS = 0x0000000A,
        MFG = 0x0000000B,
        FRIENDLYNAME = 0x0000000C,
        LOCATION_INFORMATION = 0x0000000D,
        PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E,
        CAPABILITIES = 0x0000000F,
        UI_NUMBER = 0x00000010,
        UPPERFILTERS = 0x00000011,
        LOWERFILTERS = 0x00000012,
        MAXIMUM_PROPERTY = 0x00000013,
    }

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiClassGuidsFromName(string ClassName,
        ref Guid ClassGuidArray1stItem, UInt32 ClassGuidArraySize,
        out UInt32 RequiredSize);

    [DllImport("setupapi.dll")]
    internal static extern IntPtr SetupDiGetClassDevsEx(IntPtr ClassGuid,
        [MarshalAs(UnmanagedType.LPStr)]String enumerator,
        IntPtr hwndParent, Int32 Flags, IntPtr DeviceInfoSet,
        [MarshalAs(UnmanagedType.LPStr)]String MachineName, IntPtr Reserved);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern Boolean SetupDiEnumDeviceInterfaces(
       IntPtr hDevInfo,
       IntPtr optionalCrap, //ref SP_DEVINFO_DATA devInfo,
       ref Guid interfaceClassGuid,
       UInt32 memberIndex,
       ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData
    );

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
        Int32 MemberIndex, ref SP_DEVINFO_DATA DeviceInterfaceData);

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiClassNameFromGuid(ref Guid ClassGuid,
        StringBuilder className, Int32 ClassNameSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiGetClassDescription(ref Guid ClassGuid,
        StringBuilder classDescription, Int32 ClassDescriptionSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        StringBuilder DeviceInstanceId, Int32 DeviceInstanceIdSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SetupDiGetClassDevs(           // 1st form using a ClassGUID only, with null Enumerator
       ref Guid ClassGuid,
       IntPtr Enumerator,
       IntPtr hwndParent,
       int Flags
    );

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern Boolean SetupDiGetDeviceInterfaceDetail(
       IntPtr hDevInfo,
       ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
       ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
       UInt32 deviceInterfaceDetailDataSize,
       out UInt32 requiredSize,
       ref SP_DEVINFO_DATA deviceInfoData
    );

    /// <summary>
    /// The SetupDiGetDeviceRegistryProperty function retrieves the specified device property.
    /// This handle is typically returned by the SetupDiGetClassDevs or SetupDiGetClassDevsEx function.
    /// </summary>
    /// <param Name="DeviceInfoSet">Handle to the device information set that contains the interface and its underlying device.</param>
    /// <param Name="DeviceInfoData">Pointer to an SP_DEVINFO_DATA structure that defines the device instance.</param>
    /// <param Name="Property">Device property to be retrieved. SEE MSDN</param>
    /// <param Name="PropertyRegDataType">Pointer to a variable that receives the registry data Type. This parameter can be NULL.</param>
    /// <param Name="PropertyBuffer">Pointer to a buffer that receives the requested device property.</param>
    /// <param Name="PropertyBufferSize">Size of the buffer, in bytes.</param>
    /// <param Name="RequiredSize">Pointer to a variable that receives the required buffer size, in bytes. This parameter can be NULL.</param>
    /// <returns>If the function succeeds, the return value is nonzero.</returns>
    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryProperty(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Property,
        out UInt32 PropertyRegDataType,
        byte[] PropertyBuffer,
        uint PropertyBufferSize,
        out UInt32 RequiredSize);


    const int DIGCF_DEFAULT = 0x1;
    const int DIGCF_PRESENT = 0x2;
    const int DIGCF_ALLCLASSES = 0x4;
    const int DIGCF_PROFILE = 0x8;
    const int DIGCF_DEVICEINTERFACE = 0x10;
    const int INVALID_HANDLE_VALUE = -1;

    private static Guid[] GetClassGUIDs(string className)
    {
        UInt32 requiredSize = 0;
        Guid[] guidArray = new Guid[1];

        bool status = SetupDiClassGuidsFromName(className, ref guidArray[0], 1, out requiredSize);
        if (true == status)
        {
            if (1 < requiredSize)
            {
                guidArray = new Guid[requiredSize];
                SetupDiClassGuidsFromName(className, ref guidArray[0], requiredSize, out requiredSize);
            }
        }
        else
            throw new System.ComponentModel.Win32Exception();

        return guidArray;
    }


}

Posting tonight's code, for everybody's enjoyment:

public class SetupDiWrap
{
    static public string ComPortNameFromFriendlyNamePrefix(string friendlyNamePrefix)
    {
        const string className = "Ports";
        Guid[] guids = GetClassGUIDs(className);

        System.Text.RegularExpressions.Regex friendlyNameToComPort =
            new System.Text.RegularExpressions.Regex(@".? \((COM\d+)\)$");  // "..... (COMxxx)" -> COMxxxx

        foreach (Guid guid in guids)
        {
            // We start at the "root" of the device tree and look for all
            // devices that match the interface GUID of a disk
            Guid guidClone = guid;
            IntPtr h = SetupDiGetClassDevs(ref guidClone, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);
            if (h.ToInt32() != INVALID_HANDLE_VALUE)
            {
                int nDevice = 0;
                while (true)
                {
                    SP_DEVINFO_DATA da = new SP_DEVINFO_DATA();
                    da.cbSize = (uint)Marshal.SizeOf(da);

                    if (0 == SetupDiEnumDeviceInfo(h, nDevice++, ref da))
                        break;

                    uint RegType;
                    byte[] ptrBuf = new byte[BUFFER_SIZE];
                    uint RequiredSize;
                    if (SetupDiGetDeviceRegistryProperty(h, ref da,
                        (uint)SPDRP.FRIENDLYNAME, out RegType, ptrBuf,
                        BUFFER_SIZE, out RequiredSize))
                    {
                        const int utf16terminatorSize_bytes = 2;
                        string friendlyName = System.Text.UnicodeEncoding.Unicode.GetString(ptrBuf, 0, (int)RequiredSize - utf16terminatorSize_bytes);

                        if (!friendlyName.StartsWith(friendlyNamePrefix))
                            continue;

                        if (!friendlyNameToComPort.IsMatch(friendlyName))
                            continue;

                        return friendlyNameToComPort.Match(friendlyName).Groups[1].Value;
                    }
                } // devices
                SetupDiDestroyDeviceInfoList(h);
            }
        } // class guids

        return null;
    }

    /// <summary>
    /// The SP_DEVINFO_DATA structure defines a device instance that is a member of a device information set.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVINFO_DATA
    {
        /// <summary>Size of the structure, in bytes.</summary>
        public uint cbSize;
        /// <summary>GUID of the device interface class.</summary>
        public Guid ClassGuid;
        /// <summary>Handle to this device instance.</summary>
        public uint DevInst;
        /// <summary>Reserved; do not use.</summary>
        public uint Reserved;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVICE_INTERFACE_DATA
    {
        public Int32 cbSize;
        public Guid interfaceClassGuid;
        public Int32 flags;
        private UIntPtr reserved;
    }

    const int BUFFER_SIZE = 1024;

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct SP_DEVICE_INTERFACE_DETAIL_DATA
    {
        public int cbSize;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = BUFFER_SIZE)]
        public string DevicePath;
    }

    private enum SPDRP
    {
        DEVICEDESC = 0x00000000,
        HARDWAREID = 0x00000001,
        COMPATIBLEIDS = 0x00000002,
        NTDEVICEPATHS = 0x00000003,
        SERVICE = 0x00000004,
        CONFIGURATION = 0x00000005,
        CONFIGURATIONVECTOR = 0x00000006,
        CLASS = 0x00000007,
        CLASSGUID = 0x00000008,
        DRIVER = 0x00000009,
        CONFIGFLAGS = 0x0000000A,
        MFG = 0x0000000B,
        FRIENDLYNAME = 0x0000000C,
        LOCATION_INFORMATION = 0x0000000D,
        PHYSICAL_DEVICE_OBJECT_NAME = 0x0000000E,
        CAPABILITIES = 0x0000000F,
        UI_NUMBER = 0x00000010,
        UPPERFILTERS = 0x00000011,
        LOWERFILTERS = 0x00000012,
        MAXIMUM_PROPERTY = 0x00000013,
    }

    [DllImport("setupapi.dll", SetLastError = true)]
    static extern bool SetupDiClassGuidsFromName(string ClassName,
        ref Guid ClassGuidArray1stItem, UInt32 ClassGuidArraySize,
        out UInt32 RequiredSize);

    [DllImport("setupapi.dll")]
    internal static extern IntPtr SetupDiGetClassDevsEx(IntPtr ClassGuid,
        [MarshalAs(UnmanagedType.LPStr)]String enumerator,
        IntPtr hwndParent, Int32 Flags, IntPtr DeviceInfoSet,
        [MarshalAs(UnmanagedType.LPStr)]String MachineName, IntPtr Reserved);

    [DllImport("setupapi.dll")]
    internal static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern Boolean SetupDiEnumDeviceInterfaces(
       IntPtr hDevInfo,
       IntPtr optionalCrap, //ref SP_DEVINFO_DATA devInfo,
       ref Guid interfaceClassGuid,
       UInt32 memberIndex,
       ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData
    );

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
        Int32 MemberIndex, ref SP_DEVINFO_DATA DeviceInterfaceData);

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiClassNameFromGuid(ref Guid ClassGuid,
        StringBuilder className, Int32 ClassNameSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiGetClassDescription(ref Guid ClassGuid,
        StringBuilder classDescription, Int32 ClassDescriptionSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiGetDeviceInstanceId(IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        StringBuilder DeviceInstanceId, Int32 DeviceInstanceIdSize, ref Int32 RequiredSize);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SetupDiGetClassDevs(           // 1st form using a ClassGUID only, with null Enumerator
       ref Guid ClassGuid,
       IntPtr Enumerator,
       IntPtr hwndParent,
       int Flags
    );

    [DllImport(@"setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern Boolean SetupDiGetDeviceInterfaceDetail(
       IntPtr hDevInfo,
       ref SP_DEVICE_INTERFACE_DATA deviceInterfaceData,
       ref SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData,
       UInt32 deviceInterfaceDetailDataSize,
       out UInt32 requiredSize,
       ref SP_DEVINFO_DATA deviceInfoData
    );

    /// <summary>
    /// The SetupDiGetDeviceRegistryProperty function retrieves the specified device property.
    /// This handle is typically returned by the SetupDiGetClassDevs or SetupDiGetClassDevsEx function.
    /// </summary>
    /// <param Name="DeviceInfoSet">Handle to the device information set that contains the interface and its underlying device.</param>
    /// <param Name="DeviceInfoData">Pointer to an SP_DEVINFO_DATA structure that defines the device instance.</param>
    /// <param Name="Property">Device property to be retrieved. SEE MSDN</param>
    /// <param Name="PropertyRegDataType">Pointer to a variable that receives the registry data Type. This parameter can be NULL.</param>
    /// <param Name="PropertyBuffer">Pointer to a buffer that receives the requested device property.</param>
    /// <param Name="PropertyBufferSize">Size of the buffer, in bytes.</param>
    /// <param Name="RequiredSize">Pointer to a variable that receives the required buffer size, in bytes. This parameter can be NULL.</param>
    /// <returns>If the function succeeds, the return value is nonzero.</returns>
    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryProperty(
        IntPtr DeviceInfoSet,
        ref SP_DEVINFO_DATA DeviceInfoData,
        uint Property,
        out UInt32 PropertyRegDataType,
        byte[] PropertyBuffer,
        uint PropertyBufferSize,
        out UInt32 RequiredSize);


    const int DIGCF_DEFAULT = 0x1;
    const int DIGCF_PRESENT = 0x2;
    const int DIGCF_ALLCLASSES = 0x4;
    const int DIGCF_PROFILE = 0x8;
    const int DIGCF_DEVICEINTERFACE = 0x10;
    const int INVALID_HANDLE_VALUE = -1;

    private static Guid[] GetClassGUIDs(string className)
    {
        UInt32 requiredSize = 0;
        Guid[] guidArray = new Guid[1];

        bool status = SetupDiClassGuidsFromName(className, ref guidArray[0], 1, out requiredSize);
        if (true == status)
        {
            if (1 < requiredSize)
            {
                guidArray = new Guid[requiredSize];
                SetupDiClassGuidsFromName(className, ref guidArray[0], requiredSize, out requiredSize);
            }
        }
        else
            throw new System.ComponentModel.Win32Exception();

        return guidArray;
    }


}
不即不离 2024-09-10 15:18:41

本文 的代码为我完成了这项工作(他链接到这篇文章,但他自己似乎没有在这里提供答案)。这是作者的代码:

using System.Management;
internal class ProcessConnection { 

   public static ConnectionOptions ProcessConnectionOptions()
   {
     ConnectionOptions options = new ConnectionOptions();
     options.Impersonation = ImpersonationLevel.Impersonate;
     options.Authentication = AuthenticationLevel.Default;
     options.EnablePrivileges = true;
     return options;
   }

   public static ManagementScope ConnectionScope(string machineName, ConnectionOptions options, string path)
   {
     ManagementScope connectScope = new ManagementScope();
     connectScope.Path = new ManagementPath(@"\\" + machineName + path);
     connectScope.Options = options;
     connectScope.Connect();
     return connectScope;
   }
}

public class COMPortInfo
{
   public string Name { get; set; }
   public string Description { get; set; }

   public COMPortInfo() { }     

   public static List<COMPortInfo> GetCOMPortsInfo()
   {
     List<COMPortInfo> comPortInfoList = new List<COMPortInfo>();

     ConnectionOptions options = ProcessConnection.ProcessConnectionOptions();
     ManagementScope connectionScope = ProcessConnection.ConnectionScope(Environment.MachineName, options, @"\root\CIMV2");

     ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
     ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(connectionScope, objectQuery);

     using (comPortSearcher)
     {
       string caption = null;
       foreach (ManagementObject obj in comPortSearcher.Get())
       {
         if (obj != null)
         {
           object captionObj = obj["Caption"];
           if (captionObj != null)
           {
              caption = captionObj.ToString();
              if (caption.Contains("(COM"))
              {
                COMPortInfo comPortInfo = new COMPortInfo();
                comPortInfo.Name = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")",
                                                     string.Empty);
                comPortInfo.Description = caption;
                comPortInfoList.Add(comPortInfo);
              }
           }
         }
       }
     } 
     return comPortInfoList;
   } 
}

用法:

foreach (COMPortInfo comPort in COMPortInfo.GetCOMPortsInfo())
{
  Console.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description));
}

This article's code did the job for me (he links to this post, but doesn't seem to have provided an answer here himself). Here's the author's code:

using System.Management;
internal class ProcessConnection { 

   public static ConnectionOptions ProcessConnectionOptions()
   {
     ConnectionOptions options = new ConnectionOptions();
     options.Impersonation = ImpersonationLevel.Impersonate;
     options.Authentication = AuthenticationLevel.Default;
     options.EnablePrivileges = true;
     return options;
   }

   public static ManagementScope ConnectionScope(string machineName, ConnectionOptions options, string path)
   {
     ManagementScope connectScope = new ManagementScope();
     connectScope.Path = new ManagementPath(@"\\" + machineName + path);
     connectScope.Options = options;
     connectScope.Connect();
     return connectScope;
   }
}

public class COMPortInfo
{
   public string Name { get; set; }
   public string Description { get; set; }

   public COMPortInfo() { }     

   public static List<COMPortInfo> GetCOMPortsInfo()
   {
     List<COMPortInfo> comPortInfoList = new List<COMPortInfo>();

     ConnectionOptions options = ProcessConnection.ProcessConnectionOptions();
     ManagementScope connectionScope = ProcessConnection.ConnectionScope(Environment.MachineName, options, @"\root\CIMV2");

     ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
     ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(connectionScope, objectQuery);

     using (comPortSearcher)
     {
       string caption = null;
       foreach (ManagementObject obj in comPortSearcher.Get())
       {
         if (obj != null)
         {
           object captionObj = obj["Caption"];
           if (captionObj != null)
           {
              caption = captionObj.ToString();
              if (caption.Contains("(COM"))
              {
                COMPortInfo comPortInfo = new COMPortInfo();
                comPortInfo.Name = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")",
                                                     string.Empty);
                comPortInfo.Description = caption;
                comPortInfoList.Add(comPortInfo);
              }
           }
         }
       }
     } 
     return comPortInfoList;
   } 
}

Usage:

foreach (COMPortInfo comPort in COMPortInfo.GetCOMPortsInfo())
{
  Console.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description));
}
爱给你人给你 2024-09-10 15:18:41

我知道这是用 C# 发布的,但我确信这可以轻松转换...

    Public Function foo() As Integer
    Try
        Dim searcher As New ManagementObjectSearcher( _
            "root\CIMV2", _
            "SELECT * FROM Win32_SerialPort")

        For Each queryObj As ManagementObject In searcher.Get()
            Debug.WriteLine(queryObj("Caption"))
            Debug.WriteLine(queryObj("Description"))
            Debug.WriteLine(queryObj("DeviceID"))
            Debug.WriteLine(queryObj("Name"))
            Debug.WriteLine(queryObj("PNPDeviceID"))

        Next
    Catch err As ManagementException
        Stop
    End Try
End Function

Public Function bar() As Integer
    Try
        Dim searcher As New ManagementObjectSearcher( _
            "root\CIMV2", _
            "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0")

        For Each queryObj As ManagementObject In searcher.Get()
            If queryObj("Caption").ToString.Contains("(COM") Then
                Debug.WriteLine(queryObj("Caption"))
                Debug.WriteLine(queryObj("Description"))
                Debug.WriteLine(queryObj("DeviceID"))
                Debug.WriteLine(queryObj("Name"))
                Debug.WriteLine(queryObj("PNPDeviceID"))
            End If
        Next
    Catch err As ManagementException
        Stop
    End Try
End Function

它找到我所有的 com 端口、调制解调器、串行、USB 和蓝牙。

I know this was posted in C#, but I am certain this can easily be converted...

    Public Function foo() As Integer
    Try
        Dim searcher As New ManagementObjectSearcher( _
            "root\CIMV2", _
            "SELECT * FROM Win32_SerialPort")

        For Each queryObj As ManagementObject In searcher.Get()
            Debug.WriteLine(queryObj("Caption"))
            Debug.WriteLine(queryObj("Description"))
            Debug.WriteLine(queryObj("DeviceID"))
            Debug.WriteLine(queryObj("Name"))
            Debug.WriteLine(queryObj("PNPDeviceID"))

        Next
    Catch err As ManagementException
        Stop
    End Try
End Function

Public Function bar() As Integer
    Try
        Dim searcher As New ManagementObjectSearcher( _
            "root\CIMV2", _
            "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0")

        For Each queryObj As ManagementObject In searcher.Get()
            If queryObj("Caption").ToString.Contains("(COM") Then
                Debug.WriteLine(queryObj("Caption"))
                Debug.WriteLine(queryObj("Description"))
                Debug.WriteLine(queryObj("DeviceID"))
                Debug.WriteLine(queryObj("Name"))
                Debug.WriteLine(queryObj("PNPDeviceID"))
            End If
        Next
    Catch err As ManagementException
        Stop
    End Try
End Function

It finds all of my com ports, modem, serial, usb, and bluetooth.

素食主义者 2024-09-10 15:18:41

Pavel 的类 SetupDiWrap 工作得很好,它只需要针对 Windows 7 进行一些小调整。

希望此更新能够帮助其他人(像我一样)在 Windows 7 中从 VCP 名称获取 COM 端口号

。1 ) SP_DEVINFO_DATA 在 Windows 7 中发生了变化,总长度不再是 28 字节,而是 32 字节长。这对我有用:

   private struct SP_DEVINFO_DATA
        {
            /// <summary>Size of the structure, in bytes.</summary>
            public int cbSize;
            /// <summary>GUID of the device interface class.</summary>
            public Guid ClassGuid;
            /// <summary>Handle to this device instance.</summary>
            public int DevInst;
            /// <summary>Reserved; do not use.</summary>
            public ulong Reserved;
        }

注意 ulong 代表保留而不是 int。将 uint cbSize 更改为 int cbSize 为我节省了稍后的转换,否则您可以将其保留为 uint。

2) 我还写了这一行:

 da.cbSize = (uint)Marshal.SizeOf(da);

为了清楚起见,有点不同,将 cbSize 设为 32 位:

da.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));

3) 我更改

 [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SetupDiGetClassDevs(       
           ref Guid ClassGuid,
           IntPtr Enumerator,
           IntPtr hwndParent,
           int Flags
        );

 [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SetupDiGetClassDevs( 
           ref Guid ClassGuid,
           UInt32 Enumerator,
           IntPtr hwndParent,
           UInt32 Flags
        );

The Enumerator is no no no more in IntPtr, so you need to call SetupDiGetClassDevs 像这样:

IntPtr h = SetupDiGetClassDevs(ref guidClone, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);

在传递枚举器时注意“0”而不是 IntPtr.Zero

现在,该代码在 Windows 7 中运行起来就像魅力一样!

Pavel's class SetupDiWrap works great, it just needs a few small tweaks for Windows 7.

Hopefully, this update will help other people struggling (like me) to get COM port numbers from VCP names in Windows 7.

1) The SP_DEVINFO_DATA has changed in Windows 7, the total length is no longer 28 bytes, it is 32 bytes long. This is what works for me:

   private struct SP_DEVINFO_DATA
        {
            /// <summary>Size of the structure, in bytes.</summary>
            public int cbSize;
            /// <summary>GUID of the device interface class.</summary>
            public Guid ClassGuid;
            /// <summary>Handle to this device instance.</summary>
            public int DevInst;
            /// <summary>Reserved; do not use.</summary>
            public ulong Reserved;
        }

Note ulong for Reserved instead of an int. Changing uint cbSize to int cbSize saved me a cast later on, otherwise you can leave it as uint.

2) I also wrote the line:

 da.cbSize = (uint)Marshal.SizeOf(da);

a bit different, for clarity, to get the cbSize to 32 bits:

da.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));

3) I changed

 [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
        static extern IntPtr SetupDiGetClassDevs(       
           ref Guid ClassGuid,
           IntPtr Enumerator,
           IntPtr hwndParent,
           int Flags
        );

to

 [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SetupDiGetClassDevs( 
           ref Guid ClassGuid,
           UInt32 Enumerator,
           IntPtr hwndParent,
           UInt32 Flags
        );

The Enumerator is no longer an IntPtr, so you need to call SetupDiGetClassDevs like this:

IntPtr h = SetupDiGetClassDevs(ref guidClone, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_PROFILE);

Note "0" instead of IntPtr.Zero when passing the Enumerator.

The code now runs like a charm in Windows 7!

我喜欢麦丽素 2024-09-10 15:18:41

尝试在 Win32_SerialPort 类上运行 WMI 查询。下载 WmiCodeCreator进行实验并自动生成 C# 代码。

Try running a WMI query on the Win32_SerialPort class. Download WmiCodeCreator to experiment and auto-generate the C# code.

半衾梦 2024-09-10 15:18:41

您可能还想考虑使用注册表,因为我发现 WMI 非常慢(5 或 6 秒)。

在我的例子中,我想识别具有已知友好名称的设备的 COM 端口名称。我使用 regedit 在注册表中搜索了也包含 COM 端口的键中的友好名称。因为我发现的密钥是某种随机 ID 以及其他 10 个 ID,所以我上升了几个级别以找到适合在其中进行搜索的密钥。

我想出的代码如下:

Dim searchFriendlyName = "Your Device Name".ToLower
Dim k0 = Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Enum\USB\", False)
For Each k1Name In k0.GetSubKeyNames
    Dim k1 = k0.OpenSubKey(k1Name, False)
    For Each k2name In k1.GetSubKeyNames
        Dim k2 = k1.OpenSubKey(k2name, False)
        If k2.GetValueNames.Contains("FriendlyName") AndAlso k2.GetValue("FriendlyName").ToString.ToLower.Contains(searchFriendlyName) Then
            If k2.GetSubKeyNames.Contains("Device Parameters") Then
                Dim k3 = k2.OpenSubKey("Device Parameters", False)
                If k3.GetValueNames.Contains("PortName") Then
                    For Each s In SerialPort.GetPortNames
                        If k3.GetValue("PortName").ToString.ToLower = s.ToLower Then
                            Return s
                        End If
                    Next
                End If
            End If
        End If
    Next
Next

这当然需要根据您的设备在注册表中显示的方式和位置进行修改,但如果您尝试“自动检测”特定类型设备的 Com 端口,那么你应该能够完成这项工作。

请记住,如果您必须递归搜索大量键,那么这会减慢上述解决方案的速度,因此请尝试在注册表中找到正确的位置进行查找。

我还在注册表搜索后添加了 WMI 代码,以防注册表搜索为空:

Dim mg As New System.Management.ManagementClass("Win32_SerialPort")
Try

    For Each i In mg.GetInstances()
        Dim name = i.GetPropertyValue("Name")
        If name IsNot Nothing AndAlso name.ToString.ToLower.Contains(searchFriendlyName.ToLower) Then
            Return i.GetPropertyValue("DeviceId").ToString
        End If
    Next
Finally
    mg.Dispose()
End Try

You might also want to consider using the registry as I have found WMI quite slow (5 or 6 seconds)

In my case I wanted to identify the COM port name of a device with a known friendly name. Using regedit i searched the registry for the friendly name in a key which also contained the COM port. Because the key I found was some sort of random ID along with 10 others I went up a few levels to find a key suitable to search within.

The code I came up with is as follows:

Dim searchFriendlyName = "Your Device Name".ToLower
Dim k0 = Registry.LocalMachine.OpenSubKey("SYSTEM\CurrentControlSet\Enum\USB\", False)
For Each k1Name In k0.GetSubKeyNames
    Dim k1 = k0.OpenSubKey(k1Name, False)
    For Each k2name In k1.GetSubKeyNames
        Dim k2 = k1.OpenSubKey(k2name, False)
        If k2.GetValueNames.Contains("FriendlyName") AndAlso k2.GetValue("FriendlyName").ToString.ToLower.Contains(searchFriendlyName) Then
            If k2.GetSubKeyNames.Contains("Device Parameters") Then
                Dim k3 = k2.OpenSubKey("Device Parameters", False)
                If k3.GetValueNames.Contains("PortName") Then
                    For Each s In SerialPort.GetPortNames
                        If k3.GetValue("PortName").ToString.ToLower = s.ToLower Then
                            Return s
                        End If
                    Next
                End If
            End If
        End If
    Next
Next

This will of course need to be modified depending upon how and where your device shows up in the registry but if you are trying to 'Auto Detect' the Com Port of a specific type of deivce then you should be able to make this work.

Remember if you have to recursivly search lots of keys then this will slow the above solution down so try and find the right place in the registry to look.

I also included WMI code after the registry search in case the registry search came up empty:

Dim mg As New System.Management.ManagementClass("Win32_SerialPort")
Try

    For Each i In mg.GetInstances()
        Dim name = i.GetPropertyValue("Name")
        If name IsNot Nothing AndAlso name.ToString.ToLower.Contains(searchFriendlyName.ToLower) Then
            Return i.GetPropertyValue("DeviceId").ToString
        End If
    Next
Finally
    mg.Dispose()
End Try
仲春光 2024-09-10 15:18:41

如果您专门使用 USB 设备而不是其他类型的 COM 端口,则跨平台 USB 库 libusbp 有一个示例,您可以运行它来演示如何查找 COM基于 COM 端口的 USB 产品 ID 和供应商 ID 的端口名称。

与尝试在设备管理器中使用友好名称相比,这是一个不同但可能更好的选择。如果您确实想要的话,也许可以扩展 libusbp 以允许访问友好名称。

If you are specifically using USB devices and not some other type of COM port, the cross-platform USB library libusbp has an example you can run that shows how to find the COM port name based on the USB product ID and vendor ID of the COM port.

That is a different but probably better choice than trying to use the friendly name in the Device Manager. Perhaps libusbp could be extended to allow access to the friendly name if you really want that.

无言温柔 2024-09-10 15:18:41

我使用 com0com 生成的虚拟端口。
这样,您就可以根据需要命名端口 - 所以我的端口标题如下:
“com0com - 串行端口对仿真器 0 的总线 (COMA <-> COMB)”

使用上面发布的 WMI 代码,您将获得名称 ” COMA <-> COMB" 用于该端口。
看起来这样的结构不是端口,但上面的代码会将其视为串行端口...

顺便说一句,“COMA”是端口的完全有效名称...(这意味着,寻找仅末尾的数字是不够的)。

所以我想知道如何才能可靠地区分有效的现有串行端口名称和这种奇怪的结构......

I use virtual ports generated by com0com.
With that you're able to name the ports as you want - so I've port captions like follows:
"com0com - bus for serial port pair emulator 0 (COMA <-> COMB)"

With the above posted WMI code you will then get the name "COMA <-> COMB" for that port.
It seems such constructs are no ports, but the above code will treat it as serial port...

BTW, "COMA" is a totally valid name for a port... (that means, looking for only numbers at the end is not enough).

So I wonder how I can reliably distinguish between a valid, existing serial port name and such strange constructs...

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