获取与 COM 端口相关的设备/驱动程序信息?

发布于 2024-11-15 15:01:08 字数 425 浏览 4 评论 0原文

我有一个串行转 USB 设备,在 Windows 设备管理器中具有类似名称的设备驱动程序。这些设备并不总是在系统启动时获取相同的 COM 端口,因此我的程序需要在启动时识别它。

我尝试使用 RXTX 枚举系统上的 COM 端口,但是这不起作用,因为 CommPortIdentifier.getName() 只是返回 COM 名称(例如 COM1、COM2 等)。我需要获取驱动程序制造商名称或驱动程序名称出现在设备管理器中,并将其与 COM 名称关联起来。

这可以用 Java 轻松完成吗? (我会对支持此功能的任何第三方 Java 库感兴趣。)否则,我如何开始通过 win32 API 来完成此任务?

I have a Serial-to-USB device with a similarly named device driver in the Windows device manager. The devices do not always grab the same COM port on system boot, so my program needs to identify it on start up.

I've tried using RXTX to enumerate the COM ports on the system, but this didn't work because CommPortIdentifier.getName() simply returns the COM name (eg. COM1, COM2, etc.) I need to acquire either the driver manufacturer name, or the driver name as it appears in the device manager, and associate it with the COM name.

Can this easily be done in Java? (I'd be interested in any 3rd party Java libraries that support this.) Otherwise, how I could begin to accomplish this via the win32 API?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

尸血腥色 2024-11-22 15:01:08

我通过使用 David 在 这个SO问题从与我的USB设备关联的注册表项获取FriendlyName。然后我从友好名称中解析出 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. 无论设备当前是否连接,设备密钥都存在于注册表中。此代码假设如果设备重新连接到不同的 COM 端口,Windows 将更新 FriendlyName。我尚未验证这一点,但在使用测试过程中情况看起来不错。

示例

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

I achieved what I wanted by using the WinRegistry class provided by David in this SO question to obtain the FriendlyName from registry key associated with my USB device. I then parse out the COM number from the friendly name.

Some things to consider:

  1. USB devices are located at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\ in the registry (tested on WinXP, Win7.)

  2. I required the device VID + PID to identify the correct device key (eg. VID_xxxx&PID_xxxx.) Since VID and PID are device specific, this key should be reliable across multiple systems.

  3. The VID_xxxx&PID_xxxx key contains another sub-key with device values. I had some trouble enumerating the sub-keys with WinRegistry, so I hard-coded the sub-key name as a quick hack during development. A much safer solution would search sub-keys to find the correct name.

  4. The device keys exist in the registry regardless of whether the device is currently connected. This code makes the assumption that Windows will update FriendlyName if the device is reconnected to a different COM port. I haven't verified this, but things looked good during use-testing.

Example

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

Code

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;
}   
逐鹿 2024-11-22 15:01:08

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

更新:我不认为这些是解决方案。为什么?该信息静态存储在注册表中 - 即使设备未连接。

@robjb Your code does not allow for more than one device to be connected. How will the user know the device name? I added to your code thus to return a list of com ports:

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

Update: I don't think these are solutions. Why? This information is statically stored in the registry - even when the device is not connected.

静赏你的温柔 2024-11-22 15:01:08

很好的例子,使用 JNA, 这里
作者 (Geir Arne Ruud) 在公共领域许可下发布了它。

我的示例代码

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

Great example, using JNA, here.
The author (Geir Arne Ruud) has released it under Public Domain License.

My example code

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文