HID FileStream 在 Windows 7 上不起作用



在我的开发计算机中,我使用 Windows 10 创建了一个 WPF,用于接收缓冲区并将其发送到我的 HID 设备(自定义游戏控制器)。

它在我尝试的任何Windows 10上运行良好,但是我的一些客户端运行Windows 7(无法升级),我无法使其工作。

写入方法引发异常:

提供的用户缓冲区对于请求的操作无效。

public static bool SendBufferToDevice(HIDDev device, byte[] buffer)
{
try
{
lock (device)
{
device.fileStream.Write(buffer, 0, buffer.Length);
}
return true;
}
catch(Exception e)
{
return false;
}
}

read 方法引发相同的异常:

提供的用户缓冲区对于请求的操作无效。

public static byte[] ReceiveBufferFromDevice(HIDDev device, int bufferSize)
{
byte[] buffer = new byte[bufferSize];
try
{
using (MemoryStream ms = new MemoryStream())
{
int read = device.fileStream.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
return ms.ToArray();
}
}
catch (Exception e)
{
return buffer;
}
}

我尝试更改发送到方法的缓冲区的大小和类型,但没有成功。此外,如前所述,此确切代码适用于 Windows 10。

HIDDev 类的一部分:

public class HIDDev : IDisposable
{
// device handle
private IntPtr handle;
// safe file handle
SafeFileHandle shandle;
// stream
private FileStream _fileStream;
public FileStream fileStream 
{
get { return _fileStream; }
/* do not expose this setter */
internal set { _fileStream = value; }
}

...
}

我需要做什么仅适用于

编辑:

如前所述,HID 类:

原生.cs

using System;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32.SafeHandles;

namespace HIDRealdrive
{
class Native
{
/* invalid handle value */
public static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

#region kernel32.dll

/* read access */
public const uint GENERIC_READ = 0x80000000;
/* write access */
public const uint GENERIC_WRITE = 0x40000000;
/* Enables subsequent open operations on a file or device to request 
* write access.*/
public const uint FILE_SHARE_WRITE = 0x2;
/* Enables subsequent open operations on a file or device to request
* read access. */
public const uint FILE_SHARE_READ = 0x1;
/* The file or device is being opened or created for asynchronous I/O. */
public const uint FILE_FLAG_OVERLAPPED = 0x40000000;
/* Opens a file or device, only if it exists. */
public const uint OPEN_EXISTING = 3;
/* Opens a file, always. */
public const uint OPEN_ALWAYS = 4;
[DllImport("kernel32.dll", SetLastError = true)]
/* opens files that access usb hid devices */
public static extern IntPtr CreateFile(
[MarshalAs(UnmanagedType.LPStr)] string strName, 
uint nAccess, uint nShareMode, IntPtr lpSecurity, 
uint nCreationFlags, uint nAttributes, IntPtr lpTemplate);
[DllImport("kernel32.dll", SetLastError = true)]
/* closes file */
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
static public extern int WriteFile(IntPtr hFile, ref byte lpBuffer, int nNumberOfBytesToWrite);
[DllImport("kernel32.dll")]
static public extern bool ReadFile(IntPtr hFile, ref byte lpBuffer, int nNumberOfBytesToRead);
#endregion
#region hid.dll

/* The HIDD_ATTRIBUTES structure contains vendor information about a 
* HIDClass device.*/
[StructLayout(LayoutKind.Sequential)]
public struct HiddAttributtes
{
/* size in bytes */
public Int32 Size;
/* vendor id */
public Int16 VendorID;
/* product id */
public Int16 ProductID;
/* hid vesion number */
public Int16 VersionNumber;
}
//Capacidades totais do Dispositivo
public struct HIDP_CAPS
{
public Int16 Usage;
public Int16 UsagePage;
public Int16 InputReportByteLength;
public Int16 OutputReportByteLength;
public Int16 FeatureReportByteLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
public Int16[] Reserved;
public Int16 NumberLinkCollectionNodes;
public Int16 NumberInputButtonCaps;
public Int16 NumberInputValueCaps;
public Int16 NumberInputDataIndices;
public Int16 NumberOutputButtonCaps;
public Int16 NumberOutputValueCaps;
public Int16 NumberOutputDataIndices;
public Int16 NumberFeatureButtonCaps;
public Int16 NumberFeatureValueCaps;
public Int16 NumberFeatureDataIndices;
}

[DllImport("hid.dll", SetLastError = true)]
/* gets HID class Guid */
public static extern void HidD_GetHidGuid(out Guid gHid);
/* gets hid device attributes */
[DllImport("hid.dll", SetLastError = true)]
public static extern Boolean HidD_GetAttributes(IntPtr hFile,
ref HiddAttributtes attributes);
/* gets usb manufacturer string */
[DllImport("hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean HidD_GetManufacturerString(IntPtr hFile,
StringBuilder buffer, Int32 bufferLength);
/* gets product string */
[DllImport("hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean HidD_GetProductString(IntPtr hFile,
StringBuilder buffer, Int32 bufferLength);
/* gets serial number string */
[DllImport("hid.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool HidD_GetSerialNumberString(IntPtr hDevice,
StringBuilder buffer, Int32 bufferLength);
//Novos Imports do GenericHid_62
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_FlushQueue(SafeFileHandle HidDeviceObject);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_GetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
Int32 ReportBufferLength);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_GetInputReport(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
Int32 ReportBufferLength);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_GetNumInputBuffers(SafeFileHandle HidDeviceObject, ref Int32 NumberBuffers);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_GetPreparsedData(SafeFileHandle HidDeviceObject, ref IntPtr PreparsedData);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_SetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
Int32 ReportBufferLength);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_SetNumInputBuffers(SafeFileHandle HidDeviceObject, Int32 NumberBuffers);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Boolean HidD_SetOutputReport(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
Int32 ReportBufferLength);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Int32 HidP_GetCaps(IntPtr PreparsedData, ref HIDP_CAPS Capabilities);
[DllImport("hid.dll", SetLastError = true)]
internal static extern Int32 HidP_GetValueCaps(Int32 ReportType, Byte[] ValueCaps, ref Int32 ValueCapsLength,
IntPtr PreparsedData);

#endregion
#region setupapi.dll

/* Return only devices that are currently present in a system. */
public const int DIGCF_PRESENT = 0x02;
/* Return devices that support device interfaces for the specified 
* device interface classes. */
public const int DIGCF_DEVICEINTERFACE = 0x10;
/* structure returned by SetupDiEnumDeviceInterfaces */
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeviceInterfaceData
{
/* size of fixed part of structure */
public int Size;
/* The GUID for the class to which the device interface belongs. */
public Guid InterfaceClassGuid;
/* Can be one or more of the following: SPINT_ACTIVE, 
* SPINT_DEFAULT, SPINT_REMOVED */
public int Flags;
/* do not use */
public IntPtr Reserved;
}
/* A structure contains the path for a device interface.*/
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DeviceInterfaceDetailData
{
/* size of fixed part of structure */
public int Size;
/* device path, as to be used by CreateFile */
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
public string DevicePath;
}
/* function returns a handle to a device information set that contains
* requested device information elements for a local computer */
[DllImport("setupapi.dll", SetLastError = true)]
public static extern IntPtr SetupDiGetClassDevs(ref Guid gClass, 
[MarshalAs(UnmanagedType.LPStr)] string strEnumerator, 
IntPtr hParent, uint nFlags);
/* The function enumerates the device interfaces that are contained in 
* a device information set.*/
[DllImport("setupapi.dll", SetLastError = true)]
public static extern bool SetupDiEnumDeviceInterfaces(
IntPtr lpDeviceInfoSet, uint nDeviceInfoData, ref Guid gClass,
uint nIndex, ref DeviceInterfaceData oInterfaceData);
/* The SetupDiGetDeviceInterfaceDetail function returns details about 
* a device interface.*/
[DllImport("setupapi.dll", SetLastError = true)]
public static extern bool SetupDiGetDeviceInterfaceDetail(
IntPtr lpDeviceInfoSet, ref DeviceInterfaceData oInterfaceData,
ref DeviceInterfaceDetailData oDetailData, 
uint nDeviceInterfaceDetailDataSize, ref uint nRequiredSize,
IntPtr lpDeviceInfoData);
/* destroys device list */
[DllImport("setupapi.dll", SetLastError = true)]
public static extern bool SetupDiDestroyDeviceInfoList(IntPtr lpInfoSet);

#endregion
}
}

HIDInfo.cs

namespace HIDRealdrive
{
public class HIDInfo
{
/* device path */
public string Path { get; private set; }
/* vendor ID */
public short Vid { get; private set; }
/* product id */
public short Pid { get; private set; }
/* usb product string */
public string Product { get; private set; }
/* usb manufacturer string */
public string Manufacturer { get; private set; }
/* usb serial number string */
public string SerialNumber { get; private set; }
/* constructor */
public HIDInfo(string product, string serial, string manufacturer, 
string path, short vid, short pid)
{
/* copy information */
Product = product;
SerialNumber = serial;
Manufacturer = manufacturer;
Path = path;
Vid = vid;
Pid = pid;
}
}
}

隐藏.cs

using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;

namespace HIDRealdrive
{
public class HIDDev : IDisposable
{
/* device handle */
private IntPtr handle;
/* safe file handle */
SafeFileHandle shandle;
/* stream */
private FileStream _fileStream;
//conectado
private bool isConnected = false;
internal Native.HIDP_CAPS Capabilities;
private string[] capabilitiesStrings = new string[16];
//Retorna a conexão
public bool IsConnected { get { return isConnected; } }

/* stream */
public FileStream fileStream 
{
get { return _fileStream; }
/* do not expose this setter */
internal set { _fileStream = value; }
}
/* dispose */
public void Dispose()
{
/* deal with file stream */
if (_fileStream != null) {
/* close stream */
_fileStream.Close();
/* get rid of object */
_fileStream = null;
}
/* close handle */
Native.CloseHandle(handle);
}
/* open hid device */
public bool Open(HIDInfo dev)
{

/* opens hid device file */
handle = Native.CreateFile(dev.Path, 
Native.GENERIC_READ | Native.GENERIC_WRITE,
Native.FILE_SHARE_READ | Native.FILE_SHARE_WRITE,
IntPtr.Zero, Native.OPEN_EXISTING, Native.FILE_FLAG_OVERLAPPED,
IntPtr.Zero);
/* whops */
if (handle == Native.INVALID_HANDLE_VALUE) {
isConnected = false;
return false;
}
isConnected = true;
/* build up safe file handle */
shandle = new SafeFileHandle(handle, false);
capabilitiesStrings = GetDeviceCapabilities(shandle);
/* prepare stream - async */
_fileStream = new FileStream(shandle, FileAccess.ReadWrite, 
32, true);
/* report status */
return true;
}
/*Recebe informações totais do Dispositivo*/
string[] GetDeviceCapabilities(SafeFileHandle hidHandle)
{
var preparsedData = new IntPtr();
string[] capabilitiesStrings = new string[16];
try
{
//  ***
//  API function: HidD_GetPreparsedData
//  Purpose: retrieves a pointer to a buffer containing information about the device's capabilities.
//  HidP_GetCaps and other API functions require a pointer to the buffer.
//  Requires: 
//  A handle returned by CreateFile.
//  A pointer to a buffer.
//  Returns:
//  True on success, False on failure.
//  ***
Native.HidD_GetPreparsedData(hidHandle, ref preparsedData);
//  ***
//  API function: HidP_GetCaps
//  Purpose: find out a device's capabilities.
//  For standard devices such as joysticks, you can find out the specific
//  capabilities of the device.
//  For a custom device where the software knows what the device is capable of,
//  this call may be unneeded.
//  Accepts:
//  A pointer returned by HidD_GetPreparsedData
//  A pointer to a HIDP_CAPS structure.
//  Returns: True on success, False on failure.
//  ***
Int32 result = Native.HidP_GetCaps(preparsedData, ref Capabilities);
if ((result != 0))
{
Debug.WriteLine("");
Debug.WriteLine("  Usage: " + Convert.ToString(Capabilities.Usage, 16));
Debug.WriteLine("  Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
Debug.WriteLine("  Input Report Byte Length: " + Capabilities.InputReportByteLength);
Debug.WriteLine("  Output Report Byte Length: " + Capabilities.OutputReportByteLength);
Debug.WriteLine("  Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
Debug.WriteLine("  Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
Debug.WriteLine("  Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
Debug.WriteLine("  Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
Debug.WriteLine("  Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
Debug.WriteLine("  Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
Debug.WriteLine("  Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
Debug.WriteLine("  Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
Debug.WriteLine("  Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
Debug.WriteLine("  Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
Debug.WriteLine("  Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
capabilitiesStrings[0]=("Full Device Capabilities Report:");
capabilitiesStrings[1] = ("  Usage: " + Convert.ToString(Capabilities.Usage, 16));
capabilitiesStrings[2] = ("  Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
capabilitiesStrings[3] = ("  Input Report Byte Length: " + Capabilities.InputReportByteLength);
capabilitiesStrings[4] = ("  Output Report Byte Length: " + Capabilities.OutputReportByteLength);
capabilitiesStrings[5] = ("  Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
capabilitiesStrings[6] = ("  Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
capabilitiesStrings[7] = ("  Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
capabilitiesStrings[8] = ("  Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
capabilitiesStrings[9] = ("  Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
capabilitiesStrings[10] = ("  Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
capabilitiesStrings[11] = ("  Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
capabilitiesStrings[12] = ("  Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
capabilitiesStrings[13] = ("  Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
capabilitiesStrings[14] = ("  Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
capabilitiesStrings[15] = ("  Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
//  ***
//  API function: HidP_GetValueCaps
//  Purpose: retrieves a buffer containing an array of HidP_ValueCaps structures.
//  Each structure defines the capabilities of one value.
//  This application doesn't use this data.
//  Accepts:
//  A report type enumerator from hidpi.h,
//  A pointer to a buffer for the returned array,
//  The NumberInputValueCaps member of the device's HidP_Caps structure,
//  A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.
//  Returns: True on success, False on failure.
//  ***                    
Int32 vcSize = Capabilities.NumberInputValueCaps;
var valueCaps = new Byte[vcSize];
//Native.HidP_GetValueCaps(Native.HidP_Input, valueCaps, ref vcSize, preparsedData);
// (To use this data, copy the ValueCaps byte array into an array of structures.)              
}
}
catch (Exception ex)
{
throw;
}
finally
{
//  ***
//  API function: HidD_FreePreparsedData
//  Purpose: frees the buffer reserved by HidD_GetPreparsedData.
//  Accepts: A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.
//  Returns: True on success, False on failure.
//  ***
if (preparsedData != IntPtr.Zero)
{
Native.HidD_FreePreparsedData(preparsedData);
}
}
return capabilitiesStrings;
}
/* close hid device */
public void Close()
{
/* deal with file stream */
if (_fileStream != null) {
/* close stream */
_fileStream.Close();
/* get rid of object */
_fileStream = null;
}
/* close handle */
Native.CloseHandle(handle);
isConnected = false;
}
/* write record */
public void Write(byte[] data)
{
/* Cria task e write some bytes */ 
fileStream.Write(data, 0, data.Length);
/* flush! */
_fileStream.Flush();
}
public async Task WriteAsync(byte[] data)
{
/* Cria task e write some bytes */
Task t =_fileStream.WriteAsync(data, 0, data.Length);
await t;
/* flush! */
_fileStream.Flush();
}
/* read record */
public void Read(byte[] data)
{
/* get number of bytes */
int n = 0, bytes = data.Length;
/* read buffer */
while (n != bytes) {
/* read data */
int rc = _fileStream.Read(data, n, bytes - n);
/* update pointers */
n += rc;
}
}
public byte[] GetInputReport(byte[] inBuffer, int buffLenght)
{
Native.HidD_GetInputReport(shandle, inBuffer, buffLenght);
return inBuffer;
}
/*Mais info sobre a placa*/
public string[] GetFullDeviceCapabilities(string[] cap)
{
return cap;
}
public string GetFullDeviceCapabilitiesString()
{
string capabilities = "";
for (int i = 0; i <= capabilitiesStrings.Length-1; i++)
{
capabilities = capabilities + capabilitiesStrings[i];
}
return capabilities;
}
}
}

只是停下来尝试重新发明轮子并使用

希德夏普

与 https://www.zer7.com/software/hidsharp 相比

而且效果很好。

获取设备功能,它会说出输入和输出报告的大小。

必须使缓冲区与此大小匹配。

老实说,我不再尝试在 Win 7 上使用文件流,因为它们一直挂在内核中等待语义。

使用 HIDAPI 并互操作这些调用。(不确定,但认为这可能是HidSharp已经做的事情?

https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/introduction-to-hid-concepts

最新更新