我有一个串行到USB设备,在Windows设备管理器中有一个类似命名的设备驱动程序。设备并不总是在系统启动时获取相同的COM端口,因此我的程序需要在启动时识别它。
我尝试使用RXTX枚举系统上的COM端口,但这不起作用,因为CommPortIdentifier.getName()
只返回COM名称(例如COM1,COM2等)我需要获取驱动程序制造商名称或设备管理器中显示的驱动程序名称,并将其与COM名称关联。
这可以用Java轻松完成吗? (我对任何支持这种情况的第三方Java库感兴趣。)否则,我如何通过win32 API开始实现这一目标?
答案 0 :(得分:8)
我使用David在this SO question中提供的WinRegistry
类来实现我想要的功能,以便从与我的USB设备关联的注册表项中获取 FriendlyName 。然后我从友好名称解析出COM号码。
需要考虑的一些事项:
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 。我没有对此进行验证,但在使用测试期间看起来很不错。
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;
}
答案 1 :(得分:0)
@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)));
}
}
更新:我不认为这些是解决方案。为什么?此信息静态存储在注册表中 - 即使设备未连接也是如此。
答案 2 :(得分:-1)
很好的例子,使用JNA,My example code。 作者(Geir Arne Ruud)已经在Public Domain License下发布了它。
{{3}}
awk -vOFS="\t" '{
# Loop through fields
for(i=2;i<=NF;i++)
{
# Filename variable
f=sprintf("file_%d.txt",i-1)
# If filename index exists in array F
# Append to file if exists
if(f in F)
{
print $1,$i >>f
}
else{
# write to file
print $1,$i >f
# Array F where key is filename
F[f]
}
# close file since we do not know how many columns exists
# in your original file, to avoid too many open files error
# we close everytime, and append if filename exists in array F
close(f)
}
}' file