Domanda

Ho un modem GSM collegato tramite USB. Il modem crea 2 porte seriali. Il primo viene automaticamente collegato al modem, il secondo viene visualizzato in Gestione dispositivi come "HUAWEI Mobile Connect - Interfaccia UI PC 3G (COM6)"

La seconda porta viene utilizzata per ottenere informazioni vitali dal modem, come la qualità del segnale; per inviare e ricevere messaggi di testo; e tutta una serie di altre funzioni.

Sto scrivendo un'applicazione che racchiuderà alcune delle funzionalità fornite dalla seconda porta. Quello di cui ho bisogno è un metodo sicuro per identificare quale porta COM è quella di riserva. Iterazione delle porte e controllo di una risposta a "ATE0" non è sufficiente. La porta del modem è in genere quella con il numero più basso e quando una connessione remota non è attiva, risponderà a "ATE0". lo stesso della seconda porta.

Quello che stavo pensando di fare è iterare le porte e controllare il loro nome descrittivo, come mostra Device Manager. In questo modo posso collegare la porta della mia applicazione alla porta etichettata "HUAWEI Mobile Connect - Interfaccia UI PC 3G (COM6)" in Gestione dispositivi. Non ho ancora trovato alcuna informazione che mi permetta di ottenere quel nome a livello di codice.

È stato utile?

Soluzione

Molto tempo fa ho scritto un'utilità per un client per fare proprio questo, ma per un GPS piuttosto che un modem.

L'ho appena visto, e i bit che saltano fuori come forse utili sono:

    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))
    {
...

(questo bit viene chiamato in un ciclo con incremento di nDevice)

e poi

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

che trova il nome del dispositivo.

Speriamo che ti possa aiutare nella giusta direzione.

Altri suggerimenti

Dopo aver determinato un dispositivo con porta seriale è quello desiderato (guardando il suo nome descrittivo, controllando il suo dispositivo padre ecc.), il modo corretto per ottenere il nome della porta sarebbe probabilmente:

  • invoca SetupDiOpenDevRegKey (hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) per ottenere HKEY sulla cosiddetta chiave del dispositivo
  • interroga questa chiave di registro per il REG_SZ valore " PortName "
  • non dimenticare di chiudere HKEY :)

Tuttavia, questo potrebbe richiedere così tanto interoperabilità in C #, non è nemmeno divertente, quindi non ti biasimo se rimani sulla soluzione di analisi delle stringhe.

Le informazioni pubblicate da Will Dean sono state di grande aiuto. Questo è il codice che alla fine ha funzionato per me. Tutto nella classe PInvoke è stato preso alla lettera da http://www.pinvoke.net . Ho dovuto cambiare un tipo di dati qui o là per farlo funzionare (come quando si utilizza un enum anziché un uint) ma dovrebbe essere facile da capire.

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;
}

Penso che la riga Risultato = tmpstring.Substring (tmpstring.IndexOf (" COM "), tmpstring.IndexOf (')') - tmpstring.IndexOf (" COM ")); è un po 'goffo, i suggerimenti su come ripulirlo sarebbero apprezzati.

Grazie per il tuo aiuto in questa faccenda Will, senza di te, starei ancora cercando su Google.

La versione C ++ basata sulla risposta @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;
    }
}

Sono contento che abbia funzionato.

Potresti provare:

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

per la corrispondenza delle stringhe.

Come indica lo stile .NET, aggiungerei un " usando System.Text " ;, e non inizierei i nomi delle variabili locali con le maiuscole e, se mi sentissi veramente virtuoso, probabilmente inserirei SetupDiDestroyDeviceInfoList in un infine la clausola {}.

Utilizzato il metodo pubblicato da LiGenChen . Il metodo ComPortSetupAPISetupDiClassGuids ha dato il miglior tempo e il nome descrittivo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top