HIDUSBConnection is a concrete implementation of the IConnection interface that enables communication with a specific HID-class USB device (identified by Vendor ID 0x1CB9 and Product ID 0x0003, named HIDSLICE) using Windows file I/O APIs (CreateFile, ReadFile, WriteFile via overlapped I/O). It abstracts low-level HID report handling (input/output reports) over USB, providing asynchronous send/receive semantics consistent with .NET’s IAsyncResult pattern. This module exists to support direct, low-latency data transfer to/from embedded hardware (e.g., a data acquisition recorder) where standard socket-based communication is not applicable.
2. Public Interface
Constructors & Finalizer
HIDUSBConnection()
Initializes the instance, sets up SECURITY_ATTRIBUTES for CreateFile, and initializes _Connected = false.
~HIDUSBConnection()
Finalizer that invokes Dispose(false) to release unmanaged resources.
Disposal
void Dispose()
Performs deterministic cleanup: calls Dispose(true) and suppresses finalization.
protected virtual void Dispose(bool disposing)
Releases all handles (_HIDHandle, _ReadHandle, _WriteHandle) via FileIODeclarations.CloseHandle, disposes _MyHID, and sets _Connected = false. Idempotent (disposed flag prevents double-disposal).
Connection Management
void Create(string ConnectString)
Stores the device path (ConnectString) for later use in EndConnect. Does not open the device.
IAsyncResult BeginConnect(AsyncCallback cb, object state)
Initiates asynchronous connection. Enqueues a work item to invoke NetCallbackFix, which in turn invokes the callback on the thread pool. Actual device opening occurs in EndConnect.
void EndConnect(IAsyncResult ar)
Opens the device using ConnectString (set via Create) via three CreateFile calls:
_HIDHandle: for attribute queries (no access rights)
_ReadHandle: for reading input reports (GENERIC_READ)
_WriteHandle: for writing output reports (GENERIC_WRITE)
Retrieves device attributes (HidD_GetAttributes), capabilities (GetDeviceCapabilities), and input report buffer size (GetInputReportBufferSize). Flushes the input queue. Sets _Connected = true. Throws on handle failure or attribute retrieval failure.
IAsyncResult BeginDisconnect(bool reuseSocket, AsyncCallback cb, object state)
Asynchronous disconnect. Enqueues a work item to invoke the callback. Actual cleanup is deferred to EndDisconnect.
void EndDisconnect(IAsyncResult asyncResult)
Closes all three handles (_HIDHandle, _ReadHandle, _WriteHandle) and sets _Connected = false.
Properties
bool Connected { get; }
Returns _Connected.
string ConnectString { get; }
Returns Device_Name (set via Create).
System.Net.Sockets.SocketFlags Flags { get; set; }
Property required by IConnection interface; unused in this implementation.
string GetConnectionData()
Returns "" (empty string). No meaningful data exposed.
double GetCurrentDownloadRate()
Returns 0D. Rate tracking not implemented.
double GetCurrentUploadRate()
Returns 0D. Rate tracking not implemented.
Static Utility
static string GetFirstConnectString()
Scans all HID devices on the system to find the first device matching DTS_VID (0x1CB9) and HIDSLICE_PID (0x0003). Returns the device’s path string (e.g., \\?\hid#vid_1cb9&pid_0003#...) or string.Empty if not found. Uses HIDDeclarations.HidD_GetHidGuid, DeviceManagement.FindDeviceFromGuid, and HIDDeclarations.HidD_GetAttributes.
I/O Operations
IAsyncResult BeginSend(byte[] buffer, int offset, int size, AsyncCallback cb, object state)
Initiates asynchronous send. Validates _ReadHandle and _WriteHandle are valid. Enqueues callback via ThreadPool.QueueUserWorkItem. Actual transmission occurs in EndSend.
int EndSend(IAsyncResult ar)
Writes buffer[offset..offset+size) to the device in chunks, respecting OutputReportByteLength.
Prepends each chunk with report ID 0x00 at index 0.
Uses HIDevice.OutputReport.Write for each chunk.
Returns size (number of bytes sent). Throws on invalid handles or write failure.
IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback cb, object state)
Initiates asynchronous receive. Validates handles. Enqueues callback. Actual read occurs in EndReceive.
int EndReceive(IAsyncResult ar)
Reads one input report into InputReportBuffer via HIDevice.InputReport.Read. Copies data (skipping report ID at index 0) into buffer[offset..]. Returns size if successful, 0 otherwise. Sets IsCompleted = true and signals AsyncWaitHandle.
BeginAccept, EndAccept, Bind(int), Listen(int)
These methods are implemented only to satisfy IConnection but are not applicable to HID device communication.
3. Invariants
Device Identity: Only devices with VendorID == 0x1CB9 and ProductID == 0x0003 are accepted.
Handle State: _HIDHandle, _ReadHandle, and _WriteHandle must be valid (non-INVALID_HANDLE_VALUE) before BeginSend/BeginReceive succeeds.
Connection State: _Connected is true only after successful completion of EndConnect, and false otherwise (including after EndDisconnect or disposal).
Report Structure:
Input reports: Data starts at index 1; index 0 is the report ID (ignored).
Output reports: Data starts at index 1; index 0 is report ID (set to 0).
Buffer Size: InputReportBuffer is sized to _MyHID.Capabilities.InputReportByteLength during EndConnect.
Disposal Safety: Dispose is idempotent (disposed flag prevents re-entry).
Asynchronous Pattern: All async operations (BeginConnect, BeginSend, etc.) use HIDUSBRecAsyncResult and delegate callback invocation to NetCallbackFix, which runs on a thread pool thread.
System.Windows.Forms.MessageBox (used in NetCallbackFix for exception reporting—potential runtime dependency on WinForms).
Implemented Interfaces
IConnection (interface defining the contract; not shown in source but referenced).
Inferred Consumers
Any code requiring IConnection to communicate with the HIDSLICE device (e.g., data acquisition logic, device enumeration UI).
GetFirstConnectString is likely called by device discovery components.
5. Gotchas
Misleading Async Pattern: BeginConnect/BeginSend/BeginReceive do not perform actual I/O; they only enqueue a callback. All work happens in End* methods. This deviates from typical .NET async patterns where Begin* initiates the operation.
No Overlapped I/O: Despite using CreateFile with overlapped semantics (implied by _ReadHandle/_WriteHandle), the code does not use OVERLAPPED structures or ReadFile/WriteFile with completion callbacks. Instead, it relies on synchronous HIDevice.InputReport.Read/Write, which may block the thread pool thread.
Hardcoded Report ID: Output reports always use 0x00 as the report ID. This assumes the device expects report ID 0; mismatched IDs will cause silent failures or device errors.
WinForms Dependency in Error Handling: NetCallbackFix shows a MessageBox on exceptions—a severe anti-pattern for non-UI threads or server environments.
GetFirstConnectString Hack: The method scans all HID devices and stops at the first match. If multiple HIDSLICE devices are connected, behavior is undefined (first found wins).
Buffer Size Mismatch in EndReceive: EndReceive copies InputReportBuffer.Length - 1 bytes into the user buffer, but returns rar.size regardless. If rar.size < InputReportBuffer.Length - 1, the caller may read uninitialized buffer data beyond the actual received payload.
No Timeout Handling: No mechanism for read/write timeouts; operations may block indefinitely.
Flags Property Unused: The SocketFlags property is implemented but never used.
BeginAccept/EndAccept Misuse: Throwing NotSupportedException for connection-oriented methods suggests this class was adapted from a socket-based IConnection implementation without full refactoring.