获取 USB 3.0 设备的盘符(Java 下 Windows)
Get drive letters of USB 3.0 devices (Java under Windows)
我的 Java 程序需要获取已连接 USB 设备的驱动器盘符列表,但只有那些支持 USB 3.0 的设备(包括设备和它插入的 USB 端口,这样它才能工作高速)。
目前我尝试通过我的 Java 程序执行的 PowerShell 命令使用 WMI。
我已经找到了:Powershell: Grab USB Drive letter。但它也会列出 USB 2.0 设备。
关于版本检测,我发现:How to check the version of the available USB ports? - 我尝试的 PowerShell 命令是 Get-WmiObject Win32_USBHub
。这带来了几个问题。第一:它列出的东西远不止 USB 驱动器(我想还有我 PC 的所有 USB 集线器)。第二:即使列表中的所有项目都有一个字段 USBVersion,它始终为空。
更新
我最近几天研究的重点是,我需要连接 2 个信息领域。
- 驱动器/逻辑驱动器
- 盘符
- BusType(就我而言等于“USB”)
- USB 设备
- 供应商 ID 和产品 ID (VID&PID)
- bcdUSB(USB设备描述符中的值,表示USB版本)
对于给定的驱动器盘符,我需要找到 bcdUSB 值。但是一直没找到USB设备对应驱动的方法。
到目前为止我尝试了什么
基于 PowerShell 的 WMI
我找到的相关命令是
Get-Disk // Get BusType
gwmi Win32_LogicalDisk // Get drive letter
// Those make the connection between disk and logical disk
gwmi Win32_LogicalDiskToPartition
gwmi Win32_LogicalDiskToPartition
即使我得到 BusType,我也无法连接到 bcdUSB
usb4java (Link)
我这里只获取USB设备领域的信息。我可以加载设备并查看 VID&PID 和 bcdUSB 值,但无法将其映射到驱动器和驱动器号。
lsusb 通过 Cygwin
根据 this post,linux 命令比 WMI 更容易处理。所以我尝试在Windows下使用它。但是我喜欢usb4java我只有VID&PID + bcdUSB,没有挂载点(盘符)。
正在搜索 Windows 注册表
我在 Windows 注册表中进行了一些字符串搜索。没有成功。
正在读取Windows事件日志
我想过观察 Windows 事件来检测同时连接的驱动器和 USB 设备。我什至在插入 U 盘时都没有找到事件。
也许这就是您要找的:
Find Windows Drive Letter of a removable disk from USB VID/PID
至少有人将答案标记为有效...:-)
由于建议的 Link 解决了 C# 的这个问题而不是 Java 并省去了一个步骤,我将 post 我的最终代码放在这里。
总结
在Java
- 使用 USB4Java 查找所有连接的 USB 设备
bcdUSB=0x0300
- 获取该设备的供应商 ID 和产品 ID (VID&PID)
通过 Powershell(jPowerShell)
- 获取给定 VID 和 PID 的 PnPEntity
- 获取相关 USB 控制器
- 查找与磁盘驱动器关联的 USB 控制器的关联器
- 获取该磁盘驱动器
- 获取相关磁盘分区
- 获取相关逻辑盘->LogicalDisk.DeviceID=盘符
代码
Java class:
class UsbDetector {
private PowerShell shell;
@PostConstruct
private void init() {
shell = com.profesorfalken.jpowershell.PowerShell.openSession();
}
@OnDestroy
private void onShutdownHook() {
shell.close();
}
/**
* Get drive letters of USB 3.0 devices.
*/
public List<String> getDriveLettersForUsb3Devices() throws IOException, UsbException {
List<UsbDevice> devicesUSB3 = getAllUsb3Devices();
ImmutableList.Builder<String> driveLetterList = ImmutableList.builder();
for (UsbDevice device : devicesUSB3) {
String vidAndPid = getVidAndPid(device);
String powerShellScript = buildScript(vidAndPid);
String driveLetter = executeOnPowerShell(powerShellScript);
driveLetterList.add(driveLetter);
}
return driveLetterList.build();
}
private String executeOnPowerShell(String powerShellScript) {
InputStream psScriptStream = new ByteArrayInputStream(powerShellScript.getBytes());
BufferedReader psScriptReader = new BufferedReader(new InputStreamReader(psScriptStream));
PowerShellResponse response = shell.executeScript(psScriptReader);
return response.getCommandOutput();
}
private String buildScript(String vidAndPid) throws IOException {
InputStream psScriptStream =
getClass().getClassLoader().getResourceAsStream("GetUsbDrives.ps1");
String psScript = IOUtil.toString(psScriptStream);
psScript = String.format("$input=\"%s\"", vidAndPid) + "\n" + psScript;
return psScript;
}
/**
* The Vendor ID and Product ID are necessary to find the device via WMI.
*/
private String getVidAndPid(UsbDevice device) {
short vendorId = device.getUsbDeviceDescriptor().idVendor();
short productId = device.getUsbDeviceDescriptor().idProduct();
String vendorIdHexString = String.format("%04x", vendorId).toUpperCase();
String productIdHexString = String.format("%04x", productId).toUpperCase();
String vidAndPid = String.format("VID_%s&PID_%s", vendorIdHexString, productIdHexString);
return vidAndPid;
}
/**
* From all Usb devices find those with USB 3.0. The value bcdUsb is a hexadecimal coded number
* telling us the USB version.
*/
private List<UsbDevice> getAllUsb3Devices() throws UsbException {
List<UsbDevice> devicesUSB3 = Lists.newArrayList();
UsbServices services = new org.usb4java.javax.Services();
UsbHub hub = services.getRootUsbHub();
List<UsbDevice> devices = getAllUsbDevices(hub);
for (UsbDevice device : devices) {
UsbDeviceDescriptor descriptor = device.getUsbDeviceDescriptor();
short bcdUsb = descriptor.bcdUSB();
String bcdDecoded = DescriptorUtils.decodeBCD(bcdUsb);
if (Objects.equal(bcdDecoded, "3.00")) {
devicesUSB3.add(device);
}
}
return devicesUSB3;
}
/**
* UsbHubs can either mount UsbDevices or further UsbHubs. This method searches through the tree
* of UsbHubs for UsbDevices and returns them as list.
*/
private List<UsbDevice> getAllUsbDevices(UsbHub hub) {
List<UsbDevice> devices = Lists.newArrayList();
List<UsbDevice> attachedDevices = hub.getAttachedUsbDevices();
for (UsbDevice device : attachedDevices) {
if (device instanceof UsbHub) {
List<UsbDevice> subdevices = getAllUsbDevices((UsbHub) device);
devices.addAll(subdevices);
} else {
devices.add(device);
}
}
return devices;
}
}
PowerShell 脚本:
# $input = "VID_XXXX&PID_XXXX (this line is added in Java Code)
# For given VID and PID of a USB device we search for
# the corresponding logical disk to get the drive letter.
# The chain of objects is:
# PnPEntity (PnP = Plug and Play)
# -> USBController
# -> Some associator of USBController that has a related disk drive
# -> diskDrive
# -> diskPartition
# -> logicalDisk
# Find PnPEntity for given VID and PID
$usbPnPEntity = (gwmi Win32_PnPEntity | where DeviceID -match $input)
# Get USB Controller related to PnP Entity
$usbController = $usbPnPEntity.getRelated("Win32_USBController")
$usbControllerID = $usbController.DeviceID
# Find objects associated with the USB Controller
$query = "ASSOCIATORS OF {Win32_USBController.DeviceID='$usbControllerID'}"
$associators = ([wmisearcher]$query).get()
# Search through associators
foreach ($associator in $associators) {
# Find associator that is related to a disk Drive
$assoDeviceID = $associator.DeviceID
$diskDrive = (gwmi win32_diskdrive | where PNPDeviceID -eq $assoDeviceID)
if($diskDrive){
# Get logical Disk related to the disk drive
$logicalDisk = $diskDrive.getRelated("Win32_DiskPartition").getRelated("Win32_LogicalDisk")
# Print device ID which is the drive letter (e.g. "C:")
$logicalDisk.DeviceID
break
}
}
Maven 依赖项:
<dependency>
<groupId>org.usb4java</groupId>
<artifactId>usb4java-javax</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.profesorfalken</groupId>
<artifactId>jPowerShell</artifactId>
<version>3.1.1</version>
</dependency>
我的 Java 程序需要获取已连接 USB 设备的驱动器盘符列表,但只有那些支持 USB 3.0 的设备(包括设备和它插入的 USB 端口,这样它才能工作高速)。
目前我尝试通过我的 Java 程序执行的 PowerShell 命令使用 WMI。
我已经找到了:Powershell: Grab USB Drive letter。但它也会列出 USB 2.0 设备。
关于版本检测,我发现:How to check the version of the available USB ports? - 我尝试的 PowerShell 命令是 Get-WmiObject Win32_USBHub
。这带来了几个问题。第一:它列出的东西远不止 USB 驱动器(我想还有我 PC 的所有 USB 集线器)。第二:即使列表中的所有项目都有一个字段 USBVersion,它始终为空。
更新
我最近几天研究的重点是,我需要连接 2 个信息领域。
- 驱动器/逻辑驱动器
- 盘符
- BusType(就我而言等于“USB”)
- USB 设备
- 供应商 ID 和产品 ID (VID&PID)
- bcdUSB(USB设备描述符中的值,表示USB版本)
对于给定的驱动器盘符,我需要找到 bcdUSB 值。但是一直没找到USB设备对应驱动的方法。
到目前为止我尝试了什么
基于 PowerShell 的 WMI
我找到的相关命令是
Get-Disk // Get BusType
gwmi Win32_LogicalDisk // Get drive letter
// Those make the connection between disk and logical disk
gwmi Win32_LogicalDiskToPartition
gwmi Win32_LogicalDiskToPartition
即使我得到 BusType,我也无法连接到 bcdUSB
usb4java (Link)
我这里只获取USB设备领域的信息。我可以加载设备并查看 VID&PID 和 bcdUSB 值,但无法将其映射到驱动器和驱动器号。
lsusb 通过 Cygwin
根据 this post,linux 命令比 WMI 更容易处理。所以我尝试在Windows下使用它。但是我喜欢usb4java我只有VID&PID + bcdUSB,没有挂载点(盘符)。
正在搜索 Windows 注册表
我在 Windows 注册表中进行了一些字符串搜索。没有成功。
正在读取Windows事件日志
我想过观察 Windows 事件来检测同时连接的驱动器和 USB 设备。我什至在插入 U 盘时都没有找到事件。
也许这就是您要找的: Find Windows Drive Letter of a removable disk from USB VID/PID 至少有人将答案标记为有效...:-)
由于建议的 Link 解决了 C# 的这个问题而不是 Java 并省去了一个步骤,我将 post 我的最终代码放在这里。
总结
在Java
- 使用 USB4Java 查找所有连接的 USB 设备
bcdUSB=0x0300
- 获取该设备的供应商 ID 和产品 ID (VID&PID)
通过 Powershell(jPowerShell)
- 获取给定 VID 和 PID 的 PnPEntity
- 获取相关 USB 控制器
- 查找与磁盘驱动器关联的 USB 控制器的关联器
- 获取该磁盘驱动器
- 获取相关磁盘分区
- 获取相关逻辑盘->LogicalDisk.DeviceID=盘符
代码
Java class:
class UsbDetector {
private PowerShell shell;
@PostConstruct
private void init() {
shell = com.profesorfalken.jpowershell.PowerShell.openSession();
}
@OnDestroy
private void onShutdownHook() {
shell.close();
}
/**
* Get drive letters of USB 3.0 devices.
*/
public List<String> getDriveLettersForUsb3Devices() throws IOException, UsbException {
List<UsbDevice> devicesUSB3 = getAllUsb3Devices();
ImmutableList.Builder<String> driveLetterList = ImmutableList.builder();
for (UsbDevice device : devicesUSB3) {
String vidAndPid = getVidAndPid(device);
String powerShellScript = buildScript(vidAndPid);
String driveLetter = executeOnPowerShell(powerShellScript);
driveLetterList.add(driveLetter);
}
return driveLetterList.build();
}
private String executeOnPowerShell(String powerShellScript) {
InputStream psScriptStream = new ByteArrayInputStream(powerShellScript.getBytes());
BufferedReader psScriptReader = new BufferedReader(new InputStreamReader(psScriptStream));
PowerShellResponse response = shell.executeScript(psScriptReader);
return response.getCommandOutput();
}
private String buildScript(String vidAndPid) throws IOException {
InputStream psScriptStream =
getClass().getClassLoader().getResourceAsStream("GetUsbDrives.ps1");
String psScript = IOUtil.toString(psScriptStream);
psScript = String.format("$input=\"%s\"", vidAndPid) + "\n" + psScript;
return psScript;
}
/**
* The Vendor ID and Product ID are necessary to find the device via WMI.
*/
private String getVidAndPid(UsbDevice device) {
short vendorId = device.getUsbDeviceDescriptor().idVendor();
short productId = device.getUsbDeviceDescriptor().idProduct();
String vendorIdHexString = String.format("%04x", vendorId).toUpperCase();
String productIdHexString = String.format("%04x", productId).toUpperCase();
String vidAndPid = String.format("VID_%s&PID_%s", vendorIdHexString, productIdHexString);
return vidAndPid;
}
/**
* From all Usb devices find those with USB 3.0. The value bcdUsb is a hexadecimal coded number
* telling us the USB version.
*/
private List<UsbDevice> getAllUsb3Devices() throws UsbException {
List<UsbDevice> devicesUSB3 = Lists.newArrayList();
UsbServices services = new org.usb4java.javax.Services();
UsbHub hub = services.getRootUsbHub();
List<UsbDevice> devices = getAllUsbDevices(hub);
for (UsbDevice device : devices) {
UsbDeviceDescriptor descriptor = device.getUsbDeviceDescriptor();
short bcdUsb = descriptor.bcdUSB();
String bcdDecoded = DescriptorUtils.decodeBCD(bcdUsb);
if (Objects.equal(bcdDecoded, "3.00")) {
devicesUSB3.add(device);
}
}
return devicesUSB3;
}
/**
* UsbHubs can either mount UsbDevices or further UsbHubs. This method searches through the tree
* of UsbHubs for UsbDevices and returns them as list.
*/
private List<UsbDevice> getAllUsbDevices(UsbHub hub) {
List<UsbDevice> devices = Lists.newArrayList();
List<UsbDevice> attachedDevices = hub.getAttachedUsbDevices();
for (UsbDevice device : attachedDevices) {
if (device instanceof UsbHub) {
List<UsbDevice> subdevices = getAllUsbDevices((UsbHub) device);
devices.addAll(subdevices);
} else {
devices.add(device);
}
}
return devices;
}
}
PowerShell 脚本:
# $input = "VID_XXXX&PID_XXXX (this line is added in Java Code)
# For given VID and PID of a USB device we search for
# the corresponding logical disk to get the drive letter.
# The chain of objects is:
# PnPEntity (PnP = Plug and Play)
# -> USBController
# -> Some associator of USBController that has a related disk drive
# -> diskDrive
# -> diskPartition
# -> logicalDisk
# Find PnPEntity for given VID and PID
$usbPnPEntity = (gwmi Win32_PnPEntity | where DeviceID -match $input)
# Get USB Controller related to PnP Entity
$usbController = $usbPnPEntity.getRelated("Win32_USBController")
$usbControllerID = $usbController.DeviceID
# Find objects associated with the USB Controller
$query = "ASSOCIATORS OF {Win32_USBController.DeviceID='$usbControllerID'}"
$associators = ([wmisearcher]$query).get()
# Search through associators
foreach ($associator in $associators) {
# Find associator that is related to a disk Drive
$assoDeviceID = $associator.DeviceID
$diskDrive = (gwmi win32_diskdrive | where PNPDeviceID -eq $assoDeviceID)
if($diskDrive){
# Get logical Disk related to the disk drive
$logicalDisk = $diskDrive.getRelated("Win32_DiskPartition").getRelated("Win32_LogicalDisk")
# Print device ID which is the drive letter (e.g. "C:")
$logicalDisk.DeviceID
break
}
}
Maven 依赖项:
<dependency>
<groupId>org.usb4java</groupId>
<artifactId>usb4java-javax</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.profesorfalken</groupId>
<artifactId>jPowerShell</artifactId>
<version>3.1.1</version>
</dependency>