Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.IConnection/USBConnection/USBFramework.md

158 lines
13 KiB
Markdown
Raw Normal View History

2026-04-17 14:55:32 -04:00
---
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.