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

2022-01-18 00:00:00 windows serial-port java device-driver

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

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.

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

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.

这可以在 Java 中轻松完成吗?(我会对任何支持此功能的第 3 方 Java 库感兴趣.)否则,我如何开始通过 win32 API 完成此操作?

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?

推荐答案

我通过使用 David 在 WinRegistry 类实现了我想要的/questions/62289/read-write-to-windows-registry-using-java">this SO question 从与我的 USB 设备关联的注册表项中获取 FriendlyName.然后我从友好名称中解析出 COM 号.

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.

需要考虑的一些事项:

  1. USB 设备位于注册表中的 HKEY_LOCAL_MACHINESYSTEMCurrentControlSetEnumUSB(在 WinXP、Win7 上测试.)

  1. USB devices are located at HKEY_LOCAL_MACHINESYSTEMCurrentControlSetEnumUSB in the registry (tested on WinXP, Win7.)

我需要设备 VID + PID 来识别正确的设备密钥(例如 VID_xxxx&PID_xxxx.)由于 VID 和 PID 是特定于设备的,因此该密钥应该在多个系统中是可靠的.

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.

VID_xxxx&PID_xxxx 键包含另一个带有设备值的子键.我在使用 WinRegistry 枚举子键时遇到了一些麻烦,因此我在开发过程中将子键名称硬编码为快速破解.更安全的解决方案是搜索子键以找到正确的名称.

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.

无论设备当前是否连接,设备密钥都存在于注册表中.此代码假设如果设备重新连接到不同的 COM 端口,Windows 将更新 FriendlyName.我尚未对此进行验证,但在使用测试期间情况看起来不错.

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.

示例

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

相关文章