web-dev-qa-db-fra.com

Comment obtenir une liste des ports série disponibles dans Win32?

J'ai un code hérité qui fournit une liste des ports COM disponibles sur le PC en appelant la fonction EnumPorts() puis en filtrant les noms de port commençant par "COM".

À des fins de test, il serait très utile si je pouvais utiliser ce code avec quelque chose comme com0com , qui fournit des paires de ports COM virtuels en boucle comme un modem nul.

Cependant les ports com0com ne sont pas trouvés par la fonction EnumPorts() (même sans filtrage pour "COM"). HyperTerminal et SysInternals PortMon peuvent tous les deux les voir, donc je suis sûr qu'il est installé correctement.

Y a-t-il donc une autre fonction Win32 qui fournit une liste définitive des ports série disponibles?

49
GrahamS

Le EnumSerialPorts v1.2 suggéré par Nick D utilise neuf différentes méthodes pour lister les ports série! Nous ne sommes certainement pas à court de choix, bien que les résultats semblent varier.

Pour sauver les autres, je vais les énumérer ici et indiquer leur succès dans la recherche du com0com ports sur mon PC (XP Pro SP2):

  1. CreateFile ("COM" + 1-> 255) comme suggéré par Wael Dalloul
    ✔ Les ports com0com trouvés ont pris 234 ms.

  2. QueryDosDevice ()
    ✔ Les ports com0com trouvés ont pris 0 ms.

  3. GetDefaultCommConfig ("COM" + 1-> 255)
    ✔ Les ports com0com trouvés ont pris 235 ms.

  4. "SetupAPI1" à l'aide d'appels à SETUPAPI.DLL
    ✔ Les ports com0com trouvés, également signalés comme "noms conviviaux", ont pris 15 ms.

  5. "SetupAPI2" à l'aide d'appels à SETUPAPI.DLL
    ✘ N'a pas trouvé de ports com0com, a signalé des "noms conviviaux", a pris 32 ms.

  6. EnumPorts ()
    ✘ Signalé certains ports non COM, n'a pas trouvé de ports com0com, a pris 15 ms.

  7. Utilisation d'appels WMI
    ✔ Les ports com0com trouvés, également signalés comme "noms conviviaux", ont pris 47 ms.

  8. Base de données COM utilisant des appels à MSPORTS.DLL
    ✔/✘ Signalé que certains ports non COM, trouvé des ports com0com, ont pris 16 ms.

  9. Itérer sur la clé de registre HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM
    ✔ Les ports com0com trouvés ont pris 0 ms. C'est apparemment ce que SysInternals PortMon utilise.

Sur la base de ces résultats, je pense que la méthode WMI convient probablement le mieux à mes besoins car elle est relativement rapide et en prime, elle donne également des noms conviviaux (par exemple, "Communications Port (COM1)", "com0com - émulateur de port série").

76
GrahamS

Il semble que ce ne soit pas une tâche simple.

Vérifiez ceci: EnumSerialPorts v1.2

11
Nick Dandoulakis

vous pouvez faire une boucle par exemple de 1 à 50 et essayer d'ouvrir chaque port. Si le port est disponible, l'ouverture fonctionnera. Si le port est utilisé, vous obtiendrez une erreur de partage. Si le port n'est pas installé, vous obtiendrez une erreur de fichier introuvable.

pour ouvrir le port, utilisez CreateFile API:

HANDLE Port = CreateFile(
                  "\\\\.\\COM1",
                  GENERIC_READ | GENERIC_WRITE,
                  0,
                  NULL,
                  OPEN_EXISTING,
                  FILE_ATTRIBUTE_NORMAL,
                  NULL);

puis vérifiez le résultat.

5
Wael Dalloul

J'ai réorganisé PJ Naughter's EnumSerialPorts comme des formes plus portables et individuelles, c'est plus utile.

Pour une meilleure compatibilité, j'utilise C, au lieu de C++.

Si vous en avez besoin ou êtes intéressé, veuillez visiter le post dans mon blogueur.

1
Gaiger Chen

Dans mon cas, j'ai besoin à la fois des noms complets et des adresses de port COM. J'ai des ports série physiques, des ports série USB et des ports série virtuels com0com.

Comme le suggère la réponse acceptée, j'utilise les appels WMI. SELECT * FROM Win32_PnPEntity rechercher tous les appareils. Il renvoie des périphériques physiques comme celui-ci, et l'adresse peut être analysée à partir de Caption:

Serial Port for Barcode Scanner (COM13)

Cependant, pour les ports com0com Caption est comme ceci (pas d'adresse):

com0com - serial port emulator

SELECT * FROM Win32_SerialPort renvoie les adresses (DeviceID), ainsi que les noms complets (Name). Cependant, il ne trouve que les ports série physiques et les ports com0com, pas les ports série USB.

Donc au final, j'ai besoin de deux appels WMI: SELECT * FROM Win32_SerialPort (l'adresse est DeviceID) et SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM%' (l'adresse peut être analysée à partir de Caption). J'ai réduit le Win32_PnPEntity appeler, car il n'a besoin que de rechercher des périphériques qui n'ont pas été trouvés lors du premier appel.

1
Ville-Valtteri