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

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

问题描述

我正在尝试访问在UWP上连接到我的计算机的Hid(USB)设备.我没有问题,可以枚举设备并通过.NET Core中的Windows API调用与它们对话.在UWP中,我可以枚举设备,但是当我使用同一设备调用HidD_GetPreparsedData时(

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隐藏或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.您需要像这样在包清单中定义设备:

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和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隐藏API调用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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