Получение информации о последовательном порте

У меня есть код, который загружает последовательные порты в поле со списком:

     List<String> tList = new List<String>(); 

     comboBoxComPort.Items.Clear();

     foreach (string s in SerialPort.GetPortNames())
     {
        tList.Add(s);
     }

     tList.Sort();
     comboBoxComPort.Items.Add("Select COM port...");
     comboBoxComPort.Items.AddRange(tList.ToArray());
     comboBoxComPort.SelectedIndex = 0;

Я хотел бы добавить описания портов (аналогично тому, что показано для COM-портов в диспетчере устройств) в список и отсортировать элементы в списке после индекса 0 (решено: см. Фрагмент выше). У кого-нибудь есть предложения по добавлению описаний портов? Я использую Microsoft Visual C# 2008 Express Edition (.NET 2.0). Любые мысли, которые вы можете иметь, будут оценены. Благодарю.

9 ответов

Решение

На MSDN есть сообщение об этой же проблеме:

Получение дополнительной информации о последовательном порте в C#

Привет Равенб,

Мы не можем получить информацию через тип SerialPort. Я не знаю, зачем вам эта информация в вашем приложении. Однако есть решенная тема с тем же вопросом, что и у вас. Вы можете проверить код там и посмотреть, может ли он вам помочь.

Если у вас возникнут какие-либо проблемы, пожалуйста, дайте мне знать.

С наилучшими пожеланиями, Брюс Чжоу

Ссылка в этом посте идет на этот:

Как получить больше информации о порте, используя System.IO.Ports.SerialPort

Вы, вероятно, можете получить эту информацию из запроса WMI. Проверьте этот инструмент, чтобы помочь вам найти правильный код. Почему ты все равно? Это просто деталь для эмулятора USB, нормальные последовательные порты не будут иметь этого. Последовательный порт просто известен "COMx", не более того.

Я попробовал так много решений здесь, которые не работали для меня, только отображая некоторые порты. Но следующее отображало все из них и их информацию.

        using (var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PnPEntity WHERE Caption like '%(COM%'"))
        {
            var portnames = SerialPort.GetPortNames();
            var ports = searcher.Get().Cast<ManagementBaseObject>().ToList().Select(p => p["Caption"].ToString());

            var portList = portnames.Select(n => n + " - " + ports.FirstOrDefault(s => s.Contains(n))).ToList();

            foreach(string s in portList)
            {
                Console.WriteLine(s);
            }
        }
    }

РЕДАКТИРОВАТЬ: Извините, я пролетел мимо вашего вопроса слишком быстро. Теперь я понимаю, что вы ищете список с именем порта + описание порта. Я обновил код соответственно...

Используя System.Management, вы можете запрашивать все порты и всю информацию для каждого порта (как в диспетчере устройств...)

Пример кода (обязательно добавьте ссылку на System.Management):

using System;
using System.Management;
using System.Collections.Generic;
using System.Linq;
using System.IO.Ports;        

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var searcher = new ManagementObjectSearcher
                ("SELECT * FROM WIN32_SerialPort"))
            {
                string[] portnames = SerialPort.GetPortNames();
                var ports = searcher.Get().Cast<ManagementBaseObject>().ToList();
                var tList = (from n in portnames
                            join p in ports on n equals p["DeviceID"].ToString()
                            select n + " - " + p["Caption"]).ToList();

                tList.ForEach(Console.WriteLine);
            }

            // pause program execution to review results...
            Console.WriteLine("Press enter to exit");
            Console.ReadLine();
        }
    }
}

Более подробная информация здесь: http://msdn.microsoft.com/en-us/library/aa394582%28VS.85%29.aspx

Используйте следующий фрагмент кода

Это дает следующий вывод при выполнении.

serial port : Communications Port (COM1)
serial port : Communications Port (COM2)

Не забудьте добавить

using System;
using System.Management;
using System.Windows.Forms;

Также добавьте ссылку на system.Management (по умолчанию он недоступен)

C#

private void GetSerialPort()
{

    try
    {
        ManagementObjectSearcher searcher = 
            new ManagementObjectSearcher("root\\CIMV2", 
            "SELECT * FROM Win32_PnPEntity"); 

        foreach (ManagementObject queryObj in searcher.Get())
        {
            if (queryObj["Caption"].ToString().Contains("(COM"))
            {
                Console.WriteLine("serial port : {0}", queryObj["Caption"]);
            }

        }
    }
    catch (ManagementException e)
    {
        MessageBox.Show( e.Message);
    }

}

VB

  Private Sub GetAllSerialPortsName()
        Try
            Dim searcher As New ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_PnPEntity")
            For Each queryObj As ManagementObject In searcher.Get()
                If InStr(queryObj("Caption"), "(COM") > 0 Then
                    Console.WriteLine("serial port : {0}", queryObj("Caption"))
                End If
            Next
        Catch err As ManagementException
            MsgBox(err.Message)
        End Try
    End Sub

Обновление: вы также можете проверить

if (queryObj["Caption"].ToString().StartsWith("serial port"))

вместо

if (queryObj["Caption"].ToString().Contains("(COM"))

Ни один из ответов здесь не удовлетворяет мои потребности.

Ответ Муно неверен, потому что в нем перечислены ТОЛЬКО USB-порты.

Ответ от code4life неверен, потому что в нем перечислены все, ЗА ИСКЛЮЧЕНИЕМ USB-портов. (Тем не менее, у него 44 голоса за!!!)

У меня есть порт моделирования принтера EPSON на моем компьютере, который не указан ни в одном из приведенных здесь ответов. Поэтому мне пришлось написать собственное решение. Кроме того, я хочу отображать больше информации, чем просто строку заголовка. Мне также нужно отделить имя порта от описания.

Мой код был протестирован в Windows XP, Windows 7 и Windows 10.

Имя порта (например, "COM1") должно быть прочитано из реестра, поскольку WMI не предоставляет эту информацию для всех COM-портов (EPSON).

Если вы используете мой код, вам не нужно SerialPort.GetPortNames()больше. Моя функция возвращает те же порты, но с дополнительной информацией. Почему Microsoft не реализовала такую ​​функцию во фреймворке??

using System.Management;
using Microsoft.Win32;

using (ManagementClass i_Entity = new ManagementClass("Win32_PnPEntity"))
{
    foreach (ManagementObject i_Inst in i_Entity.GetInstances())
    {
        Object o_Guid = i_Inst.GetPropertyValue("ClassGuid");
        if (o_Guid == null || o_Guid.ToString().ToUpper() != "{4D36E978-E325-11CE-BFC1-08002BE10318}")
            continue; // Skip all devices except device class "PORTS"

        String s_Caption  = i_Inst.GetPropertyValue("Caption")     .ToString();
        String s_Manufact = i_Inst.GetPropertyValue("Manufacturer").ToString();
        String s_DeviceID = i_Inst.GetPropertyValue("PnpDeviceID") .ToString();
        String s_RegPath  = "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Enum\\" + s_DeviceID + "\\Device Parameters";
        String s_PortName = Registry.GetValue(s_RegPath, "PortName", "").ToString();

        int s32_Pos = s_Caption.IndexOf(" (COM");
        if (s32_Pos > 0) // remove COM port from description
            s_Caption = s_Caption.Substring(0, s32_Pos);

        Console.WriteLine("Port Name:    " + s_PortName);
        Console.WriteLine("Description:  " + s_Caption);
        Console.WriteLine("Manufacturer: " + s_Manufact);
        Console.WriteLine("Device ID:    " + s_DeviceID);
        Console.WriteLine("-----------------------------------");
    }
}

Я тестировал код с большим количеством COM-портов. Это вывод консоли:

Port Name:    COM29
Description:  CDC Interface (Virtual COM Port) for USB Debug
Manufacturer: GHI Electronics, LLC
Device ID:    USB\VID_1B9F&PID_F003&MI_01\6&3009671A&0&0001
-----------------------------------
Port Name:    COM28
Description:  Teensy USB Serial
Manufacturer: PJRC.COM, LLC.
Device ID:    USB\VID_16C0&PID_0483\1256310
-----------------------------------
Port Name:    COM25
Description:  USB-SERIAL CH340
Manufacturer: wch.cn
Device ID:    USB\VID_1A86&PID_7523\5&2499667D&0&3
-----------------------------------
Port Name:    COM26
Description:  Prolific USB-to-Serial Comm Port
Manufacturer: Prolific
Device ID:    USB\VID_067B&PID_2303\5&2499667D&0&4
-----------------------------------
Port Name:    COM1
Description:  Comunications Port
Manufacturer: (Standard port types)
Device ID:    ACPI\PNP0501\1
-----------------------------------
Port Name:    COM999
Description:  EPSON TM Virtual Port Driver
Manufacturer: EPSON
Device ID:    ROOT\PORTS\0000
-----------------------------------
Port Name:    COM20
Description:  EPSON COM Emulation USB Port
Manufacturer: EPSON
Device ID:    ROOT\PORTS\0001
-----------------------------------
Port Name:    COM8
Description:  Standard Serial over Bluetooth link
Manufacturer: Microsoft
Device ID:    BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&000F\8&3ADBDF90&0&001DA568988B_C00000000
-----------------------------------
Port Name:    COM9
Description:  Standard Serial over Bluetooth link
Manufacturer: Microsoft
Device ID:    BTHENUM\{00001101-0000-1000-8000-00805F9B34FB}_LOCALMFG&0000\8&3ADBDF90&0&000000000000_00000002
-----------------------------------
Port Name:    COM30
Description:  Arduino Uno
Manufacturer: Arduino LLC (www.arduino.cc)
Device ID:    USB\VID_2341&PID_0001\74132343530351F03132
-----------------------------------

COM1 - это COM-порт на материнской плате.

COM 8 и 9 - это COM-порты Bluetooth.

COM 25 и 26 - это переходники USB-RS232.

COM 28, 29 и 30 - платы, подобные Arduino.

COM 20 и 999 - это порты EPSON.

Я объединил предыдущие ответы и использовал структуру класса Win32_PnPEntity, которую можно найти здесь. Получил такое решение:

using System.Management;
public static void Main()
{
     GetPortInformation();
}

public string GetPortInformation()
    {
        ManagementClass processClass = new ManagementClass("Win32_PnPEntity");
        ManagementObjectCollection Ports = processClass.GetInstances();           
        foreach (ManagementObject property in Ports)
        {
            var name = property.GetPropertyValue("Name");               
            if (name != null && name.ToString().Contains("USB") && name.ToString().Contains("COM"))
            {
                var portInfo = new SerialPortInfo(property);
                //Thats all information i got from port.
                //Do whatever you want with this information
            }
        }
        return string.Empty;
    }

SerialPortInfo класс:

public class SerialPortInfo
{
    public SerialPortInfo(ManagementObject property)
    {
        this.Availability = property.GetPropertyValue("Availability") as int? ?? 0;
        this.Caption = property.GetPropertyValue("Caption") as string ?? string.Empty;
        this.ClassGuid = property.GetPropertyValue("ClassGuid") as string ?? string.Empty;
        this.CompatibleID = property.GetPropertyValue("CompatibleID") as string[] ?? new string[] {};
        this.ConfigManagerErrorCode = property.GetPropertyValue("ConfigManagerErrorCode") as int? ?? 0;
        this.ConfigManagerUserConfig = property.GetPropertyValue("ConfigManagerUserConfig") as bool? ?? false;
        this.CreationClassName = property.GetPropertyValue("CreationClassName") as string ?? string.Empty;
        this.Description = property.GetPropertyValue("Description") as string ?? string.Empty;
        this.DeviceID = property.GetPropertyValue("DeviceID") as string ?? string.Empty;
        this.ErrorCleared = property.GetPropertyValue("ErrorCleared") as bool? ?? false;
        this.ErrorDescription = property.GetPropertyValue("ErrorDescription") as string ?? string.Empty;
        this.HardwareID = property.GetPropertyValue("HardwareID") as string[] ?? new string[] { };
        this.InstallDate = property.GetPropertyValue("InstallDate") as DateTime? ?? DateTime.MinValue;
        this.LastErrorCode = property.GetPropertyValue("LastErrorCode") as int? ?? 0;
        this.Manufacturer = property.GetPropertyValue("Manufacturer") as string ?? string.Empty;
        this.Name = property.GetPropertyValue("Name") as string ?? string.Empty;
        this.PNPClass = property.GetPropertyValue("PNPClass") as string ?? string.Empty;
        this.PNPDeviceID = property.GetPropertyValue("PNPDeviceID") as string ?? string.Empty;
        this.PowerManagementCapabilities = property.GetPropertyValue("PowerManagementCapabilities") as int[] ?? new int[] { };
        this.PowerManagementSupported = property.GetPropertyValue("PowerManagementSupported") as bool? ?? false;
        this.Present = property.GetPropertyValue("Present") as bool? ?? false;
        this.Service = property.GetPropertyValue("Service") as string ?? string.Empty;
        this.Status = property.GetPropertyValue("Status") as string ?? string.Empty;
        this.StatusInfo = property.GetPropertyValue("StatusInfo") as int? ?? 0;
        this.SystemCreationClassName = property.GetPropertyValue("SystemCreationClassName") as string ?? string.Empty;
        this.SystemName = property.GetPropertyValue("SystemName") as string ?? string.Empty;
    }

    int Availability;
    string Caption;
    string ClassGuid;
    string[] CompatibleID;
    int ConfigManagerErrorCode;
    bool ConfigManagerUserConfig;
    string CreationClassName;
    string Description;
    string DeviceID;
    bool ErrorCleared;
    string ErrorDescription;
    string[] HardwareID;
    DateTime InstallDate;
    int LastErrorCode;
    string Manufacturer;
    string Name;
    string PNPClass;
    string PNPDeviceID;
    int[] PowerManagementCapabilities;
    bool PowerManagementSupported;
    bool Present;
    string Service;
    string Status;
    int StatusInfo;
    string SystemCreationClassName;
    string SystemName;       

}

Я не совсем уверен, что вы подразумеваете под "сортировкой элементов после индекса 0", но если вы просто хотите отсортировать массив строк, возвращаемых SerialPort.GetPortNames()Вы можете использовать Array.Sort.

Я переписываю ответ Эльму и обогащаю его, используя Муно.SerialPortInfoсорт. Так это более понятно и дает больше информации. (.net 6)

      using Microsoft.Win32;
using System.Management;
using System.Runtime.Versioning;

public static class SerialPortSearcher
{

    [SupportedOSPlatform("windows")]
    public static IEnumerable<ISerialPortInfo> Search()
    {
        using var entity = new ManagementClass("Win32_PnPEntity");
        foreach (var instance in entity.GetInstances().Cast<ManagementObject>())
        {
            var classGuid = instance.GetPropertyValue("ClassGuid");
            // Skip all devices except device class "PORTS"
            if (classGuid?.ToString()?.ToUpper() == "{4D36E978-E325-11CE-BFC1-08002BE10318}")
            {
                yield return new SerialPortInfo(instance);
            }
        }
    }

    [SupportedOSPlatform("windows")]
    private class SerialPortInfo : ISerialPortInfo
    {
        public SerialPortInfo(ManagementObject obj)
        {
            this.Availability = obj.GetPropertyValue("Availability") as int? ?? 0;
            this.Caption = obj.GetPropertyValue("Caption") as string ?? string.Empty;
            this.ClassGuid = obj.GetPropertyValue("ClassGuid") as string ?? string.Empty;
            this.CompatibleID = obj.GetPropertyValue("CompatibleID") as string[] ?? new string[] { };
            this.ConfigManagerErrorCode = obj.GetPropertyValue("ConfigManagerErrorCode") as int? ?? 0;
            this.ConfigManagerUserConfig = obj.GetPropertyValue("ConfigManagerUserConfig") as bool? ?? false;
            this.CreationClassName = obj.GetPropertyValue("CreationClassName") as string ?? string.Empty;
            this.Description = obj.GetPropertyValue("Description") as string ?? string.Empty;
            this.DeviceID = obj.GetPropertyValue("DeviceID") as string ?? string.Empty;
            this.ErrorCleared = obj.GetPropertyValue("ErrorCleared") as bool? ?? false;
            this.ErrorDescription = obj.GetPropertyValue("ErrorDescription") as string ?? string.Empty;
            this.HardwareID = obj.GetPropertyValue("HardwareID") as string[] ?? new string[] { };
            this.InstallDate = obj.GetPropertyValue("InstallDate") as DateTime? ?? DateTime.MinValue;
            this.LastErrorCode = obj.GetPropertyValue("LastErrorCode") as int? ?? 0;
            this.Manufacturer = obj.GetPropertyValue("Manufacturer") as string ?? string.Empty;
            this.Name = obj.GetPropertyValue("Name") as string ?? string.Empty;
            this.PNPClass = obj.GetPropertyValue("PNPClass") as string ?? string.Empty;
            this.PNPDeviceID = obj.GetPropertyValue("PnpDeviceID") as string ?? string.Empty;
            this.PowerManagementCapabilities = obj.GetPropertyValue("PowerManagementCapabilities") as int[] ?? new int[] { };
            this.PowerManagementSupported = obj.GetPropertyValue("PowerManagementSupported") as bool? ?? false;
            this.Present = obj.GetPropertyValue("Present") as bool? ?? false;
            this.Service = obj.GetPropertyValue("Service") as string ?? string.Empty;
            this.Status = obj.GetPropertyValue("Status") as string ?? string.Empty;
            this.StatusInfo = obj.GetPropertyValue("StatusInfo") as int? ?? 0;
            this.SystemCreationClassName = obj.GetPropertyValue("SystemCreationClassName") as string ?? string.Empty;
            this.SystemName = obj.GetPropertyValue("SystemName") as string ?? string.Empty;

            var regPath = "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Enum\\" + PNPDeviceID + "\\Device Parameters";
            this.PortName = Registry.GetValue(regPath, "PortName", "")?.ToString();

            //int i = Caption.IndexOf(" (COM");
            //if (i > 0) // remove COM port from description
            //    Caption = Caption.Substring(0, i);

        }

        public int Availability { get; }
        public string Caption { get; }
        public string ClassGuid { get; }
        public string[] CompatibleID { get; }
        public int ConfigManagerErrorCode { get; }
        public bool ConfigManagerUserConfig { get; }
        public string CreationClassName { get; }
        public string Description { get; }
        public string DeviceID { get; }
        public bool ErrorCleared { get; }
        public string ErrorDescription { get; }
        public string[] HardwareID { get; }
        public DateTime InstallDate { get; }
        public int LastErrorCode { get; }
        public string Manufacturer { get; }
        public string Name { get; }
        public string PNPClass { get; }
        public string PNPDeviceID { get; }
        public int[] PowerManagementCapabilities { get; }
        public bool PowerManagementSupported { get; }
        public bool Present { get; }
        public string Service { get; }
        public string Status { get; }
        public int StatusInfo { get; }
        public string SystemCreationClassName { get; }
        public string SystemName { get; }
        public string? PortName { get; }
    }
}

public interface ISerialPortInfo
{
    int Availability { get; }
    string Caption { get; }
    string ClassGuid { get; }
    string[] CompatibleID { get; }
    int ConfigManagerErrorCode { get; }
    bool ConfigManagerUserConfig { get; }
    string CreationClassName { get; }
    string Description { get; }
    string DeviceID { get; }
    bool ErrorCleared { get; }
    string ErrorDescription { get; }
    string[] HardwareID { get; }
    DateTime InstallDate { get; }
    int LastErrorCode { get; }
    string Manufacturer { get; }
    string Name { get; }
    string PNPClass { get; }
    string PNPDeviceID { get; }
    string? PortName { get; }
    int[] PowerManagementCapabilities { get; }
    bool PowerManagementSupported { get; }
    bool Present { get; }
    string Service { get; }
    string Status { get; }
    int StatusInfo { get; }
    string SystemCreationClassName { get; }
    string SystemName { get; }
}

Проверьте это вProgram.cs:

      using System.Text.Json;

var ports = SerialPortSearcher.Search().ToArray();

Console.WriteLine(JsonSerializer.Serialize(ports, new JsonSerializerOptions { WriteIndented = true }));

this.comboPortName.Items.AddRange(
    (from qP in System.IO.Ports.SerialPort.GetPortNames()
     orderby System.Text.RegularExpressions.Regex.Replace(qP, "~\\d",
     string.Empty).PadLeft(6, '0')
     select qP).ToArray()
);
Другие вопросы по тегам