我可以在 UWP (HidD_GetPreparsedData) 中使用 Windows Hid API 调用吗? [英] Can I Use Windows Hid API Calls in UWP (HidD_GetPreparsedData)?

查看:21
本文介绍了我可以在 UWP (HidD_GetPreparsedData) 中使用 Windows Hid API 调用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过 UWP 访问连接到我的计算机的 Hid (USB) 设备.我在枚举设备并通过 .NET Core 中的 Windows API 调用与它们交谈时没有问题.在 UWP 中,我可以枚举设备,但是当我使用相同的设备调用 HidD_GetPreparsedData 时 (https://msdn.microsoft.com/en-us/library/windows/hardware/ff539679(v=vs.85).aspx),它返回假的.

I am trying to access Hid (USB) devices connected to my computer on UWP. I have no problem enumerating the devices and talking to them through Windows API calls in .NET Core. In UWP, I can enumerate the devices, but when I call HidD_GetPreparsedData with the same device (https://msdn.microsoft.com/en-us/library/windows/hardware/ff539679(v=vs.85).aspx), it returns false.

我认为因为 UWP 有自己的 HID 库,所以我应该使用它,但我希望重用我现有的代码.任何想法为什么这个电话可能会失败?

I'm thinking that because UWP has its own HID library, I'm supposed to use that, but I'm hoping to reuse my existing code. Any ideas why this call might be failing?

我确实认为这是一个权限问题,所以我从这里下载了 UWP HID 示例:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomHidDeviceAccess.然后我修改了包清单以使用设备的 VID 和 PID

I did think that this was a permissions problem, so I downloaded the UWP HID Sample from here: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/CustomHidDeviceAccess. I then modified the package manifest to use the device's VID and PID

<Capabilities>
  <DeviceCapability Name="humaninterfacedevice">
    <Device Id="vidpid:xxxx xxxx">
      <Function Type="usage:0005 *" />
    </Device>
  </DeviceCapability>
</Capabilities>

设备使用 UWP 中的标准 HID 库出现在 UWP 中.我可以枚举所有设备(不仅仅是我指定访问的设备),并且我的设备显示在示例应用的设备列表中.

The device appears in UWP using the standard HID library in UWP. I can enumerate ALL devices (not just the ones I have specified access to), and my device shows up in the list of devices in the sample app.

然而,当我编译并运行我的应用程序时,HidD_GetPreparsedData 返回 false.所以,我想知道我是否会让这个 API 调用工作.IE.我应该放弃企业,只使用标准的 UWP HID 库吗?

Yet, when I compile and run my app, the HidD_GetPreparsedData returns false. So, I'm left wondering if I'm ever going to get this API call working. I.e. should I abandon the enterprise and just use the standard UWP HID library?

推荐答案

答案是否定的.UWP 平台不允许 Windows Hid 或 USB API 调用.API 调用未出现在此处.即使 API 没有明确失败也是如此.这就引出了一个问题,即为什么 UWP 允许您访问某些 API 调用,但在调用它们时不会显式抛出异常.

The answer is no. The UWP platform does not allow Windows Hid, or USB API calls. The API call does not appear here. That's even though the API doesn't explicitly fail. This begs the question of why UWP allows you to access some API calls but doesn't explicitly throw an exception when you call them.

无论如何,没有必要,因为有一个完整的USB API,和Hid访问.您需要在包清单中定义您的设备,如下所示:

Anyway, it is not necessary because there is a full API for USB, and Hid access. You need to define your devices in the package manifest like this:

隐藏:

<DeviceCapability Name="humaninterfacedevice">

  <Device Id="vidpid:534C 0001">
    <Function Type="usage:0005 *" />
    <Function Type="usage:FF00 0001" />
    <Function Type="usage:ff00 *" />
  </Device>

  <Device Id="vidpid:1209 53C0">
    <Function Type="usage:0005 *" />
    <Function Type="usage:FF00 0001" />
    <Function Type="usage:ff00 *" />
  </Device>

  <Device Id="vidpid:1209 53C1">
    <Function Type="usage:0005 *" />
    <Function Type="usage:FF00 0001" />
    <Function Type="usage:ff00 *" />
  </Device>

</DeviceCapability>

USB:

  <!--Trezor Firmware 1.7.x -->
  <Device Id="vidpid:1209 53C1">
    <Function Type="classId:ff * *" />
  </Device>

</DeviceCapability>

这里有两个用于与 USB 通信的类,以及来自 Device.Net.

Here are two classes for communicating with USB, and Hid devices on UWP from Device.Net.

public class UWPHidDevice : UWPDeviceBase<HidDevice>
{
    #region Public Properties
    public bool DataHasExtraByte { get; set; } = true;
    #endregion

    #region Public Override Properties
    /// <summary>
    /// TODO: These vales are completely wrong and not being used anyway...
    /// </summary>
    public override ushort WriteBufferSize => 64;
    /// <summary>
    /// TODO: These vales are completely wrong and not being used anyway...
    /// </summary>
    public override ushort ReadBufferSize => 64;
    #endregion

    #region Event Handlers
    private void _HidDevice_InputReportReceived(HidDevice sender, HidInputReportReceivedEventArgs args)
    {
        HandleDataReceived(InputReportToBytes(args));
    }
    #endregion

    #region Constructors
    public UWPHidDevice()
    {
    }

    public UWPHidDevice(string deviceId) : base(deviceId)
    {
    }
    #endregion

    #region Private Methods
    private byte[] InputReportToBytes(HidInputReportReceivedEventArgs args)
    {
        byte[] bytes;
        using (var stream = args.Report.Data.AsStream())
        {
            bytes = new byte[args.Report.Data.Length];
            stream.Read(bytes, 0, (int)args.Report.Data.Length);
        }

        if (DataHasExtraByte)
        {
            bytes = RemoveFirstByte(bytes);
        }

        return bytes;
    }

    public override async Task InitializeAsync()
    {
        //TODO: Put a lock here to stop reentrancy of multiple calls

        //TODO: Dispose but this seems to cause initialization to never occur
        //Dispose();

        Logger.Log("Initializing Hid device", null, nameof(UWPHidDevice));

        await GetDevice(DeviceId);

        if (_ConnectedDevice != null)
        {
            _ConnectedDevice.InputReportReceived += _HidDevice_InputReportReceived;
            RaiseConnected();
        }
        else
        {
            throw new Exception($"The device {DeviceId} failed to initialize");
        }
    }

    protected override IAsyncOperation<HidDevice> FromIdAsync(string id)
    {
        return HidDevice.FromIdAsync(id, FileAccessMode.ReadWrite);
    }
    #endregion

    #region Public Methods

    public override async Task WriteAsync(byte[] data)
    {
        byte[] bytes;
        if (DataHasExtraByte)
        {
            bytes = new byte[data.Length + 1];
            Array.Copy(data, 0, bytes, 1, data.Length);
            bytes[0] = 0;
        }
        else
        {
            bytes = data;
        }

        var buffer = bytes.AsBuffer();
        var outReport = _ConnectedDevice.CreateOutputReport();
        outReport.Data = buffer;

        try
        {
            var operation = _ConnectedDevice.SendOutputReportAsync(outReport);
            await operation.AsTask();
            Tracer?.Trace(false, bytes);
        }
        catch (ArgumentException ex)
        {
            //TODO: Check the string is nasty. Validation on the size of the array being sent should be done earlier anyway
            if (ex.Message == "Value does not fall within the expected range.")
            {
                throw new Exception("It seems that the data being sent to the device does not match the accepted size. Have you checked DataHasExtraByte?", ex);
            }
            throw;
        }
    }
    #endregion
}

public class UWPUsbDevice : UWPDeviceBase<UsbDevice>
{
    #region Fields
    /// <summary>
    /// TODO: It should be possible to select a different configuration/interface
    /// </summary>
    private UsbInterface _DefaultConfigurationInterface;
    private UsbInterruptOutPipe _DefaultOutPipe;
    private UsbInterruptInPipe _DefaultInPipe;
    #endregion

    #region Public Override Properties
    public override ushort WriteBufferSize => (ushort)_DefaultOutPipe.EndpointDescriptor.MaxPacketSize;
    public override ushort ReadBufferSize => (ushort)_DefaultInPipe.EndpointDescriptor.MaxPacketSize;
    #endregion

    #region Constructors
    public UWPUsbDevice() : base()
    {
    }

    public UWPUsbDevice(string deviceId) : base(deviceId)
    {
    }
    #endregion

    #region Private Methods
    public override async Task InitializeAsync()
    {
        await GetDevice(DeviceId);

        if (_ConnectedDevice != null)
        {
            var usbInterface = _ConnectedDevice.Configuration.UsbInterfaces.FirstOrDefault();

            if (usbInterface == null)
            {
                _ConnectedDevice.Dispose();
                throw new Exception("There was no Usb Interface found for the device.");
            }

            var interruptPipe = usbInterface.InterruptInPipes.FirstOrDefault();

            if (interruptPipe == null)
            {
                throw new Exception("There was no interrupt pipe found on the interface");
            }

            interruptPipe.DataReceived += InterruptPipe_DataReceived;

            //TODO: Fill in the DeviceDefinition...

            // TODO: It should be possible to select a different configurations, interface, and pipes

            _DefaultConfigurationInterface = _ConnectedDevice.Configuration.UsbInterfaces.FirstOrDefault();

            //TODO: Clean up this messaging and move down to a base class across platforms
            if (_DefaultConfigurationInterface == null) throw new Exception("Could not get the default interface configuration for the USB device");

            _DefaultOutPipe = _DefaultConfigurationInterface.InterruptOutPipes.FirstOrDefault();

            if (_DefaultOutPipe == null) throw new Exception("Could not get the default out pipe for the default USB interface");

            _DefaultInPipe = _DefaultConfigurationInterface.InterruptInPipes.FirstOrDefault();

            if (_DefaultOutPipe == null) throw new Exception("Could not get the default in pipe for the default USB interface");


            RaiseConnected();
        }
        else
        {
            throw new Exception($"Could not connect to device with Device Id {DeviceId}. Check that the package manifest has been configured to allow this device.");
        }
    }

    protected override IAsyncOperation<UsbDevice> FromIdAsync(string id)
    {
        return UsbDevice.FromIdAsync(id);
    }

    #endregion

    #region Event Handlers
    private void InterruptPipe_DataReceived(UsbInterruptInPipe sender, UsbInterruptInEventArgs args)
    {
        HandleDataReceived(args.InterruptData.ToArray());
    }
    #endregion

    #region Public Methods
    public override async Task WriteAsync(byte[] bytes)
    {
        if (_DefaultOutPipe == null) throw new Exception("The device has not been initialized.");

        if (bytes.Length > WriteBufferSize) throw new Exception("The buffer size is too large");
        await _DefaultOutPipe.OutputStream.WriteAsync(bytes.AsBuffer());

        Tracer?.Trace(false, bytes);
    }
    #endregion
}

这篇关于我可以在 UWP (HidD_GetPreparsedData) 中使用 Windows Hid API 调用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆