Liste des ports série (COM) sous Windows?
-
05-07-2019 - |
Question
Je recherche un moyen robuste d’énumérer les ports série (COM) disponibles sur une machine Windows. Il existe ce message sur l’utilisation de WMI , mais je voudrais quelque chose de moins spécifique à .NET - Je souhaite obtenir la liste des ports dans un programme Python ou C ++, sans .NET.
Je connais actuellement deux autres approches:
-
Lecture des informations contenues dans la clé de registre
HARDWARE \\ DEVICEMAP \\ SERIALCOMM
. Cela semble être une bonne option, mais est-il robuste ? Je ne trouve aucune garantie en ligne ou dans MSDN sur le fait que cette cellule de registre contient toujours la liste complète des ports disponibles. -
Essayez d'appeler
CreateFile
surCOMN
avec N un nombre compris entre 1 et quelque chose. Cela ne suffit pas, car certains ports COM ne sont pas nommés COMN. Par exemple, certains ports COM virtuels créés sont nommés CSNA0, CSNB0, etc., de sorte que je ne compterais pas sur cette méthode.
D'autres méthodes / idées / expériences à partager?
Modifier: au fait, voici une implémentation simple en Python consistant à lire les noms de port dans le registre:
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
La solution
Plusieurs options sont disponibles:
-
Appelez QueryDosDevice à l'aide de la touche NULL lpDeviceName pour répertorier tous les périphériques DOS. Ensuite, utilisez CreateFile et GetCommConfig avec chaque nom d'appareil dans tournez pour savoir s’il s’agit d’un port série.
-
Appelez SetupDiGetClassDevs avec un ClassGuid de GUID_DEVINTERFACE_COMPORT.
Il y a une conversation à propos du groupe de discussion win32 et un CodeProject, projet .
Autres conseils
Utilisation de pySerial avec Python:
import serial.tools.list_ports
ports = list(serial.tools.list_ports.comports())
for p in ports:
print p
Le projet PySerial fournit un deux solutions .
Je viens de créer ce qui suit, en lisant EnumSerialPorts dans la source C ++ et en consultant le fonction GetDefaultCommConfig ()
. Cela ressemblait à la méthode la plus simple utilisant le simple ANSI C et un seul appel API pour chaque port COM possible.
#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;
}
C’est bien assez tard, mais cela m’a été utile!
http: / /eli.thegreenplace.net/2009/07/31/listing-all-serial-ports-on-windows-with-python/
En particulier cet exemple:
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
Il y a un exemple dans la distribution pyserial qui fait cela appelé scanwin32.py
http://pyserial.sourcearchive.com/documentation/2.5/scanwin32_8py_source.html
Je pense que WMI est la voie à suivre puisqu'il est assez facile de commencer et que le code est minimal. Cela vous évite d’avoir à creuser dans le registre et vous donne une garantie que cela fonctionnera pour des situations plus générales à l’avenir.
Vous pouvez installer tout ce dont vous avez besoin avec pip install pypiwin32 WMI
et tout fonctionne à l’origine.
Code
import wmi
query = "SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM%)'"
coms = wmi.WMI().query(query)
for com in coms:
print(com.Name)
Sortie
Communications Port (COM1)
mbed Serial Port (COM3)
mbed Serial Port (COM5)
Je suppose que votre port série est une sorte de Plug 'n Play, cela devrait donc fonctionner correctement. Pour une raison quelconque, Win32_SerialPort
ne fonctionne pas pour tous les ports.
De nos jours, il existe un one-liner Powershell pour cela.
[System.IO.Ports.SerialPort]::GetPortNames()