Получение информации об устройстве / драйвере, связанной с COM-портом? - PullRequest
10 голосов
/ 15 июня 2011

У меня есть устройство Serial-to-USB с одноименным драйвером устройства в диспетчере устройств Windows. Устройства не всегда захватывают один и тот же COM-порт при загрузке системы, поэтому моя программа должна определить его при запуске.

Я пытался использовать RXTX для перечисления COM-портов в системе, но это не сработало, потому что CommPortIdentifier.getName() просто возвращает имя COM (например, COM1, COM2 и т. Д.) I необходимо получить либо имя производителя драйвера, либо имя драйвера, как оно отображается в диспетчере устройств, и связать его с именем COM.

Может ли это быть легко сделано в Java? (Я был бы заинтересован в любых сторонних библиотеках Java, которые поддерживают это.) В противном случае, как я мог бы начать достигать этого через win32 API?

Ответы [ 3 ]

9 голосов
/ 16 июня 2011

Я достиг того, что хотел, используя класс WinRegistry, предоставленный Дэвидом в этом вопросе SO , чтобы получить FriendlyName из раздела реестра, связанного с моим USB-устройством. Затем я анализирую номер COM из понятного имени.

Некоторые вещи, которые следует учитывать:

  1. USB-устройства находятся в реестре HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\ (протестировано на WinXP, Win7.)

  2. Мне потребовалось, чтобы VID + PID устройства идентифицировал правильный ключ устройства (например, VID_xxxx&PID_xxxx.) Поскольку VID и PID зависят от устройства, этот ключ должен быть надежным во многих системах.

  3. Клавиша VID_xxxx&PID_xxxx содержит еще один подраздел с параметрами устройства. У меня были некоторые проблемы при перечислении подключей с помощью WinRegistry, поэтому я жестко закодировал имя подключа как быстрый взлом во время разработки. Гораздо более безопасное решение будет искать подключи, чтобы найти правильное имя.

  4. Ключи устройства существуют в реестре независимо от того, подключено ли устройство в данный момент. Этот код предполагает, что Windows обновит FriendlyName , если устройство будет повторно подключено к другому COM-порту. Я не проверял это, но все выглядело хорошо во время тестирования использования.

Пример * +1034 * String keyPath = "SYSTEM\\CurrentControlSet\\Enum\\USB\\Vid_067b&Pid_2303\\"; String device1 = "5&75451e6&0&1"; System.out.println("First COM device: " + getComNumber(keyPath + device1)); Код

import java.util.regex.Pattern;
import java.util.regex.Matcher;

// Given a registry key, attempts to get the 'FriendlyName' value
// Returns null on failure.
//
public static String getFriendlyName(String registryKey) {
    if (registryKey == null || registryKey.isEmpty()) {
        throw new IllegalArgumentException("'registryKey' null or empty");
    }
    try {
        int hkey = WinRegistry.HKEY_LOCAL_MACHINE;
        return WinRegistry.readString(hkey, registryKey, "FriendlyName");
    } catch (Exception ex) { // catch-all: 
        // readString() throws IllegalArg, IllegalAccess, InvocationTarget
        System.err.println(ex.getMessage());
        return null;
    }
}

// Given a registry key, attempts to parse out the integer after
// substring "COM" in the 'FriendlyName' value; returns -1 on failure.
//
public static int getComNumber(String registryKey) {
    String friendlyName = getFriendlyName(registryKey);

    if (friendlyName != null && friendlyName.indexOf("COM") >= 0) {
        String substr = friendlyName.substring(friendlyName.indexOf("COM"));
        Matcher matchInt = Pattern.compile("\\d+").matcher(substr);
        if (matchInt.find()) {
            return Integer.parseInt(matchInt.group());
        }
    }
    return -1;
}   
0 голосов
/ 30 июня 2015

Отличный пример, используя JNA, здесь . Автор (Geir Arne Ruud) выпустил его по лицензии Public Domain.

Мой пример кода

public static String getFriendlyName(GoGPSModel model, String name) 
{
   if(model.getSystem().getOSType() != OSType.Windows32 
   && model.getSystem().getOSType() != OSType.Windows64) {
      return name;
   }
   for (DeviceInformation devInfo : infoObjects) {
      System.out.println(devInfo.toString());
      String friendlyName = devInfo.getFriendlyName();
      if(friendlyName != null && !friendlyName.equals("") && friendlyName.contains(name)) {
         return devInfo.getManufacturer() + ": " + friendlyName;
      }
   }
   return name;
}
0 голосов
/ 12 марта 2013

@ robjb Ваш код не позволяет подключать более одного устройства.Как пользователь узнает имя устройства?Я добавил к вашему коду таким образом, чтобы получить список com-портов:

    ArrayList<String> subKeys = WinRegistry.readStringSubKeys(WinRegistry.HKEY_LOCAL_MACHINE, keyPath);
    ArrayList<Integer> comPorts = new ArrayList<Integer>();
    for (String subKey : subKeys) {
        String friendlyName = getFriendlyName(keyPath + subKey);
        if (friendlyName != null && friendlyName.contains("MyDriverName") && friendlyName.contains("COM")) {
            int beginIndex = friendlyName.indexOf("COM") + 3 /*length of 'COM'*/;
            int endIndex = friendlyName.indexOf(")");
            comPorts.add(Integer.parseInt(friendlyName.substring(beginIndex, endIndex)));
        }
    }

Обновление: я не думаю, что это решения.Зачем?Эта информация статически хранится в реестре - даже если устройство не подключено.

...