C# HID Input Report Problem.

CakeDev 50 Reputation points
2024-08-04T01:56:29.68+00:00

Currently I'm having a problem with getting input reports from a HID device. What's happening is that I'm getting the device path of the device, but CreateFileW doesn't recognize it as a valid device path.

Here's my platform invokes and main function if anyone has any clue.
C#
using System;``using System.Runtime.InteropServices;

class Program

{

private const int FILE_FLAG_OVERLAPPED = 0x40000000;

private const uint GENERIC_READ = 0x80000000;

private const uint GENERIC_WRITE = 0x40000000;

private const uint FILE_SHARE_READ = 0x00000001;

private const uint FILE_SHARE_WRITE = 0x00000002;

private const uint OPEN_EXISTING = 3;

private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

[DllImport("kernel32.dll", SetLastError = true)]

private static extern bool CloseHandle(IntPtr hObject);

[DllImport("kernel32.dll", SetLastError = true)]

private static extern bool ReadFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, ref OVERLAPPED lpOverlapped);

[DllImport("kernel32.dll", SetLastError = true)]

private static extern IntPtr CreateFileW(

string lpFileName,

uint dwDesiredAccess,

uint dwShareMode,

IntPtr lpSecurityAttributes,

uint dwCreationDisposition,

uint dwFlagsAndAttributes,

IntPtr hTemplateFile);

[DllImport("hid.dll")]

private static extern void HidD_GetHidGuid(out Guid HidGuid);

[DllImport("setupapi.dll", CharSet = CharSet.Auto)]

private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, string Enumerator, IntPtr hwndParent, uint Flags);

[DllImport("setupapi.dll")]

[return: MarshalAs(UnmanagedType.Bool)]

private static extern bool SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, uint MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);

[DllImport("setupapi.dll", CharSet = CharSet.Auto)]

[return: MarshalAs(UnmanagedType.Bool)]

private static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, uint DeviceInterfaceDetailDataSize, out uint RequiredSize, IntPtr DeviceInfoData);

[DllImport("setupapi.dll")]

private static extern void SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

[StructLayout(LayoutKind.Sequential)]

private struct SP_DEVICE_INTERFACE_DATA

{

public uint cbSize;

public Guid InterfaceClassGuid;

public uint Flags;

public IntPtr Reserved;

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]

private struct SP_DEVICE_INTERFACE_DETAIL_DATA

{

public uint cbSize;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]

public string DevicePath;

}

[StructLayout(LayoutKind.Sequential)]

public struct OVERLAPPED

{

public IntPtr Internal;

public IntPtr InternalHigh;

public uint Offset;

public uint OffsetHigh;

public IntPtr hEvent;

}

private const uint DIGCF_PRESENT = 0x00000002;

private const uint DIGCF_DEVICEINTERFACE = 0x00000010;

static void Main()

{

Guid hidGuid;

HidD_GetHidGuid(out hidGuid);

IntPtr deviceInfoSet = SetupDiGetClassDevs(ref hidGuid, null, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

if (deviceInfoSet == IntPtr.Zero)

{

Console.WriteLine("Failed to get device info set");

return;

}

SP_DEVICE_INTERFACE_DATA deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA

{

cbSize = (uint)Marshal.SizeOf<SP_DEVICE_INTERFACE_DATA>()

};

uint index = 0;

while (SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref hidGuid, index++, ref deviceInterfaceData))

{

uint requiredSize = 0;

SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, out requiredSize, IntPtr.Zero);

if (requiredSize == 0)

{

continue;

}

IntPtr detailDataBuffer = Marshal.AllocHGlobal((int)requiredSize);

try

{

Marshal.WriteInt32(detailDataBuffer, IntPtr.Size == 8 ? 8 : 5);

if (SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, requiredSize, out requiredSize, IntPtr.Zero))

{

IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + Marshal.OffsetOf<SP_DEVICE_INTERFACE_DETAIL_DATA>("DevicePath").ToInt64());

string devicePath = Marshal.PtrToStringAuto(pDevicePathName);

string searchString1 = "pid&2007";

string searchString2 = "pid&2006";

string VIDstring = "vid&0002057e";

if (devicePath != null && (devicePath.Contains(searchString1) || devicePath.Contains(searchString2)) && devicePath.Contains(VIDstring))

{

Console.WriteLine("Device found!");

Console.WriteLine("Device Path: " + devicePath);

IntPtr ptr = CreateFileW(devicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero);

if (ptr == INVALID_HANDLE_VALUE)

{

int errorCode = Marshal.GetLastWin32Error();

Console.WriteLine($"CreateFileW failed with error code: {errorCode}");

Console.WriteLine("Error Message: " + new System.ComponentModel.Win32Exception(errorCode).Message);

return;

}

byte[] buffer = new byte[64];

uint bytesRead;

OVERLAPPED overlapped = new OVERLAPPED();

if (ReadFile(ptr, buffer, (uint)buffer.Length, out bytesRead, ref overlapped))

{

Console.WriteLine("Read successful");

// Example processing: Check if the A button is pressed

bool aButtonPressed = (buffer[1] & 0x04) != 0;

Console.WriteLine("A button pressed: " + (aButtonPressed ? "Yes" : "No"));

}

else

{

Console.WriteLine("Failed to read from device");

}

CloseHandle(ptr);

}

}

}

finally

{

Marshal.FreeHGlobal(detailDataBuffer);

}

}

SetupDiDestroyDeviceInfoList(deviceInfoSet);

}

}

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,593 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,858 questions
{count} votes

Accepted answer
  1. Castorix31 84,546 Reputation points
    2024-08-04T15:32:15.24+00:00

    This works on my OS (Windows 10 22H2) with the code I posted in your former question and by adding :

                                   sDevicePath = didd.DevicePath;
                                   Console.WriteLine("Device Path : {0}", sDevicePath);
                                   IntPtr hHid = CreateFile(sDevicePath, unchecked((int)(GENERIC_READ | GENERIC_WRITE)), FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
                                   if (hHid != (IntPtr)INVALID_HANDLE_VALUE)
                                   {
                                       StringBuilder sString = new StringBuilder(260);
                                       HidD_GetProductString(hHid, sString, (uint)sString.Capacity);
                                       Console.WriteLine("Product String : {0}", sString.ToString());
                                       CloseHandle(hHid);
                                   }
    
    

    with :

           public const int CREATE_NEW = 1;
           public const int CREATE_ALWAYS = 2;
           public const int OPEN_EXISTING = 3;
           public const int OPEN_ALWAYS = 4;
           public const int TRUNCATE_EXISTING = 5;
    
           public const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
    
           public const int INVALID_HANDLE_VALUE = -1;
    
           [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr lpSECURITY_ATTRIBUTES, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
    
           [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
           public static extern bool CloseHandle(IntPtr hObject);
    
        	 [DllImport("Hid.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    			 public static extern bool HidD_GetProductString(IntPtr HidDeviceObject,  StringBuilder Buffer, uint BufferLength);
    
    
    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.