Вопрос

Я ищу надежный способ перечислить доступные последовательные (COM) порты на компьютере с Windows.Там есть этот пост об использовании WMI, но я хотел бы что-то менее специфичное для .NET - я хочу получить список портов в программе на Python или C ++, без .NET.

В настоящее время я знаю о двух других подходах:

  1. Считывание информации, содержащейся в HARDWARE\\DEVICEMAP\\SERIALCOMM раздел реестра.Это выглядит как отличный вариант, но так ли это надежный?Я не могу найти гарантию в Интернете или в MSDN, что в этой ячейке реестра действительно всегда содержится полный список доступных портов.

  2. Пытаюсь позвонить CreateFile вкл . COMN с N - число от 1 до чего-то еще.Этого недостаточно, потому что некоторые COM-порты не имеют имен COMN.Например, некоторые созданные виртуальные COM-порты называются CSNA0, CSNB0 и так далее, поэтому я бы не стал полагаться на этот метод.

Есть еще какие-нибудь методы / идеи / опыт, которыми можно поделиться?

Редактировать: кстати, вот простая реализация Python для чтения имен портов из реестра:

import _winreg as winreg
import itertools


def enumerate_serial_ports():
    """ Uses the Win32 registry to return a iterator of serial 
        (COM) ports existing on this computer.


    """
    path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
    try:
        key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
    except WindowsError:
        raise IterationError

    for i in itertools.count():
        try:
            val = winreg.EnumValue(key, i)
            yield (str(val[1]), str(val[0]))
        except EnvironmentError:
            break
Это было полезно?

Решение

Доступно несколько вариантов:

<Ол>
  • Позвоните QueryDosDevice с помощью NULL lpDeviceName для вывода списка всех устройств DOS. Затем используйте CreateFile и GetCommConfig с каждым именем устройства в включите, чтобы выяснить, является ли это последовательным портом.

  • Вызовите SetupDiGetClassDevs с помощью ClassGuid GUID_DEVINTERFACE_COMPORT.

  • WMI также доступен для C / C ++ программы .

  • В группе новостей win32 есть некоторые разговоры < и CodeProject, т.е. проект .

    Другие советы

    Использование pySerial с Python:

    import serial.tools.list_ports
    
    
    ports = list(serial.tools.list_ports.comports())
    for p in ports:
        print p
    

    Проект PySerial предоставляет пару решений .

    Я только что создал следующее, основываясь на чтении исходного кода C ++ на EnumSerialPorts и просмотре функция GetDefaultCommConfig () . Это выглядело как самый простой метод с использованием простого ANSI C и одного вызова API для каждого возможного COM-порта.

    #include <stdio.h>
    #include <windows.h>
    #include <winbase.h>
    
    BOOL COM_exists( int port)
    {
        char buffer[7];
        COMMCONFIG CommConfig;
        DWORD size;
    
        if (! (1 <= port && port <= 255))
        {
            return FALSE;
        }
    
        snprintf( buffer, sizeof buffer, "COM%d", port);
        size = sizeof CommConfig;
    
        // COM port exists if GetDefaultCommConfig returns TRUE
        // or changes <size> to indicate COMMCONFIG buffer too small.
        return (GetDefaultCommConfig( buffer, &CommConfig, &size)
                                                        || size > sizeof CommConfig);
    }
    
    int main()
    {
        int i;
    
        for (i = 1; i < 256; ++i)
        {
            if (COM_exists( i))
            {
                printf( "COM%d exists\n", i);
            }
        }
    
        return 0;
    }
    

    Это определенно довольно поздно, но это оказалось полезным для меня!

    http: / /eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/

    В частности, этот пример:

    import re
    
    def full_port_name(portname):
        """ Given a port-name (of the form COM7,
            COM12, CNCA0, etc.) returns a full
            name suitable for opening with the
            Serial class.
        """
        m = re.match('^COM(\d+), portname)
        if m and int(m.group(1)) < 10:
        return portname
    return '\\\\.\\' + portname
    

    В настоящее время в дистрибутиве pyserial есть пример, который называется scanwin32.py

    http://pyserial.sourcearchive.com/documentation/2.5/scanwin32_8py_source.html

    Я думаю, что WMI - это правильный путь, поскольку он довольно прост в освоении и содержит минимум кода.Это избавляет вас от необходимости копаться в реестре и дает некоторую гарантию того, что в будущем это будет работать для более общих ситуаций.

    Вы можете установить все необходимое с помощью pip install pypiwin32 WMI и это работает "из коробки".

    Код

    import wmi
    
    query = "SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM%)'"
    coms  = wmi.WMI().query(query)
    
    for com in coms:
        print(com.Name)
    

    Выходной сигнал

    Communications Port (COM1)
    mbed Serial Port (COM3)
    mbed Serial Port (COM5)
    

    Я предполагаю, что ваш последовательный порт - это что-то вроде Plug 'n Play, так что это должно работать нормально.По какой - то причине Win32_SerialPort работает не для всех портов.

    В настоящее время для этого есть однострочник Powershell.

    [System.IO.Ports.SerialPort]::GetPortNames()
    
    scroll top