繁体   English   中英

获取USB 3.0设备盘符(Windows下Java)

[英]Get drive letters of USB 3.0 devices (Java under Windows)

My Java program needs to get a list of the drive letters of connected USB devices, but only those that support USB 3.0 (both the device and the USB port it is plugged into, so that it works with high speed).

目前,我尝试通过执行 Java 程序的 PowerShell 命令来使用 WMI。

我已经找到了这个: Powershell: Grab USB Drive letter 但它也会列出 USB 2.0 设备。

关于版本检测,我发现: 如何检查可用 USB 端口的版本? - 我试过的 PowerShell 命令是Get-WmiObject Win32_USBHub 这带来了几个问题。 首先:它列出的内容远不止 USB 驱动器(我认为我的 PC 的所有 USB 集线器)。 第二:即使列表中的所有项目都有一个字段USBVersion它始终为空。

更新

我过去几天研究的本质是,我需要连接两个领域的信息。

  • 驱动器/逻辑驱动器
    • 盘符
    • BusType(就我而言,等于“USB”)
  • USB 器件
    • 供应商 ID 和产品 ID (VID&PID)
    • bcdUSB (usb 设备描述符中的值,表示 USB 版本)

对于给定的驱动器号,我需要找到 bcdUSB 值。 但是我还没有找到一种方法来获取与 USB 设备对应的驱动器。

到目前为止我尝试了什么

WMI over PowerShell

我发现的相关命令是

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 (链接)

我这里只从 USB 设备 realm 获取信息。 我可以加载设备并查看 VID&PID 和 bcdUSB 值,但无法将 map 用于驱动器和驱动器号。

lsusb 通过 Cygwin

根据这篇文章,linux 命令比 WMI 更容易处理。 所以我尝试在Windows下使用。 但我喜欢 usb4java 我只有 VID&PID + bcdUSB,而不是挂载点(驱动器号)。

搜索 Windows 注册表

我在 Windows 注册表中进行了一些字符串搜索。 没有成功。

读取 Windows 事件日志

我考虑过观察 Windows 事件以检测同时连接的驱动器和 USB 设备。 插入 USB 棒时我什至没有发现事件。

也许这就是您要查找的内容: 从 USB VID/PID 中查找可移动磁盘的 Windows 驱动器号至少有人将答案标记为工作... :-)

由于建议的链接为 C# 而不是 Java 解决了这个问题并省略了一步,因此我将在此处发布我的最终代码。

概括

在 Java

  • 使用USB4Java查找所有连接的 USB 设备bcdUSB=0x0300
  • 获取该设备的供应商 ID 和产品 ID (VID&PID)

通过 Powershell(使用jPowerShell

  • 获取给定 VID&PID 的 PnPEntity
  • 获取相关 USB Controller
  • 查找与磁盘驱动器关联的 USB Controller 的关联方
  • 获取该磁盘驱动器
  • 获取相关磁盘分区
  • 获取相关逻辑磁盘 -> LogicalDisk.DeviceID = Drive Letter

代码

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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM