Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.IConnection/USBConnection/USBFramework.md
2026-04-17 14:55:32 -04:00

158 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
source_files:
- Common/DTS.Common.IConnection/USBConnection/USBFramework/FileIODeclarations.cs
- Common/DTS.Common.IConnection/USBConnection/USBFramework/HIDDeclarations.cs
- Common/DTS.Common.IConnection/USBConnection/USBFramework/DeviceManagementDeclarations.cs
- Common/DTS.Common.IConnection/USBConnection/USBFramework/DeviceManagement.cs
generated_at: "2026-04-16T02:09:55.521694+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "8939bee008e13a9a"
---
# Documentation: USBFramework Module
## 1. Purpose
This module provides low-level Windows API interop declarations and high-level device management utilities for USB device communication, specifically targeting HID-class devices and generic file I/O operations. It serves as the foundational layer for USB device enumeration, notification handling, and raw communication in the DTS system. The module exposes P/Invoke signatures for Windows kernel32.dll, hid.dll, setupapi.dll, and advapi32.dll functions, alongside managed wrappers (e.g., `DeviceManagement`) that abstract device discovery, registration for plug-and-play events, and property retrieval. Its role is to enable reliable detection, connection, and interaction with USB devices without relying on higher-level .NET USB libraries.
## 2. Public Interface
### `FileIODeclarations` class (namespace `DTS.Common.USBFramework`)
- **`const uint GENERIC_READ = 0x80000000`**
Access mask for read operations in `CreateFile`.
- **`const uint GENERIC_WRITE = 0x40000000`**
Access mask for write operations in `CreateFile`.
- **`const uint FILE_SHARE_READ = 0x00000001`**
Share mode flag for read sharing.
- **`const uint FILE_SHARE_WRITE = 0x00000002`**
Share mode flag for write sharing.
- **`const uint FILE_FLAG_OVERLAPPED = 0x40000000`**
Flag for asynchronous I/O in `CreateFile`.
- **`const int INVALID_HANDLE_VALUE = -1`**
Sentinel value for invalid handle.
- **`const short OPEN_EXISTING = 3`**
Creation disposition for opening existing files/devices.
- **`const int WAIT_TIMEOUT = 0x102`**, **`WAIT_OBJECT_0 = 0`**, **`WAIT_FAILED = 0xFFFFFFFF`**, **`WAIT_ABANDONED = 0x00000080`**
Return codes for `WaitForSingleObject`.
- **`const int FSCTL_SET_COMPRESSION = 0x9C040`**
I/O control code for compression (unused in current context).
- **`struct OVERLAPPED`**
Unmanaged structure for asynchronous I/O (note: `hEvent` is `int`, not `IntPtr`).
- **`struct SECURITY_ATTRIBUTES`**
Unmanaged structure for security descriptor handling (note: `lpSecurityDescriptor` is `int`, not `IntPtr`).
- **`int CancelIo(int hFile)`**
Cancels pending I/O operations on the specified file handle.
- **`int CloseHandle(int hObject)`**
Closes an open object handle.
- **`int CreateEvent(ref SECURITY_ATTRIBUTES SecurityAttributes, int bManualReset, int bInitialState, string lpName)`**
Creates or opens a named or unnamed event object.
- **`int CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition, uint dwFlagsAndAttributes, int hTemplateFile)`**
Creates or opens a file or I/O device (e.g., USB device).
- **`int GetLastError()`**
Retrieves the calling threads last-error code.
- **`int ReadFile(int hFile, ref byte lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, int lpOverlapped)`**
Reads from a file or device (note: `lpOverlapped` is `int`, not `ref OVERLAPPED`).
- **`uint WaitForSingleObject(int hHandle, int dwMilliseconds)`**
Waits until the specified object is in the signaled state or the time-out interval elapses.
- **`int WriteFile(int hFile, ref byte lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, int lpOverlapped)`**
Writes to a file or device.
- **`int DeviceIoControl(IntPtr hDevice, int dwIoControlCode, ref short lpInBuffer, int nInBufferSize, IntPtr lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned, IntPtr lpOverlapped)`**
Sends a control code directly to a device driver.
### `FileIO` class (namespace `DTS.Common.USBFramework`)
- **`const short FILE_ATTRIBUTE_NORMAL = 0x80`**, **`FILE_FLAG_OVERLAPPED = 0x40000000`**, etc.
Duplicate constants (with different types) from `FileIODeclarations`.
- **`struct SECURITY_ATTRIBUTES`**
Alternate definition with `lpSecurityDescriptor` as `IntPtr` (inconsistent with `FileIODeclarations`).
- **`bool CloseHandle(SafeFileHandle hObject)`**
Managed wrapper for closing a `SafeFileHandle`.
- **`SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, ref SECURITY_ATTRIBUTES lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile)`**
Managed wrapper returning `SafeFileHandle`.
### `HIDDeclarations` class (namespace `DTS.DASLib.Connection.USBFramework`)
- **`const short HidP_Input = 0`, `HidP_Output = 1`, `HidP_Feature = 2`**
Report types for HID operations.
- **`struct HIDD_ATTRIBUTES`**
Contains vendor ID, product ID, and version number.
- **`struct HIDP_CAPS`**
Contains HID device capabilities (report sizes, usage pages, etc.).
- **`struct HidP_Value_Caps`**
Describes value capabilities (e.g., range, usage, min/max).
- **`bool HidD_FlushQueue(int HidDeviceObject)`**
Flushes the input buffer of an HID device.
- **`bool HidD_FreePreparsedData(ref IntPtr PreparsedData)`**
Frees preparsed data allocated by `HidD_GetPreparsedData`.
- **`int HidD_GetAttributes(int HidDeviceObject, ref HIDD_ATTRIBUTES Attributes)`**
Retrieves device attributes (VID, PID, version).
- **`bool HidD_GetFeature(int HidDeviceObject, ref byte lpReportBuffer, int ReportBufferLength)`**
Retrieves a feature report from the device.
- **`bool HidD_GetInputReport(int HidDeviceObject, ref byte lpReportBuffer, int ReportBufferLength)`**
Retrieves an input report from the device.
- **`void HidD_GetHidGuid(ref Guid HidGuid)`**
Retrieves the system-defined GUID for HID devices.
- **`bool HidD_GetNumInputBuffers(int HidDeviceObject, ref int NumberBuffers)`**
Gets the number of input buffers allocated for the device.
- **`bool HidD_GetPreparsedData(int HidDeviceObject, ref IntPtr PreparsedData)`**
Retrieves preparsed data for HID device.
- **`bool HidD_SetFeature(int HidDeviceObject, ref byte lpReportBuffer, int ReportBufferLength)`**
Sends a feature report to the device.
- **`bool HidD_SetNumInputBuffers(int HidDeviceObject, int NumberBuffers)`**
Sets the number of input buffers.
- **`bool HidD_SetOutputReport(int HidDeviceObject, ref byte lpReportBuffer, int ReportBufferLength)`**
Sends an output report to the device.
- **`int HidP_GetCaps(IntPtr PreparsedData, ref HIDP_CAPS Capabilities)`**
Retrieves HID capabilities from preparsed data.
- **`int HidP_GetValueCaps(short ReportType, ref byte ValueCaps, ref short ValueCapsLength, IntPtr PreparsedData)`**
Retrieves value capability information.
### `DeviceManagement` class (namespace `DTS.Common.USBFramework`)
- **`bool DeviceNameMatch(Message m, string mydevicePathName)`**
Compares the device path in a `WM_DEVICECHANGE` message with `mydevicePathName`. Returns `true` if they match (case-insensitive). Uses `DEV_BROADCAST_DEVICEINTERFACE_1` to extract the device name from the messages `LParam`.
- **`bool FindDeviceFromGuid(Guid myGuid, ref string[] devicePathName)`**
Enumerates devices in the interface class specified by `myGuid` and populates `devicePathName` with their device paths. Returns `true` if at least one device is found. Uses `SetupDiGetClassDevs`, `SetupDiEnumDeviceInterfaces`, and `SetupDiGetDeviceInterfaceDetail`.
- **`bool RegisterForDeviceNotifications(IntPtr formHandle, Guid classGuid, ref IntPtr deviceNotificationHandle)`**
Registers a window (`formHandle`) to receive `WM_DEVICECHANGE` notifications for devices in `classGuid`. Returns `true` on success. Allocates unmanaged memory for `DEV_BROADCAST_DEVICEINTERFACE` and calls `RegisterDeviceNotification`.
- **`void StopReceivingDeviceNotifications(IntPtr deviceNotificationHandle)`**
Unregisters device notifications using `UnregisterDeviceNotification`. Ignores failures.
- **`bool GetDeviceRegistryProperty(Guid myGuid)`**
Enumerates devices in `myGuid`s class and retrieves the `SPDRP_DRIVER` registry property for each device. Logs results via `APILogger`. Returns `true` on success (even if no devices found).
## 3. Invariants
- **Handle Validity**: All handle-based APIs (`CreateFile`, `RegisterDeviceNotification`) return `INVALID_HANDLE_VALUE` (-1) or `IntPtr.Zero` on failure. Callers must check return values before use.
- **Memory Management**: Unmanaged memory allocated via `Marshal.AllocHGlobal` (e.g., in `FindDeviceFromGuid`, `RegisterForDeviceNotifications`) must be freed with `Marshal.FreeHGlobal`. The `DeviceManagement` class handles this in `try/finally` blocks.
- **Structure Size Consistency**: The `cbSize` field of `SP_DEVICE_INTERFACE_DETAIL_DATA` must be set to `Marshal.SizeOf()` *before* calling `SetupDiGetDeviceInterfaceDetail`. The implementation writes `cbSize` manually to the unmanaged buffer, with logic to handle 32/64-bit alignment.
- **64-bit Compatibility**: `IS64_BIT_PROCESS` (set via `IntPtr.Size == 8`) is used to adjust pointer arithmetic (e.g., `cbSize` offset, handle comparison). This is critical for `FindDeviceFromGuid` and `RegisterForDeviceNotifications`.
- **HID Report Buffer Size**: `HidD_GetFeature`, `HidD_SetFeature`, etc., require the report buffer to be exactly `InputReportByteLength`/`OutputReportByteLength`/`FeatureReportByteLength` bytes (from `HIDP_CAPS`), including the report ID byte.
- **GUID Consistency**: The `HidD_GetHidGuid` function populates a `Guid` by reference; callers must pass a valid `Guid` instance (not `Guid.Empty`).
## 4. Dependencies
### Imports/References:
- **System.Runtime.InteropServices**: Required for P/Invoke, `Marshal`, `StructLayout`.
- **Microsoft.Win32.SafeHandles**: Used in `FileIO.CloseHandle` (via `SafeFileHandle`).
- **System.Windows.Forms**: Required for `Message` type in `DeviceNameMatch`.
- **DTS.Common.Utilities.Logging**: Used for `APILogger.Log` in `GetDeviceRegistryProperty`.
- **hid.dll**, **setupapi.dll**, **kernel32.dll**, **advapi32.dll**: Native libraries for HID, device setup, and registry operations.
### Dependencies on Other Modules:
- **`DeviceManagement`** depends on `DeviceManagementDeclarations` for unmanaged API declarations.
- **`FileIO`** and **`FileIODeclarations`** provide overlapping declarations (likely legacy duplication).
- **`HIDDeclarations`** is in a different namespace (`DTS.DASLib.Connection.USBFramework`) and is used by HID-specific communication logic (not shown here).
### Used By:
- Higher-level USB connection classes (e.g., `USBConnection`, `HIDConnection`) that consume `DeviceManagement` for device discovery and `HIDDeclarations` for HID I/O.
## 5. Gotchas
- **Duplicate Constants**: `FileIO` and `FileIODeclarations` define identical constants (e.g., `GENERIC_READ`, `FILE_FLAG_OVERLAPPED`) with inconsistent types (`uint` vs `short`/`int`). This may cause confusion or errors if mixed.
- **Inconsistent Structure Definitions**: `SECURITY_ATTRIBUTES` is defined twice in `FileIODeclarations` and `FileIO` with different field types (`int` vs `IntPtr`). This is unsafe and may cause crashes on 64-bit systems.
- **`OVERLAPPED` Structure**: The `OVERLAPPED` struct uses `int` for `hEvent` instead of `IntPtr`, which is incorrect for 64-bit compatibility. This will fail on 64-bit processes.
- **`CreateFile` Overloads**: `FileIODeclarations.CreateFile` returns `int` (unmanaged handle), while `FileIO.CreateFile` returns `SafeFileHandle`. Using the wrong overload may lead to resource leaks or handle misuse.
- **`RegisterForDeviceNotifications` Memory Leak Risk**: The `buffer` allocated via `Marshal.AllocHGlobal` is freed *after* `RegisterDeviceNotification`, but if `RegisterDeviceNotification` fails, the handle is `IntPtr.Zero`, and the buffer is still freed. This is safe, but the comment `// Set fDeleteOld True to prevent memory leaks` is misleading—the `true` flag in `StructureToPtr` overwrites the old pointer, but `AllocHGlobal`/`FreeHGlobal` is still required.
- **`FindDeviceFromGuid` Buffer Size Calculation**: The `cbSize` offset calculation `(IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8` assumes `cbSize` is 4 bytes on 32-bit and 8 on 64-bit, but `SP_DEVICE_INTERFACE_DETAIL_DATA.cbSize` is `int` (4 bytes) regardless of platform. This may cause misalignment on 64-bit.
- **`DeviceNameMatch` String Size Calculation**: Assumes `dbcc_name` is Unicode (2 bytes/char) and subtracts 28 bytes for fixed fields. This is correct for `DEV_BROADCAST_DEVICEINTERFACE_1` but may break if structure layout changes.
- **`GetDeviceRegistryProperty` Registry Key Access**: Uses `SetupDiOpenDevRegKey` but does not show its usage; the implementation only retrieves `SPDRP_DRIVER` via `SetupDiGetDeviceRegistryPropertyA`. Registry access may fail without elevated privileges.
- **`HIDP_*` Functions**: Return codes (e.g., `HidP_GetCaps`) are `int` but not documented. Callers must check for success (typically `0` for success, non-zero for error codes like `HIDP_STATUS_BUFFER_TOO_SMALL`).
- **No Async Support**: Despite `FILE_FLAG_OVERLAPPED` being defined, the `ReadFile`/`WriteFile` declarations use synchronous signatures (no `OVERLAPPED` pointer). Asynchronous I/O is not implemented.