This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,633 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace DTS.DASLib.Connection.USBFramework
{
public class HIDevice: IDisposable
{
// Used in error messages.
const string ModuleName = "Hid";
public HIDDeclarations.HIDP_CAPS Capabilities;
public HIDDeclarations.HIDD_ATTRIBUTES DeviceAttributes;
public void Dispose()
{
}
// For viewing results of API calls in debug.write statements:
//static Debugging MyDebugging = new Debugging();
public abstract class DeviceReport
{
// For reports that the device sends to the host.
internal int Result;
// Each DeviceReport class defines a ProtectedRead method for reading a type of report.
// ProtectedRead and Read are declared as Subs rather than as Functions because
// asynchronous reads use a callback method that can access parameters passed by ByRef
// but not Function return values.
protected abstract void ProtectedRead(int readHandle, int hidHandle, int writeHandle,
ref bool myDeviceDetected, ref byte[] readBuffer, ref bool success);
public void Read(int readHandle, int hidHandle, int writeHandle,
ref bool myDeviceDetected, ref byte[] readBuffer, ref bool success)
{
// Purpose : Calls the overridden ProtectedRead routine.
// Enables other classes to override ProtectedRead
// while limiting access as Friend.
// (Directly declaring Write as Friend MustOverride causes the
// compiler warning : "Other languages may permit Friend
// Overridable members to be overridden.")
// Accepts : readHandle - a handle for reading from the device.
// hidHandle - a handle for other device communications.
// myDeviceDetected - tells whether the device is currently
// attached and communicating.
// readBuffer - a byte array to hold the report ID and report data.
// success - read success
{
// Request the report.
ProtectedRead(readHandle, hidHandle, writeHandle, ref myDeviceDetected, ref readBuffer, ref success);
}
}
}
internal class InFeatureReport: DeviceReport
{
// For reading Feature reports.
protected override void ProtectedRead(int readHandle, int hidHandle, int writeHandle, ref bool myDeviceDetected, ref byte[] inFeatureReportBuffer, ref bool success)
{
// Purpose : reads a Feature report from the device.
// Accepts : readHandle - the handle for reading from the device.
// hidHandle - the handle for other device communications.
// myDeviceDetected - tells whether the device is currently attached.
// readBuffer - contains the requested report.
// success - read success
try
{
// ***
// API function: HidD_GetFeature
// Attempts to read a Feature report from the device.
// Requires:
// A handle to a HID
// A pointer to a buffer containing the report ID and report
// The size of the buffer.
// Returns: true on success, false on failure.
// ***
success = HIDDeclarations.HidD_GetFeature(hidHandle, ref inFeatureReportBuffer[0], inFeatureReportBuffer.Length);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
}
}
public class InputReport: DeviceReport
{
// For reading Input reports.
bool ReadyForOverlappedTransfer; // initialize to false
internal void CancelTransfer(int readHandle, int hidHandle)
{
// Purpose : closes open handles to a device.
// Accepts : ReadHandle - the handle for reading from the device.
// HIDHandle - the handle for other device communications.
try
{
// ***
// API function: CancelIo
// Purpose: Cancels a call to ReadFile
// Accepts: the device handle.
// Returns: True on success, False on failure.
// ***
Result = FileIODeclarations.CancelIo(readHandle);
// The failure may have been because the device was removed,
// so close any open handles and
// set myDeviceDetected=False to cause the application to
// look for the device on the next attempt.
if(hidHandle != 0)
{
FileIODeclarations.CloseHandle(hidHandle);
}
if(hidHandle != 0)
{
FileIODeclarations.CloseHandle(readHandle);
}
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
}
internal void PrepareForOverlappedTransfer(ref FileIODeclarations.OVERLAPPED hidOverlapped, ref int eventObject)
{
// Purpose : Creates an event object for the overlapped structure used with
// : ReadFile.
// ; Called before the first call to ReadFile.
FileIODeclarations.SECURITY_ATTRIBUTES Security = new FileIODeclarations.SECURITY_ATTRIBUTES();
try
{
// Values for the SECURITY_ATTRIBUTES structure:
Security.lpSecurityDescriptor = 0;
Security.bInheritHandle = System.Convert.ToInt32(true);
Security.nLength = Marshal.SizeOf(Security);
// ***
// API function: CreateEvent
// Purpose: Creates an event object for the overlapped structure used with ReadFile.
// Accepts:
// A security attributes structure.
// Manual Reset = False (The system automatically resets the state to nonsignaled
// after a waiting thread has been released.)
// Initial state = True (signaled)
// An event object name (optional)
// Returns: a handle to the event object
// ***
eventObject = FileIODeclarations.CreateEvent(ref Security, System.Convert.ToInt32(false), System.Convert.ToInt32(true), "");
// Set the members of the overlapped structure.
hidOverlapped.Offset = 0;
hidOverlapped.OffsetHigh = 0;
hidOverlapped.hEvent = eventObject;
ReadyForOverlappedTransfer = true;
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
}
protected override void ProtectedRead(int readHandle,
int hidHandle,
int writeHandle,
ref bool myDeviceDetected,
ref byte[] inputReportBuffer,
ref bool success)
{
// Purpose : reads an Input report from the device using interrupt transfers.
// Accepts : readHandle - the handle for reading from the device.
// hidHandle - the handle for other device communications.
// myDeviceDetected - tells whether the device is currently attached.
// readBuffer - contains the requested report.
// success - read success
// FileIOApiDeclarations.OVERLAPPED HIDOverlapped = new HID.FileIOApiDeclarations.OVERLAPPED();
{
int NumberOfBytesRead = 0;
int TotalBytesRead = 0;
long Result = 1;
while(Result != 0 && TotalBytesRead < inputReportBuffer.Length)
{
uint ret = FileIODeclarations.WaitForSingleObject(readHandle, 200);
switch(ret)
{
case FileIODeclarations.WAIT_OBJECT_0:
Result = FileIODeclarations.ReadFile(readHandle,
ref inputReportBuffer[TotalBytesRead],
inputReportBuffer.Length,
ref NumberOfBytesRead,
0);
TotalBytesRead += NumberOfBytesRead;
break;
case FileIODeclarations.WAIT_TIMEOUT:
Result = 0;
break;
case FileIODeclarations.WAIT_ABANDONED:
case FileIODeclarations.WAIT_FAILED:
default:
// throw new SliceRecorder.Recorder.RecorderException("InputReport.ProtectedRead WaitForSingleObject failed");
break;
}
}
if(0 == Result)
{
}
// If it's the first attempt to read, set up the overlapped structure for ReadFile.
if(!ReadyForOverlappedTransfer)
{
// PrepareForOverlappedTransfer(ref HIDOverlapped, ref EventObject);
}
success = Result == 1;
}
}
}
internal class InputReportViaControlTransfer: DeviceReport
{
protected override void ProtectedRead(int readHandle, int hidHandle, int writeHandle, ref bool myDeviceDetected, ref byte[] inputReportBuffer, ref bool success)
{
// Purpose : reads an Input report from the device using a control transfer.
// Accepts : readHandle - the handle for reading from the device.
// hidHandle - the handle for other device communications.
// myDeviceDetected - tells whether the device is currently attached.
// readBuffer - contains the requested report.
// success - read success
try
{
// API function: HidD_GetInputReport
// Purpose: Attempts to read an Input report from the device using a control transfer.
// Supported under Windows XP and later only.
// Requires:
// A handle to a HID
// A pointer to a buffer containing the report ID and report
// The size of the buffer.
// Returns: true on success, false on failure.
success = HIDDeclarations.HidD_GetInputReport(hidHandle, ref inputReportBuffer[0], inputReportBuffer.Length);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
}
}
public abstract class HostReport
{
// For reports the host sends to the device.
// Each report class defines a ProtectedWrite method for writing a type of report.
protected abstract bool ProtectedWrite(int deviceHandle, byte[] reportBuffer);
public bool Write(byte[] reportBuffer, int deviceHandle)
{
bool Success = false;
// Purpose : Calls the overridden ProtectedWrite routine.
// : This method enables other classes to override ProtectedWrite
// : while limiting access as Friend.
// : (Directly declaring Write as Friend MustOverride causes the
// : compiler(warning) "Other languages may permit Friend
// : Overridable members to be overridden.")
// Accepts : reportBuffer - contains the report ID and report data.
// : deviceHandle - handle to the device. '
// Returns : True on success. False on failure.
try
{
Success = ProtectedWrite(deviceHandle, reportBuffer);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Success;
}
}
internal class OutFeatureReport: HostReport
{
// For Feature reports the host sends to the device.
protected override bool ProtectedWrite(int hidHandle, byte[] outFeatureReportBuffer)
{
// Purpose : writes a Feature report to the device.
// Accepts : hidHandle - a handle to the device.
// featureReportBuffer - contains the report ID and report to send.
// Returns : True on success. False on failure.
bool Success = false;
try
{
// API function: HidD_SetFeature
// Purpose: Attempts to send a Feature report to the device.
// Accepts:
// A handle to a HID
// A pointer to a buffer containing the report ID and report
// The size of the buffer.
// Returns: true on success, false on failure.
Success = HIDDeclarations.HidD_SetFeature(hidHandle, ref outFeatureReportBuffer[0], outFeatureReportBuffer.Length);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Success;
}
}
public class OutputReport: HostReport
{
// For Output reports the host sends to the device.
// Uses interrupt or control transfers depending on the device and OS.
protected override bool ProtectedWrite(int hidHandle, byte[] outputReportBuffer)
{
// Purpose : writes an Output report to the device.
// Accepts : HIDHandle - a handle to the device.
// OutputReportBuffer - contains the report ID and report to send.
// Returns : True on success. False on failure.
int NumberOfBytesWritten = 0;
int Result;
bool Success = false;
try
{
// The host will use an interrupt transfer if the the HID has an interrupt OUT
// endpoint (requires USB 1.1 or later) AND the OS is NOT Windows 98 Gold (original version).
// Otherwise the the host will use a control transfer.
// The application doesn't have to know or care which type of transfer is used.
// Purpose: writes an Output report to the device.
// Accepts:
// A handle returned by CreateFile
// The output report byte length returned by HidP_GetCaps.
// An integer to hold the number of bytes written.
// Returns: True on success, False on failure.
Result = FileIODeclarations.WriteFile(hidHandle, ref outputReportBuffer[0], outputReportBuffer.Length, ref NumberOfBytesWritten, 0);
// Return True on success, False on failure.
Success = (Result == 0) ? false : true;
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Success;
}
}
internal class OutputReportViaControlTransfer: HostReport
{
protected override bool ProtectedWrite(int hidHandle, byte[] outputReportBuffer)
{
// Purpose : writes an Output report to the device using a control transfer.
// Accepts : hidHandle - a handle to the device.
// outputReportBuffer - contains the report ID and report to send.
// Returns : True on success. False on failure.
bool Success = false;
try
{
// API function: HidD_SetOutputReport
// Purpose:
// Attempts to send an Output report to the device using a control transfer.
// Requires Windows XP or later.
// Accepts:
// A handle to a HID
// A pointer to a buffer containing the report ID and report
// The size of the buffer.
// Returns: true on success, false on failure.
Success = HIDDeclarations.HidD_SetOutputReport(hidHandle, ref outputReportBuffer[0], outputReportBuffer.Length);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Success;
}
}
public bool FlushQueue(int hidHandle)
{
// Purpose : Remove any Input reports waiting in the buffer.
// Accepts : hidHandle - a handle to a device.
// Returns : True on success, False on failure.
bool Result = false;
try
{
// ***
// API function: HidD_FlushQueue
// Purpose: Removes any Input reports waiting in the buffer.
// Accepts: a handle to the device.
// Returns: True on success, False on failure.
// ***
Result = HIDDeclarations.HidD_FlushQueue(hidHandle);
//Debug.WriteLine(MyDebugging.ResultOfAPICall("HidD_FlushQueue, ReadHandle"));
//Debug.WriteLine("Result = " + Result.ToString());
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Result;
}
public HIDDeclarations.HIDP_CAPS GetDeviceCapabilities(int hidHandle)
{
// Purpose : Retrieves a structure with information about a device's capabilities.
// Accepts : HIDHandle - a handle to a device.
// Returns : An HIDP_CAPS structure.
byte[] PreparsedDataBytes = new byte[30];
string PreparsedDataString;
IntPtr PreparsedDataPointer = new IntPtr();
int Result;
bool Success = false;
byte[] ValueCaps = new byte[1024]; // (the array size is a guess)
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.
// ***
Success = HIDDeclarations.HidD_GetPreparsedData(hidHandle, ref PreparsedDataPointer);
//Debug.WriteLine(MyDebugging.ResultOfAPICall("HidD_GetPreparsedData"));
//Debug.WriteLine("");
// Copy the data at PreparsedDataPointer into a byte array.
PreparsedDataString = System.Convert.ToBase64String(PreparsedDataBytes);
// ***
// 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.
// ***
Result = HIDDeclarations.HidP_GetCaps(PreparsedDataPointer, ref Capabilities);
if(Result != 0)
{
// ***
// 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.
// ***
Result = HIDDeclarations.HidP_GetValueCaps(HIDDeclarations.HidP_Input, ref ValueCaps[0], ref Capabilities.NumberInputValueCaps, PreparsedDataPointer);
// (To use this data, copy the ValueCaps byte array into an array of structures.)
// ***
// 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.
// ***
Success = HIDDeclarations.HidD_FreePreparsedData(ref PreparsedDataPointer);
}
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Capabilities;
}
public string GetHIDUsage(HIDDeclarations.HIDP_CAPS MyCapabilities)
{
//'Purpose : Creates a 32-bit Usage from the Usage Page and Usage ID.
// ' : Determines whether the Usage is a system mouse or keyboard.
// ' : Can be modified to detect other Usages.
//Accepts : MyCapabilities - a HIDP_CAPS structure retrieved with HidP_GetCaps.
//'Returns : A string describing the Usage.
string UsageDescription= "";
try
{
//Create32-bit Usage from Usage Page and Usage ID.
int Usage = MyCapabilities.UsagePage * 256 + MyCapabilities.Usage;
if(Usage == 0x102)
UsageDescription = "mouse";
if(Usage == 0x106)
UsageDescription = "keyboard";
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return UsageDescription;
}
public bool GetNumberOfInputBuffers(int hidDeviceObject, ref int numberOfInputBuffers)
{
// Purpose : Retrieves the number of Input reports the host can store.
// Accepts : hidDeviceObject - a handle to a device
// : numberBuffers - an integer to hold the returned value.
// Returns : True on success, False on failure.
bool Success = false;
try
{
// ***
// API function: HidD_GetNumInputBuffers
// Purpose: retrieves the number of Input reports the host can store.
// Not supported by Windows 98 Gold.
// If the buffer is full and another report arrives, the host drops the
// oldest report.
// Accepts: a handle to a device and an integer to hold the number of buffers.
// Returns: True on success, False on failure.
// ***
Success = HIDDeclarations.HidD_GetNumInputBuffers(hidDeviceObject, ref numberOfInputBuffers);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Success;
}
internal bool SetNumberOfInputBuffers(int hidDeviceObject, int numberBuffers)
{
// Purpose : sets the number of input reports the host will store.
// : Requires Windows XP or later.
// Accepts : hidDeviceObject - a handle to the device.
// : numberBuffers - the requested number of input reports.
// Returns : True on success. False on failure.
bool Success = false;
try
{
// ***
// API function: HidD_SetNumInputBuffers
// Purpose: Sets the number of Input reports the host can store.
// If the buffer is full and another report arrives, the host drops the
// oldest report.
// Requires:
// A handle to a HID
// An integer to hold the number of buffers.
// Returns: true on success, false on failure.
// ***
Success = HIDDeclarations.HidD_SetNumInputBuffers(hidDeviceObject, numberBuffers);
}
catch(System.Exception ex)
{
HandleException(ModuleName + ":" + System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
return Success;
}
static public void HandleException(string moduleName, System.Exception e)
{
string Message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
}
}
}