【问题标题】:Listing USB devices via their USB class通过 USB 类列出 USB 设备
【发布时间】:2018-06-09 22:55:00
【问题描述】:

我正在尝试动态列出与某个 UsbDeviceClass 匹配的计算机连接的 USB

我试图在设备管理器中列出的 USB 类的信息如下

理想情况下,它应该能够列出 Com 端口,因为我要特别列出的设备是 Arduinos。

DeviceInformationCollection usbDeviceInfoCollection = await DeviceInformation.FindAllAsync(UsbDevice.GetDeviceClassSelector(new UsbDeviceClass()
{
    ClassCode = 0x02,
    SubclassCode = 0x02,
    ProtocolCode = 0x01
}));
Debug.WriteLineIf(usbDeviceInfoCollection.Count == 1, "1 USB device found");
Debug.WriteLineIf(usbDeviceInfoCollection.Count != 1, usbDeviceInfoCollection.Count + " USB devices found");

for (int i = 0; i < usbDeviceInfoCollection.Count; i++)
{
    Debug.WriteLine("USB Device " + (i + 1));
    Debug.WriteLine("ID: " + usbDeviceInfoCollection[i].Id);
    Debug.WriteLine("Name: " + usbDeviceInfoCollection[i].Name);
    Debug.WriteLine("Properties: " + usbDeviceInfoCollection[i].Properties);
    Debug.WriteLine("");
}

上面的代码显示了我是如何尝试实现这一目标的,但到目前为止我还没有运气。这是因为当程序运行时,如果有设备连接,它会返回 0 个设备。

我也尝试过使用预定义类UsbDeviceClasses.CdcControl,但是也没有达到我想要的结果。

对于如何正确实现这一点的任何指导,我将不胜感激。


由于这是一个 UWP 项目,我已包含以下功能,因此它应该能够检测到我想要的设备。

<DeviceCapability Name="serialcommunication">
  <Device Id="any">
    <Function Type="name:serialPort"/>
  </Device>
</DeviceCapability>

使用DeviceInformation.FindAllAsync() 不使用UsbDeviceClass 作为jsanalytics 建议的程序的轻微变化的Arduino 信息的示例输出。

Device 1354
EnclosureLocation: Windows.Devices.Enumeration.EnclosureLocation
ID: \\?\USB#VID_2341&PID_0243#9543231323835131B172#{86e0d1e0-8089-11d0-9ce4-08003e301f73}
IsDefault: False
IsEnabled: True
Kind: DeviceInterface
Name: Genuino Uno (COM6)
Pairing: Windows.Devices.Enumeration.DeviceInformationPairing
Properties: System.__ComObject

注册表图像


更新,this page 介绍了更具体的 USB 功能,包括 name:cdcControl, classId:02 * *。但是,我仍然无法像这个远程 arduino 应用程序那样通过附加设备进行枚举; Windows Remote Arduino Experience.


快速编辑澄清。我不是无法连接到设备,我只是无法枚举属于 02 类子类 02 协议 01 的设备。可以通过指定 VID 和 PID 连接到我的设备,但在目前的情况下,这不符合这一点.

【问题讨论】:

  • 那么你的问题是你把0设备找回来了吗?
  • 没有等待就可以工作吗?
  • @jsanalytics 是的。我编辑了我的问题以包含所提供信息的示例
  • @jsanalytics 我目前使用的模型是Arduino Uno Rev3。感谢您的帮助
  • @jsanalytics 我更新了照片以显示只有一个条目

标签: c# xaml arduino uwp arduino-uno


【解决方案1】:

您可以枚举外部USB设备,首先您需要在Package.appxmanifest文件中添加此权限。

 <uap:Capability Name="removableStorage" />

然后在您的应用中编写此代码。

    var removableDevices = KnownFolders.RemovableDevices;
    var externalDrives = await removableDevices.GetFoldersAsync();
    foreach (var item in externalDrives)
      {
          var name = item.DisplayName;
      }

现在有一个刷新列表重新运行代码。

【讨论】:

  • 感谢您的回答,但是,这并不能正确回答原始问题。不幸的是,这是个好主意。这适用于列出诸如 USB 笔式驱动器或外部 HDD 之类的东西,但是,它不会列出我想要列出的 Arduinos 之类的东西
【解决方案2】:

SerialDevice.GetDeviceSelector()可以用来回答我枚举串口设备的具体场景。

DeviceInformationCollection deviceSearchResults = await DeviceInformation.FindAllAsync(SerialDevice.GetDeviceSelector());

但是看看类、子类和协议如何用于列出相同信息的问题,就不清楚了。

UsbDevice.GetDeviceClassSelector(new UsbDeviceClass
{
    ClassCode = 0x02,
    SubclassCode = 0x02,
    ProtocolCode = 0x01
});

上面的代码生成字符串

System.Devices.InterfaceClassGuid:="{DEE824EF-729B-4A0E-9C14-B7117D33A817}" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND System.DeviceInterface.WinUsb.UsbClass:=2 AND System.DeviceInterface.WinUsb.UsbSubClass:=2 AND System.DeviceInterface.WinUsb.UsbProtocol:=1

这不起作用有两个原因。

查看System.Devices.InterfaceClassGuid时可以看到第一个。列出的串行端口的此属性值不是DEE824EF-729B-4A0E-9C14-B7117D33A817,而是86e0d1e0-8089-11d0-9ce4-08003e301f73SerialDevice.GetDeviceSelector() 似乎在返回时考虑到了这一点

System.Devices.InterfaceClassGuid:="{86E0D1E0-8089-11D0-9CE4-08003E301F73}" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True

第二个是当使用DeviceInformation.FindAllAsync 加载您希望与问题屏幕截图中显示的值匹配的其他参数时,它们实际上是空的。

代码

private async void List()
{
    DeviceInformationCollection deviceSearchResults = await DeviceInformation.FindAllAsync("", new[]
    {
        "System.Devices.InterfaceClassGuid",
        "System.DeviceInterface.Serial.PortName",
        "System.DeviceInterface.Serial.UsbProductId",
        "System.DeviceInterface.Serial.UsbVendorId",
        "System.Devices.CompatibleIds",
        "System.Devices.ClassGuid",
        "System.DeviceInterface.WinUsb.UsbClass",
        "System.DeviceInterface.WinUsb.UsbSubClass",
        "System.DeviceInterface.WinUsb.UsbProtocol",
    });

    foreach (DeviceInformation device in deviceSearchResults)
    {
        PrintInfo(device);
    }
}

private static void PrintInfo(DeviceInformation device)
{
    Debug.WriteLine("Device:");
    Debug.WriteLine($"\tID: {device.Id}");
    Debug.WriteLine($"\tName: {device.Name}");
    Debug.WriteLine($"\tIs Enabled: {device.IsEnabled}");
    Debug.WriteLine($"\tIs Default: {device.IsDefault}");
    Debug.WriteLine($"\tKind: {device.Kind}");

    if (device.EnclosureLocation != null)
    {
        Debug.WriteLine("\tEnclosure Location:");
        Debug.WriteLine($"\t\tIn Dock: {device.EnclosureLocation.InDock}");
        Debug.WriteLine($"\t\tIn Lid: {device.EnclosureLocation.InLid}");
        Debug.WriteLine($"\t\tPanel: {device.EnclosureLocation.Panel}");
        Debug.WriteLine($"\t\tRotation Angle In Degrees Clockwise: {device.EnclosureLocation.RotationAngleInDegreesClockwise}");
    }

    if (device.Pairing != null)
    {
        Debug.WriteLine("\tPairing Info:");
        Debug.WriteLine($"\t\tCan Pair: {device.Pairing.CanPair}");
        Debug.WriteLine($"\t\tIs Paired: {device.Pairing.IsPaired}");
        Debug.WriteLine($"\t\tProtection Level: {device.Pairing.ProtectionLevel}");
    }

    Debug.WriteLine("\tProperties:");
    foreach ((string key, object value) in device.Properties)
    {
        Debug.WriteLine($"\t\t{key}: {value}");
    }

    Debug.WriteLine("");
}

返回以下输出,显示 CompatibleIds 等附加参数为空。

Device:
    ID: \\?\USB#VID_2341&PID_0043#9563533333135161B150#{86e0d1e0-8089-11d0-9ce4-08003e301f73}
    Name: USB Serial Device (COM3)
    Is Enabled: True
    Is Default: False
    Kind: DeviceInterface
    Enclosure Location:
        In Dock: False
        In Lid: False
        Panel: Right
        Rotation Angle In Degrees Clockwise: 0
    Pairing Info:
        Can Pair: False
        Is Paired: False
        Protection Level: None
    Properties:
        System.ItemNameDisplay: USB Serial Device (COM3)
        System.Devices.DeviceInstanceId: USB\VID_2341&PID_0043\9563533333135161B150
        System.Devices.Icon: C:\Windows\System32\DDORes.dll,-2001
        System.Devices.GlyphIcon: C:\Windows\System32\DDORes.dll,-3001
        System.Devices.InterfaceEnabled: True
        System.Devices.IsDefault: False
        System.Devices.PhysicalDeviceLocation: System.Byte[]
        System.Devices.ContainerId: 57921dd6-46ab-5d6d-a362-0a14d0827375
        System.Devices.InterfaceClassGuid: 86e0d1e0-8089-11d0-9ce4-08003e301f73
        System.DeviceInterface.Serial.PortName: COM3
        System.DeviceInterface.Serial.UsbProductId: 67
        System.DeviceInterface.Serial.UsbVendorId: 9025
        System.Devices.CompatibleIds: 
        System.Devices.ClassGuid: 
        System.DeviceInterface.WinUsb.UsbClass: 
        System.DeviceInterface.WinUsb.UsbSubClass: 
        System.DeviceInterface.WinUsb.UsbProtocol: 

附带说明,如果有人在这里希望在 WPF/其他桌面应用程序中实现类似的东西,这是我当时采用的方法,可以使用 WMI 通过几种方式实现。

// If in .NET Core / .NET 5 run
// Install-Package System.Management -Version 5.0.0
// See https://www.nuget.org/packages/System.Management/
ManagementObjectSearcher searcher =
    new ManagementObjectSearcher("SELECT * FROM Win32_SerialPort");

foreach (ManagementBaseObject queryObj in searcher.Get())
{
    Debug.WriteLine("COM Port");
    Debug.WriteLine($"DeviceID: {queryObj["DeviceID"]}");
    Debug.WriteLine($"Name: {queryObj["NAME"]}");
    Debug.WriteLine($"Description: {queryObj["Description"]}");
    Debug.WriteLine($"PNPDeviceID: {queryObj["PNPDeviceID"]}");
    Debug.WriteLine("");
}

// If in .NET Core / .NET 5 run
// Install-Package Microsoft.Management.Infrastructure -Version 2.0.0
// See https://www.nuget.org/packages/Microsoft.Management.Infrastructure/
CimSession cimSession = CimSession.Create(null);

IEnumerable<CimInstance> queryInstances =
    cimSession.QueryInstances(@"root\cimv2",
        "WQL",
        @"SELECT * FROM Win32_SerialPort");

foreach (CimInstance cimInstance in queryInstances)
{
    Debug.WriteLine("COM Port");
    Debug.WriteLine($"DeviceID: {cimInstance.CimInstanceProperties["DeviceID"].Value}");
    Debug.WriteLine($"Name: {cimInstance.CimInstanceProperties["NAME"].Value}");
    Debug.WriteLine($"Description: {cimInstance.CimInstanceProperties["Description"].Value}");
    Debug.WriteLine($"PNPDeviceID: {cimInstance.CimInstanceProperties["PNPDeviceID"].Value}");
    Debug.WriteLine("");
}

UWP 的 WMI/CIM 方法的问题是它不受支持,即使可以安装 NuGet。一种解决方案是使用桌面桥将 Win32 代码作为后台进程包含在 UWP 应用程序中。请参阅herehere 了解更多信息。


USB View 是一个似乎能够获得大量有关 USB 信息的资源。它不是用 C# 编写的,但它是开源的,并且是用 C 编写的,因此可以翻译成 C#。

【讨论】:

  • 嘿@Dan,感谢您提供的大量新信息。我在我的系统上尝试了您的列表。但是我得到的属性输出不足。喜欢Name/ItemNameDisplay: Dual RS232Name/ItemNameDisplay: TTL232R-3V3。此外,System.DeviceInterface.Serial.* 字段为空。我希望能在设备管理器中得到一些输出(Name/ItemNameDisplay: USB Serial Port (COM11),就像你的一样)。我也对设备的制造商名称和序列号感兴趣。但这似乎不是一件容易的事。
  • 目前我正在使用USB Tree View(上述 USB 查看工具的扩展版本)来查找属性。所以基本上属性就在那里。问题是我能够在 UWP 应用程序中得到这个。
  • @veeman 如果你运行DeviceInformation.FindAllAsync("System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True", additional parameters); 并打印出所有信息,com 端口在吗?当我运行它时,它会列出设备两次,一次带有 com 端口信息,一次没有
  • @veeman 但是我明白了你的问题,我不知道为什么某些字段没有被填充,即使你提到的工具清楚地突出了这些信息。这个工具也很酷。大量更好的信息
猜你喜欢
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-19
相关资源
最近更新 更多