Question

J'ai un modem GSM connecté via USB. Le modem crée 2 ports série. Le premier est automatiquement connecté au modem, le second apparaît dans le Gestionnaire de périphériques comme suit: "HUAWEI Mobile Connect - Interface d'interface utilisateur 3G pour PC (COM6)"

Le deuxième port est utilisé pour obtenir des informations vitales du modem, telles que la qualité du signal; envoyer et recevoir des messages texte; et une foule d'autres fonctions.

Je suis en train d’écrire une application qui résumera certaines des fonctionnalités fournies par le deuxième port. Ce dont j'ai besoin, c'est d'une méthode infaillible d'identification du port COM disponible. Itérer les ports et vérifier une réponse à " ATE0 " c'est insuffisant. Le port du modem est généralement celui dont le numéro est le plus petit et, lorsqu'une connexion par numérotation n'est pas active, il répondra à "ATE0". identique au deuxième port.

Ce que je pensais faire est de réitérer les ports et de vérifier leur nom convivial, comme indiqué dans le Gestionnaire de périphériques. Ainsi, je peux relier le port de mon application au port intitulé "HUAWEI Mobile Connect - Interface d'interface utilisateur 3G (COM6)". dans le Gestionnaire de périphériques. Je n'ai tout simplement pas trouvé d'informations qui me permettraient d'obtenir ce nom par programmation.

Était-ce utile?

La solution

Il y a longtemps, j'ai écrit un utilitaire destiné à un client, mais uniquement à un GPS plutôt qu'à un modem.

Je viens de le regarder, et les éléments qui jaillissent comme pouvant être utiles sont:

    GUID guid = GUID_DEVCLASS_PORTS;

SP_DEVICE_INTERFACE_DATA interfaceData;
ZeroMemory(&interfaceData, sizeof(interfaceData));
interfaceData.cbSize = sizeof(interfaceData);

SP_DEVINFO_DATA devInfoData;
ZeroMemory(&devInfoData, sizeof(devInfoData));
devInfoData.cbSize = sizeof(devInfoData);

if(SetupDiEnumDeviceInfo(
    hDeviceInfo,            // Our device tree
    nDevice,            // The member to look for
    &devInfoData
    ))
{
    DWORD regDataType;

    BYTE hardwareId[300];
    if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), NULL))
    {
...

(Vous appelez ce bit dans une boucle avec nDevice incrémenté)

et ensuite

BYTE friendlyName[300];
        if(SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, friendlyName, sizeof(friendlyName), NULL))
        {
            strFriendlyNames += (LPCTSTR)friendlyName;
            strFriendlyNames += '\n';
        }

qui trouve le nom du périphérique.

J'espère que cela vous aidera dans la bonne direction.

Autres conseils

Une fois que vous avez déterminé qu'un périphérique de port série est celui que vous souhaitez (en regardant son nom convivial, en vérifiant son périphérique parent, etc.), la méthode appropriée pour obtenir le nom du port serait probablement:

  • invoque SetupDiOpenDevRegKey (hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) pour obtenir le HKEY vers la clé de périphérique appelée
  • interrogez cette clé de registre pour la valeur REG_SZ "Nom du port" et
  • n'oubliez pas de fermer HKEY :)

Cependant, cela pourrait nécessiter beaucoup d'interopérabilité en C #, ce n'est même pas drôle, alors je ne vous en veux pas si vous vous en tenez à la solution d'analyse syntaxique des chaînes.

Les informations publiées par Will Dean ont été des plus utiles. C'est le code qui a finalement fonctionné pour moi. Tout dans la classe PInvoke a été repris intégralement de http://www.pinvoke.net . Je devais changer un type de données ici ou là pour que cela fonctionne (comme si vous utilisiez un enum au lieu d'un uint), mais cela devrait être facile à comprendre.

internal static string GetComPortByDescription(string Description)
{
    string Result = string.Empty;
    Guid guid = PInvoke.GUID_DEVCLASS_PORTS;
    uint nDevice = 0;
    uint nBytes = 300;
    byte[] retval = new byte[nBytes];
    uint RequiredSize = 0;
    uint PropertyRegDataType = 0;

    PInvoke.SP_DEVINFO_DATA devInfoData = new PInvoke.SP_DEVINFO_DATA();
    devInfoData.cbSize = Marshal.SizeOf(typeof(PInvoke.SP_DEVINFO_DATA));

    IntPtr hDeviceInfo = PInvoke.SetupDiGetClassDevs(
        ref guid, 
        null, 
        IntPtr.Zero, 
        PInvoke.DIGCF.DIGCF_PRESENT);

    while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData))
    {
        if (PInvoke.SetupDiGetDeviceRegistryProperty(
                hDeviceInfo, 
                ref devInfoData, 
                PInvoke.SPDRP.SPDRP_FRIENDLYNAME,
                out PropertyRegDataType, 
                retval, 
                nBytes, 
                out RequiredSize))
        {
            if (System.Text.Encoding.Unicode.GetString(retval).Substring(0, Description.Length).ToLower() ==
                Description.ToLower())
            {
                string tmpstring = System.Text.Encoding.Unicode.GetString(retval);
                Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM"));
            } // if retval == description
        } // if (PInvoke.SetupDiGetDeviceRegistryProperty( ... SPDRP_FRIENDLYNAME ...
    } // while (PInvoke.SetupDiEnumDeviceInfo(hDeviceInfo, nDevice++, ref devInfoData))

    PInvoke.SetupDiDestroyDeviceInfoList(hDeviceInfo);
    return Result;
}

Je pense que la ligne Result = tmpstring.Substring (tmpstring.IndexOf ("COM"), tmpstring.IndexOf (')') - tmpstring.IndexOf ("COM"), tmpstring.IndexOf (')' - tmpstring.IndexOf ("COM"), tmpstring.IndexOf (')'); est un peu maladroit, des suggestions sur la façon de le nettoyer seraient appréciées.

Merci de votre aide dans cette affaire Will, sans vous, je chercherais toujours sur Google.

La version C ++ basée sur la réponse @Will Dean.

#include <windows.h>
#include <initguid.h>
#include <devguid.h>
#include <setupapi.h>

void enumerateSerialPortsFriendlyNames()
{
    SP_DEVINFO_DATA devInfoData = {};
    devInfoData.cbSize = sizeof(devInfoData);

    // get the tree containing the info for the ports
    HDEVINFO hDeviceInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS,
                                               0,
                                               nullptr,
                                               DIGCF_PRESENT
                                               );
    if (hDeviceInfo == INVALID_HANDLE_VALUE)
    {
        return;
    }

    // iterate over all the devices in the tree
    int nDevice = 0;
    while (SetupDiEnumDeviceInfo(hDeviceInfo,            // Our device tree
                                 nDevice++,            // The member to look for
                                 &devInfoData))
    {
        DWORD regDataType;
        DWORD reqSize = 0;

        // find the size required to hold the device info
        SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize);
        BYTE* hardwareId = new BYTE[(reqSize > 1) ? reqSize : 1];
        // now store it in a buffer
        if (SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId) * reqSize, nullptr))
        {
            // find the size required to hold the friendly name
            reqSize = 0;
            SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize);
            BYTE* friendlyName = new BYTE[(reqSize > 1) ? reqSize : 1];
            // now store it in a buffer
            if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, friendlyName, sizeof(friendlyName) * reqSize, nullptr))
            {
                // device does not have this property set
                memset(friendlyName, 0, reqSize > 1 ? reqSize : 1);
            }
            // use friendlyName here
            delete[] friendlyName;
        }
        delete[] hardwareId;
    }
}

Heureux cela a fonctionné.

Vous pouvez essayer:

Regex.Match (tmpstring, @ "COM \ s \ d +"). ToString ()

pour votre correspondance de chaîne.

En tant que points de style .NET, j’ajouterais un "using System.Text", et je ne commencerais pas les noms de variables locales par des majuscules, et si je me sentais vraiment vertueux, je mettrais probablement SetupDiDestroyDeviceInfoList dans un finally {} clause.

Utiliser la méthode publiée par LiGenChen . La méthode ComPortSetupAPISetupDiClassGuids a donné le meilleur temps et un nom convivial.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top