2008-11-20 29 views
12

Tengo un módem GSM conectado a través de USB. El módem crea 2 puertos serie. La primera se adjunta automáticamente al módem, la segunda muestra en el Administrador de dispositivos como "HUAWEI Mobile Connect - 3G PC UI (interfaz COM6)"¿Cómo obtengo el nombre descriptivo de un puerto COM en Windows?

el segundo puerto se utiliza para obtener información vital del módem, tales como la calidad de la señal ; para enviar y recibir mensajes de texto; y toda una serie de otras funciones.

Estoy escribiendo una aplicación que resumirá algunas de las características proporcionadas por el segundo puerto. Lo que necesito es un método seguro para identificar qué puerto COM es el de repuesto. Iterar los puertos y verificar una respuesta a "ATE0" no es suficiente. El puerto del módem suele ser el número más bajo, y cuando una conexión de acceso telefónico no está activa, responderá a "ATE0" igual que el segundo puerto.

Lo que estaba pensando hacer es repetir los puertos y verificar su nombre descriptivo, como se muestra en el Administrador de dispositivos. De esa forma puedo vincular el puerto de mi aplicación al puerto etiquetado como "HUAWEI Mobile Connect - Interfaz de interfaz de usuario de PC 3G (COM6)" en el Administrador de dispositivos. Todavía no he encontrado ninguna información que me permita obtener ese nombre programáticamente.

Respuesta

7

Hace mucho tiempo escribí una utilidad para que un cliente hiciera solo esto, pero para un GPS en lugar de un módem.

Acabo de mirar en él, y los bits que saltan de salida como posiblemente útiles son:

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

(se llama a este bit en un bucle con el incremento nDevice)

y luego

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

que encuentra el nombre del dispositivo.

Espero que eso te ayude en la dirección correcta.

+0

Esto parece que podría hacer el truco. Estoy escribiendo una prueba en este momento. Gracias a un millón :) – RichieACC

2

La información publicada por Will Dean fue de lo más útil. Este es el código que finalmente funcionó para mí. Todo en la clase PInvoke fue tomado textualmente del http://www.pinvoke.net. Tuve que cambiar un tipo de datos aquí o allá para que funcione (como cuando se usa una enumeración en lugar de una uint) pero debería ser fácil de descifrar.

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

creo que la línea Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); es un poco torpe, sugerencias sobre cómo limpiarlo sería apreciada.

Gracias por su ayuda con este asunto Will, sin usted, todavía estaría buscando en Google.

1

Me alegro de que funcionó.

usted podría intentar:

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

para su correspondencia de cadenas..

Como puntos de estilo .NET, agregaría un "using System.Text", y no comenzaría nombres de variables locales con mayúsculas, y si me sintiera realmente virtuoso, probablemente pondría SetupDiDestroyDeviceInfoList en una finalmente {} cláusula.

+0

La expresión regular se ve más elegante. Una cosa que tuve que cambiar fue: "COM \ s? \ D +" No siempre habrá espacios en blanco entre COM y el número, por lo que debe coincidir con 0 o más. Gracias de nuevo. – RichieACC

3

Después de determinar un dispositivo de puerto serie es el que usted desea (mirando su nombre descriptivo, mediante la comprobación de su dispositivo principal, etc.), la forma correcta de obtener el nombre del puerto, probablemente sería:

  • invocar SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) para obtener el HKEY al dispositivo denominada clave
  • consulta esta clave de registro para el valor REG_SZ "PortName"
  • no se olvide de cerrar la HKEY :)

Sin embargo, esto podría requerir tanta interoperabilidad en C# que ni siquiera es gracioso, así que no te culpo si sigues con la solución de análisis de cadenas.

0

Se utilizó el método publicado por LiGenChen. El método ComPortSetupAPISetupDiClassGuids dio el mejor nombre de tiempo y fácil de usar.

+0

Sería útil si modificó su respuesta con información más relevante del enlace – Hambone

1

La versión de C++ basada en la respuesta @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[reqSize > 1 ? reqSize : 1]; 
     // now store it in a buffer 
     if (SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_HARDWAREID, &regDataType, hardwareId, sizeof(hardwareId), nullptr)) 
     { 
      // find the size required to hold the friendly name 
      reqSize = 0; 
      SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, nullptr, 0, &reqSize); 
      BYTE friendlyName[reqSize > 1 ? reqSize : 1]; 
      // now store it in a buffer 
      if (!SetupDiGetDeviceRegistryProperty(hDeviceInfo, &devInfoData, SPDRP_FRIENDLYNAME, nullptr, friendlyName, sizeof(friendlyName), nullptr)) 
      { 
       // device does not have this property set 
       memset(friendlyName, 0, reqSize > 1 ? reqSize : 1); 
      } 
      // use friendlyName here 
     } 
    } 
} 
Cuestiones relacionadas