Pergunta

Eu tenho um modem GSM conectado via USB. O modem cria 2 portas série. O primeiro é automaticamente conectado ao modem, a segunda mostra no Gerenciador de dispositivos como "HUAWEI Mobile Connect - 3G PC UI (Interface COM6)"

A segunda porta é usado para obter informações vitais do modem, tais como a qualidade do sinal; para enviar e receber mensagens de texto; e toda uma série de outras funções.

Eu estou escrevendo um aplicativo que vai encerrar alguns dos recursos fornecidos pela segunda porta. O que eu preciso é um método certo fogo de identificar qual a porta COM é a reposição. Iteração as portas e verificar a resposta ao "ATE0" não é suficiente. porta do modem é geralmente o mais baixo numeradas um, e quando uma conexão dial-up não está ativo, ele irá responder com "ATE0" o mesmo que o segundo porto.

O que eu estava pensando em fazer é reiterar as portas e verificar seu nome amigável, como mostra em Gerenciador de Dispositivos. Dessa forma eu posso ligar o porto na minha candidatura à porta identificada como "HUAWEI Mobile Connect - 3G PC UI (Interface COM6)" no Gerenciador de dispositivos. Eu só não encontrei qualquer informação que permita-me para obter esse nome através de programação.

Foi útil?

Solução

Há muito tempo atrás eu escrevi um utilitário para um cliente para fazer exatamente isso, mas para um GPS em vez de um modem.

Eu apenas olhei para ele, e bits que jump-se como sendo possivelmente úteis são:

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

(Você chama isso de pouco em um loop com incremento nDevice)

e

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

que encontra o nome do dispositivo.

Esperemos que irá ajudá-lo na direção certa.

Outras dicas

Depois de determinar um dispositivo de porta serial é o que você quer (por olhar para o seu nome amigável, verificando seu dispositivo pai etc.), a maneira correta de obter o nome do porto provavelmente seria:

  • invoke SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) para obter o HKEY a chave do dispositivo chamado
  • consulta esta chave de registo para o valor REG_SZ "PortName"
  • não se esqueça de fechar a HKEY:)

No entanto, isto pode exigir muito de interoperabilidade em C # não é mesmo engraçado, então eu não culpo você se você mantenha-se à solução seqüência de análise.

As informações postadas por Will Dean foi mais útil. Este é o código que eventualmente trabalhou para mim. Tudo na classe PInvoke foi tirado diretamente http://www.pinvoke.net . Eu tive que mudar um tipo de dados aqui ou ali para fazê-lo funcionar (como quando se usa um enum em vez de um uint), mas deve ser fácil de descobrir.

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

Eu acho que o Result = tmpstring.Substring(tmpstring.IndexOf("COM"),tmpstring.IndexOf(')') - tmpstring.IndexOf("COM")); linha é um pouco desajeitado, sugestões sobre como limpá-lo seria apreciada.

Obrigado por sua ajuda com este assunto Will, sem você, eu ainda estaria em busca google.

A C ++ versão com base na resposta @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;
    }
}

Fico feliz que funcionou.

Você pode tentar:

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

para sua correspondência string.

pontos estilo como .NET, eu adicionar um "usando System.Text", e eu não iria começar nomes de variáveis ??locais com capitais, e se eu estava me sentindo muito virtuosa, eu provavelmente iria colocar o SetupDiDestroyDeviceInfoList num finalmente {} cláusula.

Usado o método publicado por LiGenChen . Os ComPortSetupAPISetupDiClassGuids método deu o melhor tempo e nome amigável.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top