通过USB类

时间:2017-12-29 13:49:57

标签: c# xaml arduino uwp arduino-uno

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

匹配的USB

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

Device Manager Information

理想情况下,它应该能够列出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()编写的程序略有变化的Arduino信息输出示例,其中UsbDeviceClassjsanalytics

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

注册表图片

enter image description here

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

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

2 个答案:

答案 0 :(得分: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;
      }

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

答案 1 :(得分:1)

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 信息的资源是 USB View。它不是用 C# 编写的,但它是开源的并且是用 C 编写的,因此它可能可以翻译成 C#。