Je recherche un moyen robuste de répertorier les ports série (COM) disponibles sur une machine Windows. Il y a ce post sur l'utilisation de WMI , mais je voudrais quelque chose de moins spécifique à .NET - je veux obtenir la liste des ports dans un Python ou un programme C++, sans .NET.
Je connais actuellement deux autres approches:
Lire les informations dans le HARDWARE\\DEVICEMAP\\SERIALCOMM
clé d'enregistrement. Cela ressemble à une excellente option, mais est-il robuste ? Je ne trouve pas de garantie en ligne ou dans MSDN que cette cellule de registre contient en effet toujours la liste complète des ports disponibles.
Essayez d'appeler CreateFile
sur COMN
avec N un nombre de 1 à quelque chose. Ce n'est pas suffisant, car certains ports COM ne sont pas nommés COMN. Par exemple, certains ports COM virtuels créés sont nommés CSNA0, CSNB0, etc., donc je ne compterais pas sur cette méthode.
Avez-vous d'autres méthodes/idées/expériences à partager?
Edit: au fait, voici une simple implémentation Python de lecture des noms de port depuis 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
Plusieurs options sont disponibles:
Appelez QueryDosDevice avec un lpDeviceName NULL pour répertorier tous les périphériques DOS. Ensuite, utilisez CreateFile et GetCommConfig avec chaque nom de périphérique tour à tour pour déterminer s'il s'agit d'un port série.
Appelez SetupDiGetClassDevs avec un ClassGuid de GUID_DEVINTERFACE_COMPORT.
Il y a une conversation sur le groupe de discussion win32 et un CodeProject, euh, projet .
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 couple de solutions .
Je viens de créer ce qui suit, basé sur la lecture de la source C++ dans EnumSerialPorts et sur la fonction GetDefaultCommConfig()
. Cela ressemblait à la méthode la plus simple utilisant un simple C ANSI et un seul appel d'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 certainement 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
De nos jours, il existe une doublure Powershell pour cela.
[System.IO.Ports.SerialPort]::GetPortNames()
Il y a maintenant un exemple dans la distribution physique qui fait cela appelé scanwin32.py
http://pyserial.sourcearchive.com/documentation/2.5/scanwin32_8py_source.html
Je pense que WMI est le chemin à parcourir car il est assez facile de démarrer et il a un code minimal. Il vous évite d'avoir à creuser dans le registre et vous donne une garantie qu'il fonctionnera pour des situations plus générales à l'avenir.
Vous pouvez installer tout le nécessaire avec pip install pypiwin32 WMI
et cela fonctionne tout de suite.
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 & Play, cela devrait donc fonctionner correctement. Pour certaines raisons Win32_SerialPort
ne fonctionne pas pour tous les ports.