windows 获取与 COM 端口相关的设备/驱动程序信息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6362775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting device/driver information related to a COM port?
提问by Rob
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.
我在 Windows 设备管理器中有一个带有类似名称的设备驱动程序的串行转 USB 设备。这些设备在系统启动时并不总是获取相同的 COM 端口,因此我的程序需要在启动时识别它。
I've tried using RXTXto 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.
我曾尝试使用RXTX枚举系统上的 COM 端口,但这不起作用,因为CommPortIdentifier.getName()
仅返回 COM 名称(例如 COM1、COM2 等)我需要获取驱动程序制造商名称或驱动程序显示在设备管理器中的名称,并将其与 COM 名称相关联。
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?
这可以在 Java 中轻松完成吗?(我会对支持此功能的任何 3rd 方 Java 库感兴趣。)否则,我如何开始通过 win32 API 完成此操作?
回答by Rob
I achieved what I wanted by using the WinRegistry
class provided by David in this SO questionto obtain the FriendlyNamefrom registry key associated with my USB device. I then parse out the COM number from the friendly name.
我通过使用WinRegistry
David 在这个 SO 问题中提供的类从与我的 USB 设备关联的注册表项中获取FriendlyName来实现我想要的。然后我从友好名称中解析出 COM 编号。
Some things to consider:
需要考虑的一些事项:
USB devices are located at
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\
in the registry (tested on WinXP, Win7.)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.The
VID_xxxx&PID_xxxx
key contains another sub-key with device values. I had some trouble enumerating the sub-keys withWinRegistry
, 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.The device keys exist in the registry regardless of whether the device is currently connected. This code makes the assumption that Windows will update FriendlyNameif the device is reconnected to a different COM port. I haven't verified this, but things looked good during use-testing.
USB 设备位于
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\
注册表中(在 WinXP、Win7 上测试。)我需要设备 VID + PID 来识别正确的设备密钥(例如
VID_xxxx&PID_xxxx
。)由于 VID 和 PID 是特定于设备的,因此该密钥在多个系统中应该是可靠的。该
VID_xxxx&PID_xxxx
键包含另一个带有设备值的子键。我在使用 枚举子键时遇到了一些麻烦WinRegistry
,因此我在开发过程中将子键名称硬编码为快速破解。更安全的解决方案是搜索子键以找到正确的名称。无论设备当前是否已连接,设备密钥都存在于注册表中。此代码假设如果设备重新连接到不同的 COM 端口,Windows 将更新FriendlyName。我还没有验证这一点,但在使用测试期间看起来不错。
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;
}
回答by likejudo
@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:
@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)));
}
}
Update: I don't think these are solutions. Why? This information is statically stored in the registry - even when the device is not connected.
更新:我不认为这些是解决方案。为什么?此信息静态存储在注册表中 - 即使设备未连接。
回答by ZiglioUK
Great example, using JNA, here. The author (Geir Arne Ruud) has released it under Public Domain License.
很好的例子,在这里使用 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;
}