简体   繁体   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). 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).

Currently I try to use WMI through a PowerShell command my Java programm executes.目前,我尝试通过执行 Java 程序的 PowerShell 命令来使用 WMI。

I already found this: Powershell: Grab USB Drive letter .我已经找到了这个: Powershell: Grab USB Drive letter But it would also list USB 2.0 devices.但它也会列出 USB 2.0 设备。

Regarding version detection I found this: How to check the version of the available USB ports?关于版本检测,我发现: 如何检查可用 USB 端口的版本? - The PowerShell command I tried is Get-WmiObject Win32_USBHub . - 我试过的 PowerShell 命令是Get-WmiObject Win32_USBHub This brings up several problems.这带来了几个问题。 First: It lists far more stuff than only USB drives (I think also all the USB hubs of my PC).首先:它列出的内容远不止 USB 驱动器(我认为我的 PC 的所有 USB 集线器)。 Second: Even though there is a field USBVersion for all items in the list it is always empty.第二:即使列表中的所有项目都有一个字段USBVersion它始终为空。

Update更新

The essence of my research over the last days is, that there are 2 realms of information I need to connect.我过去几天研究的本质是,我需要连接两个领域的信息。

  • Drives / Logical Drives驱动器/逻辑驱动器
    • Drive Letter盘符
    • BusType (is equal to "USB" for my matter) BusType(就我而言,等于“USB”)
  • USB devices USB 器件
    • Vendor ID and Product ID (VID&PID)供应商 ID 和产品 ID (VID&PID)
    • bcdUSB (value within the usb device descriptor, indicating USB Version) bcdUSB (usb 设备描述符中的值,表示 USB 版本)

For a given drive letter I need to find the bcdUSB value.对于给定的驱动器号,我需要找到 bcdUSB 值。 But I haven't found a way to get the drive corresponding to a USB device.但是我还没有找到一种方法来获取与 USB 设备对应的驱动器。

What I tried so far到目前为止我尝试了什么

WMI over PowerShell WMI over PowerShell

Relevant commands I found are我发现的相关命令是

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

Even though I get the BusType I couldn't make a connection to bcdUSB即使我得到了 BusType,我也无法连接到 bcdUSB

usb4java ( Link ) usb4java (链接)

I only get information from the USB device realm here.我这里只从 USB 设备 realm 获取信息。 I can load devices and see ther VID&PID and the bcdUSB value, but no way to map this to drives and drive letters.我可以加载设备并查看 VID&PID 和 bcdUSB 值,但无法将 map 用于驱动器和驱动器号。

lsusb via Cygwin lsusb 通过 Cygwin

According to this post the linux command is easier to handle than WMI.根据这篇文章,linux 命令比 WMI 更容易处理。 So I tried to use it under Windows.所以我尝试在Windows下使用。 But I like usb4java I only got VID&PID + bcdUSB, not the mount point (drive letter).但我喜欢 usb4java 我只有 VID&PID + bcdUSB,而不是挂载点(驱动器号)。

Searching the Windows Registry搜索 Windows 注册表

I did a few string searchs in the Windows registry.我在 Windows 注册表中进行了一些字符串搜索。 No success.没有成功。

Reading Windows Event log读取 Windows 事件日志

I thought about ovserving Windows events to detect what Drive and what USB device connect at the same time.我考虑过观察 Windows 事件以检测同时连接的驱动器和 USB 设备。 I didn't even find events when plugging in a USB stick.插入 USB 棒时我什至没有发现事件。

Maybe this is what you are looking for: Find Windows Drive Letter of a removable disk from USB VID/PID At least someone marked the answer as working... :-)也许这就是您要查找的内容: 从 USB VID/PID 中查找可移动磁盘的 Windows 驱动器号至少有人将答案标记为工作... :-)

Since the suggested Link solves this problem for C# not Java and leaves out one step, I'll post my final code here.由于建议的链接为 C# 而不是 Java 解决了这个问题并省略了一步,因此我将在此处发布我的最终代码。

Summary概括

In Java在 Java

  • Use USB4Java to find all connected USB devices with bcdUSB=0x0300使用USB4Java查找所有连接的 USB 设备bcdUSB=0x0300
  • Get Vendor ID and Product ID (VID&PID) for that devices获取该设备的供应商 ID 和产品 ID (VID&PID)

Via Powershell (with jPowerShell )通过 Powershell(使用jPowerShell

  • Get PnPEntity for given VID&PID获取给定 VID&PID 的 PnPEntity
  • Get related USB Controller获取相关 USB Controller
  • Find associator of that USB Controller that is associated with a disk drive查找与磁盘驱动器关联的 USB Controller 的关联方
  • Get that Disk drive获取该磁盘驱动器
  • Get related disk partition获取相关磁盘分区
  • Get related logical disk -> LogicalDisk.DeviceID = Drive Letter获取相关逻辑磁盘 -> LogicalDisk.DeviceID = Drive Letter

Code代码

Java class: 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 script: 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 dependencies: 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