Вопрос

У меня есть GSM-модем, подключенный через USB.Модем создает 2 последовательных порта.Первый автоматически подключается к модему, второй отображается в диспетчере устройств как «HUAWEI Mobile Connect — 3G PC UI Interface (COM6)».

Второй порт используется для получения важной информации от модема, например, о качестве сигнала;отправлять и получать текстовые сообщения;и целый ряд других функций.

Я пишу приложение, которое реализует некоторые функции второго порта.Что мне нужно, так это надежный метод определения того, какой COM-порт является запасным.Перебора портов и проверки ответа на «ATE0» недостаточно.Порт модема обычно имеет меньший номер, и когда коммутируемое соединение не активно, он будет реагировать на «ATE0» так же, как и второй порт.

Я думал о том, чтобы перебрать порты и проверить их понятное имя, как оно отображается в диспетчере устройств.Таким образом, я могу связать порт в своем приложении с портом с надписью «HUAWEI Mobile Connect — 3G PC UI Interface (COM6)» в диспетчере устройств.Я просто еще не нашел никакой информации, которая позволила бы мне получить это имя программно.

Это было полезно?

Решение

Давным-давно я написал утилиту для клиента, которая делает именно это, но для GPS, а не для модема.

Я только что посмотрел на это, и некоторые из них, которые могут оказаться полезными:

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

(этот бит вызывается в цикле с увеличением nDevice)

а затем

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

который находит имя устройства.

Надеюсь, это поможет вам в правильном направлении.

Другие советы

После того, как вы определите, что устройство с последовательным портом является тем, которое вам нужно (посмотрев на его понятное имя, проверив его родительское устройство и т. д.), правильный способ получить имя порта, вероятно, будет следующим:

  • вызывать SetupDiOpenDevRegKey(hDevInfo, devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) чтобы получить HKEY к так называемому ключу устройства
  • запросите этот ключ реестра для REG_SZ значение «ИмяПорта»
  • не забудь закрыть HKEY :)

Однако для этого может потребоваться столько взаимодействия с C#, что это даже не смешно, поэтому я не виню вас, если вы придерживаетесь решения по синтаксическому анализу строк.

Информация, размещенная Уиллом Дином , оказалась наиболее полезной. Это код, который в итоге сработал для меня. Все в классе PInvoke было взято дословно из http://www.pinvoke.net . Мне пришлось изменить тип данных здесь или там, чтобы он работал (например, при использовании enum вместо uint), но это должно быть легко выяснить.

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

Я думаю, что строка Result = tmpstring.Substring (tmpstring.IndexOf (" COM "), tmpstring.IndexOf (')') - tmpstring.IndexOf (" COM ")); немного неуклюже, предложения о том, как его почистить, будут оценены.

Спасибо за вашу помощь в этом вопросе. Уилл, без вас я бы по-прежнему искал в Google.

Версия C ++, основанная на ответе @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;
    }
}

Рад, что это сработало.

Вы можете попробовать:

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

для вашего соответствия строк.

В качестве точек стиля .NET я бы добавил " с использованием System.Text " и не стал бы начинать имена локальных переменных с заглавных букв, и если бы я чувствовал себя действительно добродетельным, я бы, вероятно, поместил бы SetupDiDestroyDeviceInfoList в предложение finally {}.

scroll top