# HG changeset patch
# User sl
# Date 1400046741 -7200
# Node ID 316364bd7d25589d1784d41bff2c790b7ee60fff
First drop from janaxelson.com
diff -r 000000000000 -r 316364bd7d25 AssemblyInfo.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/AssemblyInfo.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,28 @@
+using System.Reflection;
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly
+
+[ assembly: AssemblyTitle( "USB test application for HIDs" ) ]
+[ assembly: AssemblyDescription( "www.Lvr.com" ) ]
+[ assembly: AssemblyCompany( "Lakeview Research" ) ]
+[ assembly: AssemblyProduct( "usbhidio" ) ]
+[ assembly: AssemblyCopyright( "c. 1999-2005 by Jan Axelson" ) ]
+[ assembly: AssemblyTrademark( "" ) ]
+[ assembly: AssemblyCulture( "" ) ]
+
+// Version information for an assembly consists of the following four values:
+
+// Major version
+// Minor Version
+// Revision
+// Build Number
+
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below
+
+
+[ assembly: AssemblyVersion( "2.2.*" ) ]
+
+
+
diff -r 000000000000 -r 316364bd7d25 ClassDiagram1.cd
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ClassDiagram1.cd Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,65 @@
+
+
+
+
+
+ AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=
+ Debugging.cs
+
+
+
+
+
+ AAAAIQAAAAACEAABAAEAAEAgBDAgAIAQCEIAgBkAAAA=
+ DeviceManagement.cs
+
+
+
+
+
+ AAQAAAAAAAAAAAAAgAQAgAgAAAAAAAAAAAABAAAAAAQ=
+ FileIODeclarations.cs
+
+
+
+
+
+
+
+ FrmMain.cs
+
+
+
+
+ ICUA1BAQNaMYBREAgFCQgUIDUERCJwAKCDHCxEEQUEA=
+ FrmMain.cs
+
+
+
+
+
+ AAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAABAAAAAA=
+ GenericHid.cs
+
+
+
+
+
+ ADSAUARIUAAAgAQAAAAJAFEAAEgAAAAAACgVABgAACE=
+ Hid.cs
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAABEAAAAQAAAAAAAAAAAAAAAIA=
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAAAIAAAAAABAAAAAAAAAAAAAAA=
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r 316364bd7d25 Debugging.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Debugging.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,47 @@
+using System;
+
+namespace GenericHid
+{
+ ///
+ /// Used only in Debug.Write statements.
+ ///
+ ///
+ internal sealed partial class Debugging
+ {
+ ///
+ /// Get text that describes the result of an API call.
+ ///
+ ///
+ /// the name of the API function.
+ ///
+ ///
+ /// The text.
+ ///
+
+ internal String ResultOfApiCall( String functionName )
+ {
+ var resultString = new String(Convert.ToChar( 0 ), 129 );
+
+ // Returns the result code for the last API call.
+
+ Int32 resultCode = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
+
+ // Get the result message that corresponds to the code.
+
+ Int64 temp = 0;
+ Int32 bytes = NativeMethods.FormatMessage(NativeMethods.FormatMessageFromSystem, ref temp, resultCode, 0, resultString, 128, 0);
+
+ // Subtract two characters from the message to strip the CR and LF.
+
+ if ( bytes > 2 )
+ {
+ resultString = resultString.Remove( bytes - 2, 2 );
+ }
+ // Create the String to return.
+
+ resultString = Environment.NewLine + functionName + Environment.NewLine + "Result = " + resultString + Environment.NewLine;
+
+ return resultString;
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 DebuggingDeclarations.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DebuggingDeclarations.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,21 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace GenericHid
+{
+ ///
+ /// Win32 API declarations for Debug.Write statements.
+ ///
+ ///
+ internal sealed partial class Debugging
+ {
+ internal static class NativeMethods
+ {
+ internal const Int16 FormatMessageFromSystem = 0X1000;
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern Int32 FormatMessage(Int32 dwFlags, ref Int64 lpSource, Int32 dwMessageId, Int32 dwLanguageZId,
+ String lpBuffer, Int32 nSize, Int32 arguments);
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 DeviceManagement.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceManagement.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,252 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+namespace GenericHid
+{
+ ///
+ /// Routine for detecting devices using Win32 SetupDi functions.
+ ///
+ ///
+ sealed internal partial class DeviceManagement
+ {
+ private const String ModuleName = "Device Management";
+
+ ///
+ /// Provides a central mechanism for exception handling.
+ /// Displays a message box that describes the exception.
+ ///
+ ///
+ /// the module where the exception occurred.
+ /// the exception
+
+ internal static void DisplayException(String name, Exception e)
+ {
+ try
+ {
+ // Create an error message.
+
+ String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + name + Environment.NewLine + "Method: " +
+ e.TargetSite.Name;
+
+ const String caption = "Unexpected Exception";
+
+ MessageBox.Show(message, caption, MessageBoxButtons.OK);
+ Debug.Write(message);
+ }
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Use SetupDi API functions to retrieve the device path name of an
+ /// attached device that belongs to a device interface class.
+ ///
+ ///
+ /// an interface class GUID.
+ /// a pointer to the device path name
+ /// of an attached device.
+ ///
+ ///
+ /// True if a device is found, False if not.
+ ///
+
+ internal Boolean FindDeviceFromGuid(Guid myGuid, ref String[] devicePathName)
+ {
+ Int32 bufferSize = 0;
+ var deviceInfoSet = new IntPtr();
+ Boolean lastDevice = false;
+ var myDeviceInterfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA();
+
+ try
+ {
+ Int32 memberIndex;
+
+ // ***
+ // API function
+
+ // summary
+ // Retrieves a device information set for a specified group of devices.
+ // SetupDiEnumDeviceInterfaces uses the device information set.
+
+ // parameters
+ // Interface class GUID.
+ // Null to retrieve information for all device instances.
+ // Optional handle to a top-level window (unused here).
+ // Flags to limit the returned information to currently present devices
+ // and devices that expose interfaces in the class specified by the GUID.
+
+ // Returns
+ // Handle to a device information set for the devices.
+ // ***
+
+ deviceInfoSet = NativeMethods.SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, NativeMethods.DIGCF_PRESENT | NativeMethods.DIGCF_DEVICEINTERFACE);
+
+ bool deviceFound = false;
+ memberIndex = 0;
+
+ // The cbSize element of the MyDeviceInterfaceData structure must be set to
+ // the structure's size in bytes.
+ // The size is 28 bytes for 32-bit code and 32 bits for 64-bit code.
+
+ myDeviceInterfaceData.cbSize = Marshal.SizeOf(myDeviceInterfaceData);
+
+ do
+ {
+ // Begin with 0 and increment through the device information set until
+ // no more devices are available.
+
+ // ***
+ // API function
+
+ // summary
+ // Retrieves a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
+ // On return, MyDeviceInterfaceData contains the handle to a
+ // SP_DEVICE_INTERFACE_DATA structure for a detected device.
+
+ // parameters
+ // DeviceInfoSet returned by SetupDiGetClassDevs.
+ // Optional SP_DEVINFO_DATA structure that defines a device instance
+ // that is a member of a device information set.
+ // Device interface GUID.
+ // Index to specify a device in a device information set.
+ // Pointer to a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
+
+ // Returns
+ // True on success.
+ // ***
+
+ Boolean success = NativeMethods.SetupDiEnumDeviceInterfaces
+ (deviceInfoSet,
+ IntPtr.Zero,
+ ref myGuid,
+ memberIndex,
+ ref myDeviceInterfaceData);
+
+ // Find out if a device information set was retrieved.
+
+ if (!success)
+ {
+ lastDevice = true;
+ }
+ else
+ {
+ // A device is present.
+
+ // ***
+ // API function:
+
+ // summary:
+ // Retrieves an SP_DEVICE_INTERFACE_DETAIL_DATA structure
+ // containing information about a device.
+ // To retrieve the information, call this function twice.
+ // The first time returns the size of the structure.
+ // The second time returns a pointer to the data.
+
+ // parameters
+ // DeviceInfoSet returned by SetupDiGetClassDevs
+ // SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces
+ // A returned pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA
+ // Structure to receive information about the specified interface.
+ // The size of the SP_DEVICE_INTERFACE_DETAIL_DATA structure.
+ // Pointer to a variable that will receive the returned required size of the
+ // SP_DEVICE_INTERFACE_DETAIL_DATA structure.
+ // Returned pointer to an SP_DEVINFO_DATA structure to receive information about the device.
+
+ // Returns
+ // True on success.
+ // ***
+
+ NativeMethods.SetupDiGetDeviceInterfaceDetail
+ (deviceInfoSet,
+ ref myDeviceInterfaceData,
+ IntPtr.Zero,
+ 0,
+ ref bufferSize,
+ IntPtr.Zero);
+
+ // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size.
+
+ IntPtr detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
+
+ // Store cbSize in the first bytes of the array. Adjust for 32- and 64-bit systems.
+
+ Int32 cbsize;
+
+ if (IntPtr.Size == 4)
+ {
+ cbsize = 4 + Marshal.SystemDefaultCharSize;
+ }
+ else
+ {
+ cbsize = 8;
+ }
+
+ Marshal.WriteInt32(detailDataBuffer, cbsize);
+
+ // Call SetupDiGetDeviceInterfaceDetail again.
+ // This time, pass a pointer to DetailDataBuffer
+ // and the returned required buffer size.
+
+ NativeMethods.SetupDiGetDeviceInterfaceDetail
+ (deviceInfoSet,
+ ref myDeviceInterfaceData,
+ detailDataBuffer,
+ bufferSize,
+ ref bufferSize,
+ IntPtr.Zero);
+
+ // Get the address of the devicePathName.
+
+ var pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
+
+ // Get the String containing the devicePathName.
+
+ devicePathName[memberIndex] = Marshal.PtrToStringAuto(pDevicePathName);
+
+ if (detailDataBuffer != IntPtr.Zero)
+ {
+ // Free the memory allocated previously by AllocHGlobal.
+
+ Marshal.FreeHGlobal(detailDataBuffer);
+ }
+ deviceFound = true;
+ }
+ memberIndex = memberIndex + 1;
+ }
+ while (!lastDevice);
+
+ return deviceFound;
+ }
+ finally
+ {
+ // ***
+ // API function
+
+ // summary
+ // Frees the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs.
+
+ // parameters
+ // DeviceInfoSet returned by SetupDiGetClassDevs.
+
+ // returns
+ // True on success.
+ // ***
+
+ if (deviceInfoSet != IntPtr.Zero)
+ {
+ NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
diff -r 000000000000 -r 316364bd7d25 DeviceManagementDeclarations.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/DeviceManagementDeclarations.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,58 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace GenericHid
+{
+ internal sealed partial class DeviceManagement
+ {
+ internal static class NativeMethods
+ {
+ ///
+ // API declarations relating to device management (SetupDixxx and
+ // RegisterDeviceNotification functions).
+ ///
+
+ // from setupapi.h
+
+ internal const Int32 DIGCF_PRESENT = 2;
+ internal const Int32 DIGCF_DEVICEINTERFACE = 0X10;
+
+ internal struct SP_DEVICE_INTERFACE_DATA
+ {
+ internal Int32 cbSize;
+ internal Guid InterfaceClassGuid;
+ internal Int32 Flags;
+ internal IntPtr Reserved;
+ }
+
+ internal struct SP_DEVICE_INTERFACE_DETAIL_DATA
+ {
+ internal Int32 cbSize;
+ internal String DevicePath;
+ }
+
+ internal struct SP_DEVINFO_DATA
+ {
+ internal Int32 cbSize;
+ internal Guid ClassGuid;
+ internal Int32 DevInst;
+ internal Int32 Reserved;
+ }
+
+ [DllImport("setupapi.dll", SetLastError = true)]
+ internal static extern IntPtr SetupDiCreateDeviceInfoList(ref Guid ClassGuid, IntPtr hwndParent);
+
+ [DllImport("setupapi.dll", SetLastError = true)]
+ internal static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
+
+ [DllImport("setupapi.dll", SetLastError = true)]
+ internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, Int32 MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ internal static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, Int32 Flags);
+
+ [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, IntPtr DeviceInfoData);
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 FileIODeclarations.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FileIODeclarations.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,23 @@
+using Microsoft.Win32.SafeHandles;
+using System.Runtime.InteropServices;
+using System;
+
+namespace GenericHid
+{
+ ///
+ /// Win32 API declarations relating to file I/O.
+ ///
+ ///
+ internal sealed class FileIo
+ {
+ internal const Int32 FileShareRead = 1;
+ internal const Int32 FileShareWrite = 2;
+ internal const uint GenericRead = 0X80000000U;
+ internal const Int32 GenericWrite = 0X40000000;
+ internal const Int32 InvalidHandleValue = -1;
+ internal const Int32 OpenExisting = 3;
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, Int32 dwShareMode, IntPtr lpSecurityAttributes, Int32 dwCreationDisposition, Int32 dwFlagsAndAttributes, IntPtr hTemplateFile);
+ }
+}
diff -r 000000000000 -r 316364bd7d25 FrmMain.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FrmMain.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,2582 @@
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Management;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Timers;
+using System.Windows.Forms;
+
+namespace GenericHid
+{
+ ///
+ /// Project: GenericHid
+ ///
+ /// ***********************************************************************
+ /// Software License Agreement
+ ///
+ /// Licensor grants any person obtaining a copy of this software ("You")
+ /// a worldwide, royalty-free, non-exclusive license, for the duration of
+ /// the copyright, free of charge, to store and execute the Software in a
+ /// computer system and to incorporate the Software or any portion of it
+ /// in computer programs You write.
+ ///
+ /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ /// THE SOFTWARE.
+ /// ***********************************************************************
+ ///
+ /// Author
+ /// Jan Axelson
+ ///
+ /// This software was written using Visual Studio Express 2012 for Windows
+ /// Desktop building for the .NET Framework v4.5.
+ ///
+ /// Purpose:
+ /// Demonstrates USB communications with a generic HID-class device
+ ///
+ /// Requirements:
+ /// Windows Vista or later and an attached USB generic Human Interface Device (HID).
+ /// (Does not run on Windows XP or earlier because .NET Framework 4.5 will not install on these OSes.)
+ ///
+ /// Description:
+ /// Finds an attached device that matches the vendor and product IDs in the form's
+ /// text boxes.
+ ///
+ /// Retrieves the device's capabilities.
+ /// Sends and requests HID reports.
+ ///
+ /// Uses the System.Management class and Windows Management Instrumentation (WMI) to detect
+ /// when a device is attached or removed.
+ ///
+ /// A list box displays the data sent and received along with error and status messages.
+ /// You can select data to send and 1-time or periodic transfers.
+ ///
+ /// You can change the size of the host's Input report buffer and request to use control
+ /// transfers only to exchange Input and Output reports.
+ ///
+ /// To view additional debugging messages, in the Visual Studio development environment,
+ /// from the main menu, select Build > Configuration Manager > Active Solution Configuration
+ /// and select Configuration > Debug and from the main menu, select View > Output.
+ ///
+ /// The application uses asynchronous FileStreams to read Input reports and write Output
+ /// reports so the application's main thread doesn't have to wait for the device to retrieve a
+ /// report when the HID driver's buffer is empty or send a report when the device's endpoint is busy.
+ ///
+ /// For code that finds a device and opens handles to it, see the FindTheHid routine in frmMain.cs.
+ /// For code that reads from the device, see GetInputReportViaInterruptTransfer,
+ /// GetInputReportViaControlTransfer, and GetFeatureReport in Hid.cs.
+ /// For code that writes to the device, see SendInputReportViaInterruptTransfer,
+ /// SendInputReportViaControlTransfer, and SendFeatureReport in Hid.cs.
+ ///
+ /// This project includes the following modules:
+ ///
+ /// GenericHid.cs - runs the application.
+ /// FrmMain.cs - routines specific to the form.
+ /// Hid.cs - routines specific to HID communications.
+ /// DeviceManagement.cs - routine for obtaining a handle to a device from its GUID.
+ /// Debugging.cs - contains a routine for displaying API error messages.
+ /// HidDeclarations.cs - Declarations for API functions used by Hid.cs.
+ /// FileIODeclarations.cs - Declarations for file-related API functions.
+ /// DeviceManagementDeclarations.cs - Declarations for API functions used by DeviceManagement.cs.
+ /// DebuggingDeclarations.cs - Declarations for API functions used by Debugging.cs.
+ ///
+ /// Companion device firmware for several device CPUs is available from www.Lvr.com/hidpage.htm
+ /// You can use any generic HID (not a system mouse or keyboard) that sends and receives reports.
+ /// This application will not detect or communicate with non-HID-class devices.
+ ///
+ /// For more information about HIDs and USB, and additional example device firmware to use
+ /// with this application, visit Lakeview Research at http://Lvr.com
+ /// Send comments, bug reports, etc. to jan@Lvr.com or post on my PORTS forum: http://www.lvr.com/forum
+ ///
+ /// V6.2
+ /// 11/12/13
+ /// Disabled form buttons when a transfer is in progress.
+ /// Other minor edits for clarity and readability.
+ /// Will NOT run on Windows XP or earlier, see below.
+ ///
+ /// V6.1
+ /// 10/28/13
+ /// Uses the .NET System.Management class to detect device arrival and removal with WMI instead of Win32 RegisterDeviceNotification.
+ /// Other minor edits.
+ /// Will NOT run on Windows XP or earlier, see below.
+ ///
+ /// V6.0
+ /// 2/8/13
+ /// This version will NOT run on Windows XP or earlier because the code uses .NET Framework 4.5 to support asynchronous FileStreams.
+ /// The .NET Framework 4.5 redistributable is compatible with Windows 8, Windows 7 SP1, Windows Server 2008 R2 SP1,
+ /// Windows Server 2008 SP2, Windows Vista SP2, and Windows Vista SP3.
+ /// For compatibility, replaced ToInt32 with ToInt64 here:
+ /// IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
+ /// and here:
+ /// if ((deviceNotificationHandle.ToInt64() == IntPtr.Zero.ToInt64()))
+ /// For compatibility if the charset isn't English, added System.Globalization.CultureInfo.InvariantCulture here:
+ /// if ((String.Compare(DeviceNameString, mydevicePathName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))
+ /// Replaced all Microsoft.VisualBasic namespace code with other .NET equivalents.
+ /// Revised user interface for more flexibility.
+ /// Moved interrupt-transfer and other HID-specific code to Hid.cs.
+ /// Used JetBrains ReSharper to clean up the code: http://www.jetbrains.com/resharper/
+ ///
+ /// V5.0
+ /// 3/30/11
+ /// Replaced ReadFile and WriteFile with FileStreams. Thanks to Joe Dunne and John on my Ports forum for tips on this.
+ /// Simplified Hid.cs.
+ /// Replaced the form timer with a system timer.
+ ///
+ /// V4.6
+ /// 1/12/10
+ /// Supports Vendor IDs and Product IDs up to FFFFh.
+ ///
+ /// V4.52
+ /// 11/10/09
+ /// Changed HIDD_ATTRIBUTES to use UInt16
+ ///
+ /// V4.51
+ /// 2/11/09
+ /// Moved Free_ and similar to Finally blocks to ensure they execute.
+ ///
+ /// V4.5
+ /// 2/9/09
+ /// Changes to support 64-bit systems, memory management, and other corrections.
+ /// Big thanks to Peter Nielsen.
+ ///
+ ///
+
+ internal class FrmMain
+ : Form
+ {
+ #region '"Windows Form Designer generated code "'
+ public FrmMain()
+ //: base()
+ {
+ // This call is required by the Windows Form Designer.
+ InitializeComponent();
+ }
+ // Form overrides dispose to clean up the component list.
+ protected override void Dispose(bool Disposing1)
+ {
+ if (Disposing1)
+ {
+ if (components != null)
+ {
+ components.Dispose();
+ }
+ }
+ base.Dispose(Disposing1);
+ }
+
+ // Required by the Windows Form Designer
+ private System.ComponentModel.IContainer components;
+ public System.Windows.Forms.ToolTip ToolTip1;
+ public System.Windows.Forms.TextBox TxtBytesReceived;
+ public System.Windows.Forms.GroupBox FraBytesReceived;
+ public System.Windows.Forms.CheckBox ChkAutoincrement;
+ public System.Windows.Forms.ComboBox CboByte1;
+ public System.Windows.Forms.ComboBox CboByte0;
+ public System.Windows.Forms.GroupBox FraBytesToSend;
+ public System.Windows.Forms.ListBox LstResults;
+ // NOTE: The following procedure is required by the Windows Form Designer
+ // It can be modified using the Windows Form Designer.
+ // Do not modify it using the code editor.
+ internal System.Windows.Forms.GroupBox fraInputReportBufferSize;
+ internal System.Windows.Forms.TextBox txtInputReportBufferSize;
+ internal System.Windows.Forms.Button cmdInputReportBufferSize;
+ internal System.Windows.Forms.GroupBox fraDeviceIdentifiers;
+ internal System.Windows.Forms.Label lblVendorID;
+ internal System.Windows.Forms.TextBox txtVendorID;
+ internal System.Windows.Forms.Label lblProductID;
+ internal System.Windows.Forms.TextBox txtProductID;
+ internal System.Windows.Forms.Button cmdFindDevice;
+ private Button cmdGetInputReportInterrupt;
+ public GroupBox fraInterruptTransfers;
+ private Button cmdSendOutputReportControl;
+ private Button cmdGetInputReportControl;
+ public GroupBox fraControlTransfers;
+ private Button cmdGetFeatureReport;
+ private Button cmdSendFeatureReport;
+ private Button cmdPeriodicTransfers;
+ public GroupBox fraSendAndGetContinuous;
+ private RadioButton radFeature;
+ private RadioButton radInputOutputControl;
+ private RadioButton radInputOutputInterrupt;
+ private Button cmdSendOutputReportInterrupt;
+
+ [System.Diagnostics.DebuggerStepThrough()]
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.ToolTip1 = new System.Windows.Forms.ToolTip(this.components);
+ this.FraBytesReceived = new System.Windows.Forms.GroupBox();
+ this.TxtBytesReceived = new System.Windows.Forms.TextBox();
+ this.FraBytesToSend = new System.Windows.Forms.GroupBox();
+ this.ChkAutoincrement = new System.Windows.Forms.CheckBox();
+ this.CboByte1 = new System.Windows.Forms.ComboBox();
+ this.CboByte0 = new System.Windows.Forms.ComboBox();
+ this.LstResults = new System.Windows.Forms.ListBox();
+ this.fraInputReportBufferSize = new System.Windows.Forms.GroupBox();
+ this.cmdInputReportBufferSize = new System.Windows.Forms.Button();
+ this.txtInputReportBufferSize = new System.Windows.Forms.TextBox();
+ this.fraDeviceIdentifiers = new System.Windows.Forms.GroupBox();
+ this.txtProductID = new System.Windows.Forms.TextBox();
+ this.lblProductID = new System.Windows.Forms.Label();
+ this.txtVendorID = new System.Windows.Forms.TextBox();
+ this.lblVendorID = new System.Windows.Forms.Label();
+ this.cmdFindDevice = new System.Windows.Forms.Button();
+ this.cmdSendOutputReportInterrupt = new System.Windows.Forms.Button();
+ this.cmdGetInputReportInterrupt = new System.Windows.Forms.Button();
+ this.fraInterruptTransfers = new System.Windows.Forms.GroupBox();
+ this.cmdPeriodicTransfers = new System.Windows.Forms.Button();
+ this.cmdSendOutputReportControl = new System.Windows.Forms.Button();
+ this.cmdGetInputReportControl = new System.Windows.Forms.Button();
+ this.fraControlTransfers = new System.Windows.Forms.GroupBox();
+ this.cmdGetFeatureReport = new System.Windows.Forms.Button();
+ this.cmdSendFeatureReport = new System.Windows.Forms.Button();
+ this.fraSendAndGetContinuous = new System.Windows.Forms.GroupBox();
+ this.radInputOutputInterrupt = new System.Windows.Forms.RadioButton();
+ this.radInputOutputControl = new System.Windows.Forms.RadioButton();
+ this.radFeature = new System.Windows.Forms.RadioButton();
+ this.FraBytesReceived.SuspendLayout();
+ this.FraBytesToSend.SuspendLayout();
+ this.fraInputReportBufferSize.SuspendLayout();
+ this.fraDeviceIdentifiers.SuspendLayout();
+ this.fraInterruptTransfers.SuspendLayout();
+ this.fraControlTransfers.SuspendLayout();
+ this.fraSendAndGetContinuous.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // fraBytesReceived
+ //
+ this.FraBytesReceived.BackColor = System.Drawing.SystemColors.Control;
+ this.FraBytesReceived.Controls.Add(this.TxtBytesReceived);
+ this.FraBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.FraBytesReceived.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.FraBytesReceived.Location = new System.Drawing.Point(16, 272);
+ this.FraBytesReceived.Name = "FraBytesReceived";
+ this.FraBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.FraBytesReceived.Size = new System.Drawing.Size(112, 136);
+ this.FraBytesReceived.TabIndex = 4;
+ this.FraBytesReceived.TabStop = false;
+ this.FraBytesReceived.Text = "Bytes Received";
+ //
+ // txtBytesReceived
+ //
+ this.TxtBytesReceived.AcceptsReturn = true;
+ this.TxtBytesReceived.BackColor = System.Drawing.SystemColors.Window;
+ this.TxtBytesReceived.Cursor = System.Windows.Forms.Cursors.IBeam;
+ this.TxtBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.TxtBytesReceived.ForeColor = System.Drawing.SystemColors.WindowText;
+ this.TxtBytesReceived.Location = new System.Drawing.Point(18, 24);
+ this.TxtBytesReceived.MaxLength = 0;
+ this.TxtBytesReceived.Multiline = true;
+ this.TxtBytesReceived.Name = "TxtBytesReceived";
+ this.TxtBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.TxtBytesReceived.Size = new System.Drawing.Size(72, 96);
+ this.TxtBytesReceived.TabIndex = 5;
+ //
+ // fraBytesToSend
+ //
+ this.FraBytesToSend.BackColor = System.Drawing.SystemColors.Control;
+ this.FraBytesToSend.Controls.Add(this.ChkAutoincrement);
+ this.FraBytesToSend.Controls.Add(this.CboByte1);
+ this.FraBytesToSend.Controls.Add(this.CboByte0);
+ this.FraBytesToSend.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.FraBytesToSend.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.FraBytesToSend.Location = new System.Drawing.Point(16, 128);
+ this.FraBytesToSend.Name = "FraBytesToSend";
+ this.FraBytesToSend.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.FraBytesToSend.Size = new System.Drawing.Size(160, 136);
+ this.FraBytesToSend.TabIndex = 1;
+ this.FraBytesToSend.TabStop = false;
+ this.FraBytesToSend.Text = "Bytes to Send";
+ //
+ // chkAutoincrement
+ //
+ this.ChkAutoincrement.BackColor = System.Drawing.SystemColors.Control;
+ this.ChkAutoincrement.Cursor = System.Windows.Forms.Cursors.Default;
+ this.ChkAutoincrement.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.ChkAutoincrement.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.ChkAutoincrement.Location = new System.Drawing.Point(8, 96);
+ this.ChkAutoincrement.Name = "ChkAutoincrement";
+ this.ChkAutoincrement.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.ChkAutoincrement.Size = new System.Drawing.Size(201, 35);
+ this.ChkAutoincrement.TabIndex = 6;
+ this.ChkAutoincrement.Text = "Autoincrement values";
+ this.ChkAutoincrement.UseVisualStyleBackColor = false;
+ //
+ // cboByte1
+ //
+ this.CboByte1.BackColor = System.Drawing.SystemColors.Window;
+ this.CboByte1.Cursor = System.Windows.Forms.Cursors.Default;
+ this.CboByte1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.CboByte1.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.CboByte1.ForeColor = System.Drawing.SystemColors.WindowText;
+ this.CboByte1.Location = new System.Drawing.Point(8, 64);
+ this.CboByte1.Name = "CboByte1";
+ this.CboByte1.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.CboByte1.Size = new System.Drawing.Size(101, 22);
+ this.CboByte1.TabIndex = 3;
+ //
+ // cboByte0
+ //
+ this.CboByte0.BackColor = System.Drawing.SystemColors.Window;
+ this.CboByte0.Cursor = System.Windows.Forms.Cursors.Default;
+ this.CboByte0.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.CboByte0.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.CboByte0.ForeColor = System.Drawing.SystemColors.WindowText;
+ this.CboByte0.Location = new System.Drawing.Point(8, 24);
+ this.CboByte0.Name = "CboByte0";
+ this.CboByte0.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.CboByte0.Size = new System.Drawing.Size(101, 22);
+ this.CboByte0.TabIndex = 2;
+ //
+ // lstResults
+ //
+ this.LstResults.BackColor = System.Drawing.SystemColors.Window;
+ this.LstResults.Cursor = System.Windows.Forms.Cursors.Default;
+ this.LstResults.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.LstResults.ForeColor = System.Drawing.SystemColors.WindowText;
+ this.LstResults.HorizontalScrollbar = true;
+ this.LstResults.ItemHeight = 14;
+ this.LstResults.Location = new System.Drawing.Point(12, 424);
+ this.LstResults.Name = "LstResults";
+ this.LstResults.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.LstResults.Size = new System.Drawing.Size(760, 326);
+ this.LstResults.TabIndex = 0;
+ //
+ // fraInputReportBufferSize
+ //
+ this.fraInputReportBufferSize.Controls.Add(this.cmdInputReportBufferSize);
+ this.fraInputReportBufferSize.Controls.Add(this.txtInputReportBufferSize);
+ this.fraInputReportBufferSize.Location = new System.Drawing.Point(248, 16);
+ this.fraInputReportBufferSize.Name = "fraInputReportBufferSize";
+ this.fraInputReportBufferSize.Size = new System.Drawing.Size(208, 96);
+ this.fraInputReportBufferSize.TabIndex = 9;
+ this.fraInputReportBufferSize.TabStop = false;
+ this.fraInputReportBufferSize.Text = "Input Report Buffer Size";
+ //
+ // cmdInputReportBufferSize
+ //
+ this.cmdInputReportBufferSize.Location = new System.Drawing.Point(96, 32);
+ this.cmdInputReportBufferSize.Name = "cmdInputReportBufferSize";
+ this.cmdInputReportBufferSize.Size = new System.Drawing.Size(96, 56);
+ this.cmdInputReportBufferSize.TabIndex = 1;
+ this.cmdInputReportBufferSize.Text = "Change Buffer Size";
+ this.cmdInputReportBufferSize.Click += new System.EventHandler(this.cmdInputReportBufferSize_Click);
+ //
+ // txtInputReportBufferSize
+ //
+ this.txtInputReportBufferSize.Location = new System.Drawing.Point(16, 40);
+ this.txtInputReportBufferSize.Name = "txtInputReportBufferSize";
+ this.txtInputReportBufferSize.Size = new System.Drawing.Size(56, 20);
+ this.txtInputReportBufferSize.TabIndex = 0;
+ //
+ // fraDeviceIdentifiers
+ //
+ this.fraDeviceIdentifiers.Controls.Add(this.txtProductID);
+ this.fraDeviceIdentifiers.Controls.Add(this.lblProductID);
+ this.fraDeviceIdentifiers.Controls.Add(this.txtVendorID);
+ this.fraDeviceIdentifiers.Controls.Add(this.lblVendorID);
+ this.fraDeviceIdentifiers.Location = new System.Drawing.Point(16, 16);
+ this.fraDeviceIdentifiers.Name = "fraDeviceIdentifiers";
+ this.fraDeviceIdentifiers.Size = new System.Drawing.Size(208, 96);
+ this.fraDeviceIdentifiers.TabIndex = 10;
+ this.fraDeviceIdentifiers.TabStop = false;
+ this.fraDeviceIdentifiers.Text = "Device Identifiers";
+ //
+ // txtProductID
+ //
+ this.txtProductID.Location = new System.Drawing.Point(120, 56);
+ this.txtProductID.Name = "txtProductID";
+ this.txtProductID.Size = new System.Drawing.Size(72, 20);
+ this.txtProductID.TabIndex = 3;
+ this.txtProductID.Text = "1299";
+ this.txtProductID.TextChanged += new System.EventHandler(this.txtProductID_TextChanged);
+ //
+ // lblProductID
+ //
+ this.lblProductID.Location = new System.Drawing.Point(16, 56);
+ this.lblProductID.Name = "lblProductID";
+ this.lblProductID.Size = new System.Drawing.Size(112, 23);
+ this.lblProductID.TabIndex = 2;
+ this.lblProductID.Text = "Product ID (hex):";
+ //
+ // txtVendorID
+ //
+ this.txtVendorID.Location = new System.Drawing.Point(120, 24);
+ this.txtVendorID.Name = "txtVendorID";
+ this.txtVendorID.Size = new System.Drawing.Size(72, 20);
+ this.txtVendorID.TabIndex = 1;
+ this.txtVendorID.Text = "0925";
+ this.txtVendorID.TextChanged += new System.EventHandler(this.txtVendorID_TextChanged);
+ //
+ // lblVendorID
+ //
+ this.lblVendorID.Location = new System.Drawing.Point(16, 24);
+ this.lblVendorID.Name = "lblVendorID";
+ this.lblVendorID.Size = new System.Drawing.Size(112, 23);
+ this.lblVendorID.TabIndex = 0;
+ this.lblVendorID.Text = "Vendor ID (hex):";
+ //
+ // cmdFindDevice
+ //
+ this.cmdFindDevice.Location = new System.Drawing.Point(483, 37);
+ this.cmdFindDevice.Name = "cmdFindDevice";
+ this.cmdFindDevice.Size = new System.Drawing.Size(136, 55);
+ this.cmdFindDevice.TabIndex = 11;
+ this.cmdFindDevice.Text = "Find My Device";
+ this.cmdFindDevice.Click += new System.EventHandler(this.cmdFindDevice_Click);
+ //
+ // cmdSendOutputReportInterrupt
+ //
+ this.cmdSendOutputReportInterrupt.Location = new System.Drawing.Point(10, 27);
+ this.cmdSendOutputReportInterrupt.Name = "cmdSendOutputReportInterrupt";
+ this.cmdSendOutputReportInterrupt.Size = new System.Drawing.Size(118, 50);
+ this.cmdSendOutputReportInterrupt.TabIndex = 12;
+ this.cmdSendOutputReportInterrupt.Text = "Send Output Report";
+ this.cmdSendOutputReportInterrupt.UseVisualStyleBackColor = true;
+ this.cmdSendOutputReportInterrupt.Click += new System.EventHandler(this.cmdSendOutputReportInterrupt_Click);
+ //
+ // cmdGetInputReportInterrupt
+ //
+ this.cmdGetInputReportInterrupt.Location = new System.Drawing.Point(10, 83);
+ this.cmdGetInputReportInterrupt.Name = "cmdGetInputReportInterrupt";
+ this.cmdGetInputReportInterrupt.Size = new System.Drawing.Size(118, 50);
+ this.cmdGetInputReportInterrupt.TabIndex = 13;
+ this.cmdGetInputReportInterrupt.Text = "Get Input Report";
+ this.cmdGetInputReportInterrupt.UseVisualStyleBackColor = true;
+ this.cmdGetInputReportInterrupt.Click += new System.EventHandler(this.cmdGetInputReportInterrupt_Click);
+ //
+ // fraInterruptTransfers
+ //
+ this.fraInterruptTransfers.BackColor = System.Drawing.SystemColors.Control;
+ this.fraInterruptTransfers.Controls.Add(this.cmdSendOutputReportInterrupt);
+ this.fraInterruptTransfers.Controls.Add(this.cmdGetInputReportInterrupt);
+ this.fraInterruptTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.fraInterruptTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.fraInterruptTransfers.Location = new System.Drawing.Point(194, 128);
+ this.fraInterruptTransfers.Name = "fraInterruptTransfers";
+ this.fraInterruptTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.fraInterruptTransfers.Size = new System.Drawing.Size(145, 152);
+ this.fraInterruptTransfers.TabIndex = 14;
+ this.fraInterruptTransfers.TabStop = false;
+ this.fraInterruptTransfers.Text = "Interrupt Transfers";
+ //
+ // cmdPeriodicTransfers
+ //
+ this.cmdPeriodicTransfers.Location = new System.Drawing.Point(153, 36);
+ this.cmdPeriodicTransfers.Name = "cmdPeriodicTransfers";
+ this.cmdPeriodicTransfers.Size = new System.Drawing.Size(118, 51);
+ this.cmdPeriodicTransfers.TabIndex = 16;
+ this.cmdPeriodicTransfers.Text = "Start";
+ this.cmdPeriodicTransfers.UseVisualStyleBackColor = true;
+ this.cmdPeriodicTransfers.Click += new System.EventHandler(this.cmdPeriodicTransfers_Click);
+ //
+ // cmdSendOutputReportControl
+ //
+ this.cmdSendOutputReportControl.Location = new System.Drawing.Point(10, 27);
+ this.cmdSendOutputReportControl.Name = "cmdSendOutputReportControl";
+ this.cmdSendOutputReportControl.Size = new System.Drawing.Size(118, 50);
+ this.cmdSendOutputReportControl.TabIndex = 12;
+ this.cmdSendOutputReportControl.Text = "Send Output Report";
+ this.cmdSendOutputReportControl.UseVisualStyleBackColor = true;
+ this.cmdSendOutputReportControl.Click += new System.EventHandler(this.cmdSendOutputReportControl_Click);
+ //
+ // cmdGetInputReportControl
+ //
+ this.cmdGetInputReportControl.Location = new System.Drawing.Point(10, 83);
+ this.cmdGetInputReportControl.Name = "cmdGetInputReportControl";
+ this.cmdGetInputReportControl.Size = new System.Drawing.Size(118, 50);
+ this.cmdGetInputReportControl.TabIndex = 13;
+ this.cmdGetInputReportControl.Text = "Get Input Report";
+ this.cmdGetInputReportControl.UseVisualStyleBackColor = true;
+ this.cmdGetInputReportControl.Click += new System.EventHandler(this.cmdGetInputReportControl_Click);
+ //
+ // fraControlTransfers
+ //
+ this.fraControlTransfers.BackColor = System.Drawing.SystemColors.Control;
+ this.fraControlTransfers.Controls.Add(this.cmdGetFeatureReport);
+ this.fraControlTransfers.Controls.Add(this.cmdSendFeatureReport);
+ this.fraControlTransfers.Controls.Add(this.cmdSendOutputReportControl);
+ this.fraControlTransfers.Controls.Add(this.cmdGetInputReportControl);
+ this.fraControlTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.fraControlTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.fraControlTransfers.Location = new System.Drawing.Point(359, 128);
+ this.fraControlTransfers.Name = "fraControlTransfers";
+ this.fraControlTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.fraControlTransfers.Size = new System.Drawing.Size(277, 152);
+ this.fraControlTransfers.TabIndex = 15;
+ this.fraControlTransfers.TabStop = false;
+ this.fraControlTransfers.Text = "Control Transfers";
+ //
+ // cmdGetFeatureReport
+ //
+ this.cmdGetFeatureReport.Location = new System.Drawing.Point(141, 83);
+ this.cmdGetFeatureReport.Name = "cmdGetFeatureReport";
+ this.cmdGetFeatureReport.Size = new System.Drawing.Size(118, 50);
+ this.cmdGetFeatureReport.TabIndex = 15;
+ this.cmdGetFeatureReport.Text = "Get Feature Report";
+ this.cmdGetFeatureReport.UseVisualStyleBackColor = true;
+ this.cmdGetFeatureReport.Click += new System.EventHandler(this.cmdGetFeatureReport_Click);
+ //
+ // cmdSendFeatureReport
+ //
+ this.cmdSendFeatureReport.Location = new System.Drawing.Point(141, 27);
+ this.cmdSendFeatureReport.Name = "cmdSendFeatureReport";
+ this.cmdSendFeatureReport.Size = new System.Drawing.Size(118, 50);
+ this.cmdSendFeatureReport.TabIndex = 14;
+ this.cmdSendFeatureReport.Text = "Send Feature Report";
+ this.cmdSendFeatureReport.UseVisualStyleBackColor = true;
+ this.cmdSendFeatureReport.Click += new System.EventHandler(this.cmdSendFeatureReport_Click);
+ //
+ // fraSendAndGetContinuous
+ //
+ this.fraSendAndGetContinuous.BackColor = System.Drawing.SystemColors.Control;
+ this.fraSendAndGetContinuous.Controls.Add(this.radFeature);
+ this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputControl);
+ this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputInterrupt);
+ this.fraSendAndGetContinuous.Controls.Add(this.cmdPeriodicTransfers);
+ this.fraSendAndGetContinuous.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.fraSendAndGetContinuous.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.fraSendAndGetContinuous.Location = new System.Drawing.Point(194, 296);
+ this.fraSendAndGetContinuous.Name = "fraSendAndGetContinuous";
+ this.fraSendAndGetContinuous.RightToLeft = System.Windows.Forms.RightToLeft.No;
+ this.fraSendAndGetContinuous.Size = new System.Drawing.Size(295, 112);
+ this.fraSendAndGetContinuous.TabIndex = 17;
+ this.fraSendAndGetContinuous.TabStop = false;
+ this.fraSendAndGetContinuous.Text = "Send and Get Continuous";
+ //
+ // radInputOutputInterrupt
+ //
+ this.radInputOutputInterrupt.AutoSize = true;
+ this.radInputOutputInterrupt.Location = new System.Drawing.Point(17, 28);
+ this.radInputOutputInterrupt.Name = "radInputOutputInterrupt";
+ this.radInputOutputInterrupt.Size = new System.Drawing.Size(126, 18);
+ this.radInputOutputInterrupt.TabIndex = 17;
+ this.radInputOutputInterrupt.TabStop = true;
+ this.radInputOutputInterrupt.Text = "Input Output Interrupt";
+ this.radInputOutputInterrupt.UseVisualStyleBackColor = true;
+ this.radInputOutputInterrupt.CheckedChanged += new System.EventHandler(this.radInputOutputInterrupt_CheckedChanged);
+ //
+ // radInputOutputControl
+ //
+ this.radInputOutputControl.AutoSize = true;
+ this.radInputOutputControl.Location = new System.Drawing.Point(17, 52);
+ this.radInputOutputControl.Name = "radInputOutputControl";
+ this.radInputOutputControl.Size = new System.Drawing.Size(120, 18);
+ this.radInputOutputControl.TabIndex = 18;
+ this.radInputOutputControl.TabStop = true;
+ this.radInputOutputControl.Text = "Input Output Control";
+ this.radInputOutputControl.UseVisualStyleBackColor = true;
+ this.radInputOutputControl.CheckedChanged += new System.EventHandler(this.radInputOutputControl_CheckedChanged);
+ //
+ // radFeature
+ //
+ this.radFeature.AutoSize = true;
+ this.radFeature.Location = new System.Drawing.Point(17, 76);
+ this.radFeature.Name = "radFeature";
+ this.radFeature.Size = new System.Drawing.Size(62, 18);
+ this.radFeature.TabIndex = 19;
+ this.radFeature.TabStop = true;
+ this.radFeature.Text = "Feature";
+ this.radFeature.UseVisualStyleBackColor = true;
+ this.radFeature.CheckedChanged += new System.EventHandler(this.radFeature_CheckedChanged);
+ //
+ // FrmMain
+ //
+ this.ClientSize = new System.Drawing.Size(784, 756);
+ this.Controls.Add(this.fraSendAndGetContinuous);
+ this.Controls.Add(this.fraControlTransfers);
+ this.Controls.Add(this.fraInterruptTransfers);
+ this.Controls.Add(this.cmdFindDevice);
+ this.Controls.Add(this.fraDeviceIdentifiers);
+ this.Controls.Add(this.fraInputReportBufferSize);
+ this.Controls.Add(this.FraBytesReceived);
+ this.Controls.Add(this.FraBytesToSend);
+ this.Controls.Add(this.LstResults);
+ this.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.Location = new System.Drawing.Point(21, 28);
+ this.Name = "FrmMain";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.Text = "Generic HID Tester";
+ this.Closed += new System.EventHandler(this.frmMain_Closed);
+ this.Load += new System.EventHandler(this.frmMain_Load);
+ this.FraBytesReceived.ResumeLayout(false);
+ this.FraBytesReceived.PerformLayout();
+ this.FraBytesToSend.ResumeLayout(false);
+ this.fraInputReportBufferSize.ResumeLayout(false);
+ this.fraInputReportBufferSize.PerformLayout();
+ this.fraDeviceIdentifiers.ResumeLayout(false);
+ this.fraDeviceIdentifiers.PerformLayout();
+ this.fraInterruptTransfers.ResumeLayout(false);
+ this.fraControlTransfers.ResumeLayout(false);
+ this.fraSendAndGetContinuous.ResumeLayout(false);
+ this.fraSendAndGetContinuous.PerformLayout();
+ this.ResumeLayout(false);
+
+ }
+ #endregion
+
+ private Boolean _deviceDetected;
+ private IntPtr _deviceNotificationHandle;
+ private FileStream _deviceData;
+ private FormActions _formActions;
+ private SafeFileHandle _hidHandle;
+ private String _hidUsage;
+ private ManagementEventWatcher _deviceArrivedWatcher;
+ private Boolean _deviceHandleObtained;
+ private ManagementEventWatcher _deviceRemovedWatcher;
+ private Int32 _myProductId;
+ private Int32 _myVendorId;
+ private Boolean _periodicTransfersRequested;
+ private ReportReadOrWritten _readOrWritten;
+ private ReportTypes _reportType;
+ private SendOrGet _sendOrGet;
+ private Boolean _transferInProgress;
+ private TransferTypes _transferType;
+
+ private static System.Timers.Timer _periodicTransfers;
+
+ private readonly Debugging _myDebugging = new Debugging(); // For viewing results of API calls via Debug.Write.
+ private readonly DeviceManagement _myDeviceManagement = new DeviceManagement();
+ private Hid _myHid = new Hid();
+
+ private enum FormActions
+ {
+ AddItemToListBox,
+ DisableInputReportBufferSize,
+ EnableGetInputReportInterruptTransfer,
+ EnableInputReportBufferSize,
+ EnableSendOutputReportInterrupt,
+ ScrollToBottomOfListBox,
+ SetInputReportBufferSize
+ }
+
+ private enum ReportReadOrWritten
+ {
+ Read,
+ Written
+ }
+
+ private enum ReportTypes
+ {
+ Input,
+ Output,
+ Feature
+ }
+
+ private enum SendOrGet
+ {
+ Send,
+ Get
+ }
+
+ private enum TransferTypes
+ {
+ Control,
+ Interrupt
+ }
+
+ private enum WmiDeviceProperties
+ {
+ Name,
+ Caption,
+ Description,
+ Manufacturer,
+ PNPDeviceID,
+ DeviceID,
+ ClassGUID
+ }
+
+ internal FrmMain FrmMy;
+
+ // This delegate has the same parameters as AccessForm.
+ // Used in accessing the application's form from a different thread.
+
+ private delegate void MarshalDataToForm(FormActions action, String textToAdd);
+
+ ///
+ /// Performs various application-specific functions that
+ /// involve accessing the application's form.
+ ///
+ ///
+ /// a FormActions member that names the action to perform on the form
+ /// text that the form displays or the code uses for
+ /// another purpose. Actions that don't use text ignore this parameter.
+
+ private void AccessForm(FormActions action, String formText)
+ {
+ try
+ {
+ // Select an action to perform on the form:
+
+ switch (action)
+ {
+ case FormActions.AddItemToListBox:
+
+ LstResults.Items.Add(formText);
+ break;
+
+ case FormActions.DisableInputReportBufferSize:
+
+ cmdInputReportBufferSize.Enabled = false;
+ break;
+
+ case FormActions.EnableGetInputReportInterruptTransfer:
+
+ cmdGetInputReportInterrupt.Enabled = true;
+ break;
+
+ case FormActions.EnableInputReportBufferSize:
+
+ cmdInputReportBufferSize.Enabled = true;
+ break;
+
+ case FormActions.EnableSendOutputReportInterrupt:
+
+ cmdSendOutputReportInterrupt.Enabled = true;
+ break;
+
+ case FormActions.ScrollToBottomOfListBox:
+
+ LstResults.SelectedIndex = LstResults.Items.Count - 1;
+ break;
+
+ case FormActions.SetInputReportBufferSize:
+
+ txtInputReportBufferSize.Text = formText;
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Add a handler to detect arrival of devices using WMI.
+ ///
+
+ private void AddDeviceArrivedHandler()
+ {
+ const Int32 pollingIntervalSeconds = 3;
+ var scope = new ManagementScope("root\\CIMV2");
+ scope.Options.EnablePrivileges = true;
+
+ try
+ {
+ var q = new WqlEventQuery();
+ q.EventClassName = "__InstanceCreationEvent";
+ q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
+ q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
+ _deviceArrivedWatcher = new ManagementEventWatcher(scope, q);
+ _deviceArrivedWatcher.EventArrived += DeviceAdded;
+
+ _deviceArrivedWatcher.Start();
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e.Message);
+ if (_deviceArrivedWatcher != null)
+ _deviceArrivedWatcher.Stop();
+ }
+ }
+
+ ///
+ /// Add a handler to detect removal of devices using WMI.
+ ///
+
+ private void AddDeviceRemovedHandler()
+ {
+ const Int32 pollingIntervalSeconds = 3;
+ var scope = new ManagementScope("root\\CIMV2");
+ scope.Options.EnablePrivileges = true;
+
+ try
+ {
+ var q = new WqlEventQuery();
+ q.EventClassName = "__InstanceDeletionEvent";
+ q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
+ q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
+ _deviceRemovedWatcher = new ManagementEventWatcher(scope, q);
+ _deviceRemovedWatcher.EventArrived += DeviceRemoved;
+ _deviceRemovedWatcher.Start();
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e.Message);
+ if (_deviceRemovedWatcher != null)
+ _deviceRemovedWatcher.Stop();
+ }
+ }
+
+ ///
+ /// Close the handle and FileStreams for a device.
+ ///
+ ///
+ private void CloseCommunications()
+ {
+ if (_deviceData != null)
+ {
+ _deviceData.Close();
+ }
+
+ if ((_hidHandle != null) && (!(_hidHandle.IsInvalid)))
+ {
+ _hidHandle.Close();
+ }
+
+ // The next attempt to communicate will get a new handle and FileStreams.
+
+ _deviceHandleObtained = false;
+ }
+
+ ///
+ /// Search for a specific device.
+ ///
+
+ private void cmdFindDevice_Click(Object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ _deviceDetected = FindDeviceUsingWmi();
+ if (_deviceDetected)
+ {
+ FindTheHid();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to get a Feature report from the device.
+ ///
+ ///
+ ///
+
+ private void cmdGetFeatureReport_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ // Don't allow another transfer request until this one completes.
+ // Move the focus away from the button to prevent the focus from
+ // switching to the next control in the tab order on disabling the button.
+
+ fraControlTransfers.Focus();
+ cmdGetFeatureReport.Enabled = false;
+ _transferType = TransferTypes.Control;
+ RequestToGetFeatureReport();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to get an Input report from the device using a control transfer.
+ ///
+ ///
+ ///
+
+ private void cmdGetInputReportControl_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ // Don't allow another transfer request until this one completes.
+ // Move the focus away from the button to prevent the focus from
+ // switching to the next control in the tab order on disabling the button.
+
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ fraControlTransfers.Focus();
+ cmdGetInputReportControl.Enabled = false;
+ _transferType = TransferTypes.Control;
+ RequestToGetInputReport();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to get an Input report retrieved using interrupt transfers.
+ ///
+ ///
+ ///
+ ///
+ private void cmdGetInputReportInterrupt_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ // Don't allow another transfer request until this one completes.
+ // Move the focus away from the button to prevent the focus from
+ // switching to the next control in the tab order on disabling the button.
+
+ fraInterruptTransfers.Focus();
+ cmdGetInputReportInterrupt.Enabled = false;
+ _transferType = TransferTypes.Interrupt;
+ RequestToGetInputReport();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Set the number of Input reports the HID driver will store.
+ ///
+
+ private void cmdInputReportBufferSize_Click(Object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ SetInputReportBufferSize();
+ }
+ }
+ catch
+ (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Alternate sending and getting a report.
+ ///
+ ///
+ ///
+
+ private void cmdPeriodicTransfers_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ if (cmdPeriodicTransfers.Text == "Start")
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ _sendOrGet = SendOrGet.Send;
+ PeriodicTransfersStart();
+ }
+ }
+ else
+ {
+ PeriodicTransfersStop();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to send a Feature report using a control transfer.
+ ///
+ ///
+ ///
+
+ private void cmdSendFeatureReport_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ // Don't allow another transfer request until this one completes.
+ // Move the focus away from the button to prevent the focus from
+ // switching to the next control in the tab order on disabling the button.
+
+ fraControlTransfers.Focus();
+ cmdSendFeatureReport.Enabled = false;
+ _transferType = TransferTypes.Control;
+ RequestToSendFeatureReport();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to send an Output report using a control transfer.
+ ///
+ ///
+ ///
+ ///
+ private void cmdSendOutputReportControl_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ // Don't allow another transfer request until this one completes.
+ // Move the focus away from the button to prevent the focus from
+ // switching to the next control in the tab order on disabling the button.
+
+ fraControlTransfers.Focus();
+ cmdSendOutputReportControl.Enabled = false;
+ _transferType = TransferTypes.Control;
+ RequestToSendOutputReport();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to send an Output report using an interrupt transfer.
+ ///
+ ///
+ ///
+
+ private void cmdSendOutputReportInterrupt_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ if (_transferInProgress)
+ {
+ DisplayTransferInProgressMessage();
+ }
+ else
+ {
+ // Don't allow another transfer request until this one completes.
+ // Move the focus away from the button to prevent the focus from
+ // switching to the next control in the tab order on disabling the button.
+
+ fraInterruptTransfers.Focus();
+ cmdSendOutputReportInterrupt.Enabled = false;
+ _transferType = TransferTypes.Interrupt;
+ RequestToSendOutputReport();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Called on arrival of any device.
+ /// Calls a routine that searches to see if the desired device is present.
+ ///
+
+ private void DeviceAdded(object sender, EventArrivedEventArgs e)
+ {
+ try
+ {
+ Debug.WriteLine("A USB device has been inserted");
+
+ _deviceDetected = FindDeviceUsingWmi();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Called if the user changes the Vendor ID or Product ID in the text box.
+ ///
+
+ private void DeviceHasChanged()
+ {
+ try
+ {
+ // If a device was previously detected, stop receiving notifications about it.
+
+ if (_deviceHandleObtained)
+ {
+ DeviceNotificationsStop();
+
+ CloseCommunications();
+ }
+ // Look for a device that matches the Vendor ID and Product ID in the text boxes.
+
+ FindTheHid();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Add handlers to detect device arrival and removal.
+ ///
+
+ private void DeviceNotificationsStart()
+ {
+ AddDeviceArrivedHandler();
+ AddDeviceRemovedHandler();
+ }
+
+ ///
+ /// Stop receiving notifications about device arrival and removal
+ ///
+
+ private void DeviceNotificationsStop()
+ {
+ try
+ {
+ if (_deviceArrivedWatcher != null)
+ _deviceArrivedWatcher.Stop();
+ if (_deviceRemovedWatcher != null)
+ _deviceRemovedWatcher.Stop();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Called on removal of any device.
+ /// Calls a routine that searches to see if the desired device is still present.
+ ///
+ ///
+ private void DeviceRemoved(object sender, EventArgs e)
+ {
+ try
+ {
+ Debug.WriteLine("A USB device has been removed");
+
+ _deviceDetected = FindDeviceUsingWmi();
+
+ if (!_deviceDetected)
+ {
+ _deviceHandleObtained = false;
+ CloseCommunications();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Displays received or written report data.
+ ///
+ ///
+ /// contains the report data.
+ /// "Input", "Output", or "Feature"
+ /// "read" for Input and IN Feature reports, "written" for Output and OUT Feature reports.
+
+ private void DisplayReportData(Byte[] buffer, ReportTypes currentReportType, ReportReadOrWritten currentReadOrWritten)
+ {
+ try
+ {
+ Int32 count;
+
+ LstResults.Items.Add(currentReportType.ToString() + " report has been " + currentReadOrWritten.ToString().ToLower() + ".");
+
+ // Display the report data received in the form's list box.
+
+ LstResults.Items.Add(" Report ID: " + String.Format("{0:X2} ", buffer[0]));
+ LstResults.Items.Add(" Report Data:");
+
+ TxtBytesReceived.Text = "";
+
+ for (count = 1; count <= buffer.Length - 1; count++)
+ {
+ // Display bytes as 2-character Hex strings.
+
+ String byteValue = String.Format("{0:X2} ", buffer[count]);
+
+ LstResults.Items.Add(" " + byteValue);
+
+ // Display the received bytes in the text box.
+
+ TxtBytesReceived.SelectionStart = TxtBytesReceived.Text.Length;
+ TxtBytesReceived.SelectedText = byteValue + Environment.NewLine;
+ }
+ ScrollToBottomOfListBox();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Display a message if the user clicks a button when a transfer is in progress.
+ ///
+ ///
+ private void DisplayTransferInProgressMessage()
+ {
+ AccessForm(FormActions.AddItemToListBox, "Command not executed because a transfer is in progress.");
+ ScrollToBottomOfListBox();
+ }
+
+ ///
+ /// Do periodic transfers.
+ ///
+ ///
+ ///
+ ///
+ /// The timer is enabled only if continuous (periodic) transfers have been requested.
+ ///
+
+ private void DoPeriodicTransfers(object source, ElapsedEventArgs e)
+ {
+ try
+ {
+ PeriodicTransfers();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Enable the command buttons on the form.
+ /// Needed after attempting a transfer and device not found.
+ ///
+ ///
+ private void EnableFormControls()
+ {
+ cmdGetInputReportInterrupt.Enabled = true;
+ cmdSendOutputReportControl.Enabled = true;
+ cmdGetInputReportControl.Enabled = true;
+ cmdGetFeatureReport.Enabled = true;
+ cmdSendFeatureReport.Enabled = true;
+ cmdPeriodicTransfers.Enabled = true;
+ cmdSendOutputReportInterrupt.Enabled = true;
+ }
+
+ ///
+ /// Use the System.Management class to find a device by Vendor ID and Product ID using WMI. If found, display device properties.
+ ///
+ ///
+ /// During debugging, if you stop the firmware but leave the device attached, the device may still be detected as present
+ /// but will be unable to communicate. The device will show up in Windows Device Manager as well.
+ /// This situation is unlikely to occur with a final product.
+ ///
+
+ private Boolean FindDeviceUsingWmi()
+ {
+ try
+ {
+ // Prepend "@" to string below to treat backslash as a normal character (not escape character):
+
+ String deviceIdString = @"USB\VID_" + _myVendorId.ToString("X4") + "&PID_" + _myProductId.ToString("X4");
+
+ _deviceDetected = false;
+ var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity");
+
+ foreach (ManagementObject queryObj in searcher.Get())
+ {
+ if (queryObj["PNPDeviceID"].ToString().Contains(deviceIdString))
+ {
+ _deviceDetected = true;
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "My device found (WMI):");
+
+ // Display device properties.
+
+ foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
+ Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
+ }
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+ }
+ }
+ if (!_deviceDetected)
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "My device not found (WMI)");
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+ }
+ return _deviceDetected;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Call HID functions that use Win32 API functions to locate a HID-class device
+ /// by its Vendor ID and Product ID. Open a handle to the device.
+ ///
+ ///
+ ///
+ /// True if the device is detected, False if not detected.
+ ///
+
+ private Boolean FindTheHid()
+ {
+ var devicePathName = new String[128];
+ String myDevicePathName = "";
+
+ try
+ {
+ _deviceHandleObtained = false;
+ CloseCommunications();
+
+ // Get the device's Vendor ID and Product ID from the form's text boxes.
+
+ GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
+
+ // Get the HID-class GUID.
+
+ Guid hidGuid = _myHid.GetHidGuid();
+
+ String functionName = "GetHidGuid";
+ Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
+ Debug.WriteLine(" GUID for system HIDs: " + hidGuid.ToString());
+
+ // Fill an array with the device path names of all attached HIDs.
+
+ Boolean availableHids = _myDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
+
+ // If there is at least one HID, attempt to read the Vendor ID and Product ID
+ // of each device until there is a match or all devices have been examined.
+
+ if (availableHids)
+ {
+ Int32 memberIndex = 0;
+
+ do
+ {
+ // Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice.
+
+ _hidHandle = _myHid.OpenHandle(devicePathName[memberIndex], false);
+
+ functionName = "CreateFile";
+ Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
+ Debug.WriteLine(" Returned handle: " + _hidHandle);
+
+ if (!_hidHandle.IsInvalid)
+ {
+ // The returned handle is valid,
+ // so find out if this is the device we're looking for.
+
+ _myHid.DeviceAttributes.Size = Marshal.SizeOf(_myHid.DeviceAttributes);
+
+ Boolean success = _myHid.GetAttributes(_hidHandle, ref _myHid.DeviceAttributes);
+
+ if (success)
+ {
+ Debug.WriteLine(" HIDD_ATTRIBUTES structure filled without error.");
+ Debug.WriteLine(" Structure size: " + _myHid.DeviceAttributes.Size);
+ Debug.WriteLine(" Vendor ID: " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
+ Debug.WriteLine(" Product ID: " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
+ Debug.WriteLine(" Version Number: " + Convert.ToString(_myHid.DeviceAttributes.VersionNumber, 16));
+
+ if ((_myHid.DeviceAttributes.VendorID == _myVendorId) && (_myHid.DeviceAttributes.ProductID == _myProductId))
+ {
+ Debug.WriteLine(" Handle obtained to my device");
+
+ // Display the information in form's list box.
+
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "Handle obtained to my device:");
+ MyMarshalDataToForm(FormActions.AddItemToListBox, " Vendor ID= " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
+ MyMarshalDataToForm(FormActions.AddItemToListBox, " Product ID = " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+
+ _deviceHandleObtained = true;
+
+ myDevicePathName = devicePathName[memberIndex];
+ }
+ else
+ {
+ // It's not a match, so close the handle.
+
+ _deviceHandleObtained = false;
+ _hidHandle.Close();
+ }
+ }
+ else
+ {
+ // There was a problem retrieving the information.
+
+ Debug.WriteLine(" Error in filling HIDD_ATTRIBUTES structure.");
+ _deviceHandleObtained = false;
+ _hidHandle.Close();
+ }
+ }
+
+ // Keep looking until we find the device or there are no devices left to examine.
+
+ memberIndex = memberIndex + 1;
+ }
+ while (!((_deviceHandleObtained || (memberIndex == devicePathName.Length))));
+ }
+
+ if (_deviceHandleObtained)
+ {
+ // The device was detected.
+ // Learn the capabilities of the device.
+
+ _myHid.Capabilities = _myHid.GetDeviceCapabilities(_hidHandle);
+
+ // Find out if the device is a system mouse or keyboard.
+
+ _hidUsage = _myHid.GetHidUsage(_myHid.Capabilities);
+
+ // Get the Input report buffer size.
+
+ GetInputReportBufferSize();
+ MyMarshalDataToForm(FormActions.EnableInputReportBufferSize, "");
+
+ //Close the handle and reopen it with read/write access.
+
+ _hidHandle.Close();
+
+ _hidHandle = _myHid.OpenHandle(myDevicePathName, true);
+
+ if (_hidHandle.IsInvalid)
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The device is a system " + _hidUsage + ".");
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 2000 and later obtain exclusive access to Input and Output reports for this devices.");
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 8 also obtains exclusive access to Feature reports.");
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+ }
+ else
+ {
+ if (_myHid.Capabilities.InputReportByteLength > 0)
+ {
+ // Set the size of the Input report buffer.
+
+ var inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
+
+ _deviceData = new FileStream(_hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
+ }
+
+ if (_myHid.Capabilities.OutputReportByteLength > 0)
+ {
+ Byte[] outputReportBuffer = null;
+ }
+ // Flush any waiting reports in the input buffer. (optional)
+
+ _myHid.FlushQueue(_hidHandle);
+ }
+ }
+ else
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "Device not found.");
+ MyMarshalDataToForm(FormActions.DisableInputReportBufferSize, "");
+ EnableFormControls();
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+ }
+ return _deviceHandleObtained;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Perform shutdown operations.
+ ///
+
+ private void frmMain_Closed(Object eventSender, EventArgs eventArgs)
+ {
+ try
+ {
+ Shutdown();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Perform startup operations.
+ ///
+
+ private void frmMain_Load(Object eventSender, EventArgs eventArgs)
+ {
+ try
+ {
+ FrmMy = this;
+ Startup();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ private void GetBytesToSend()
+ {
+ try
+ {
+ // Get the bytes to send in a report from the combo boxes.
+ // Increment the values if the autoincrement check box is selected.
+
+ if (ChkAutoincrement.Checked)
+ {
+ if (CboByte0.SelectedIndex < 255)
+ {
+ CboByte0.SelectedIndex = CboByte0.SelectedIndex + 1;
+ }
+ else
+ {
+ CboByte0.SelectedIndex = 0;
+ }
+ if (CboByte1.SelectedIndex < 255)
+ {
+ CboByte1.SelectedIndex = CboByte1.SelectedIndex + 1;
+ }
+ else
+ {
+ CboByte1.SelectedIndex = 0;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Find and display the number of Input buffers
+ /// (the number of Input reports the HID driver will store).
+ ///
+
+ private void GetInputReportBufferSize()
+ {
+ Int32 numberOfInputBuffers = 0;
+ Boolean success;
+
+ try
+ {
+ // Get the number of input buffers.
+
+ _myHid.GetNumberOfInputBuffers(_hidHandle, ref numberOfInputBuffers);
+
+ // Display the result in the text box.
+
+ MyMarshalDataToForm(FormActions.SetInputReportBufferSize, Convert.ToString(numberOfInputBuffers));
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Retrieve a Vendor ID and Product ID in hexadecimal
+ /// from the form's text boxes and convert the text to Int32s.
+ ///
+ ///
+ /// the Vendor ID
+ /// the Product ID
+
+ private void GetVendorAndProductIDsFromTextBoxes(ref Int32 myVendorId, ref Int32 myProductId)
+ {
+ try
+ {
+ myVendorId = Int32.Parse(txtVendorID.Text, NumberStyles.AllowHexSpecifier);
+ myProductId = Int32.Parse(txtProductID.Text, NumberStyles.AllowHexSpecifier);
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Initialize the elements on the form.
+ ///
+
+ private void InitializeDisplay()
+ {
+ try
+ {
+ // Create a dropdown list box for each byte to send in a report.
+ // Display the values as 2-character hex strings.
+
+ Int16 count;
+ for (count = 0; count <= 255; count++)
+ {
+ String byteValue = String.Format("{0:X2} ", count);
+ FrmMy.CboByte0.Items.Insert(count, byteValue);
+ FrmMy.CboByte1.Items.Insert(count, byteValue);
+ }
+
+ // Select a default value for each box
+
+ FrmMy.CboByte0.SelectedIndex = 0;
+ FrmMy.CboByte1.SelectedIndex = 128;
+ FrmMy.radInputOutputInterrupt.Checked = true;
+
+ // Check the autoincrement box to increment the values each time a report is sent.
+
+ ChkAutoincrement.CheckState = CheckState.Checked;
+
+ // Don't allow the user to select an input report buffer size until there is
+ // a handle to a HID.
+
+ cmdInputReportBufferSize.Focus();
+ cmdInputReportBufferSize.Enabled = false;
+
+ LstResults.Items.Add("For a more detailed event log, view debug statements in Visual Studio's Output window:");
+ LstResults.Items.Add("Click Build > Configuration Manager > Active Solution Configuration > Debug > Close.");
+ LstResults.Items.Add("Then click View > Output.");
+ LstResults.Items.Add("");
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Enables accessing a form's controls from another thread
+ ///
+ ///
+ /// a FormActions member that names the action to perform on the form
+ /// text that the form displays or the code uses for
+ /// another purpose. Actions that don't use text ignore this parameter.
+
+ private void MyMarshalDataToForm(FormActions action, String textToDisplay)
+ {
+ try
+ {
+ object[] args = { action, textToDisplay };
+
+ // The AccessForm routine contains the code that accesses the form.
+
+ MarshalDataToForm marshalDataToFormDelegate = AccessForm;
+
+ // Execute AccessForm, passing the parameters in args.
+
+ Invoke(marshalDataToFormDelegate, args);
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Timeout if read via interrupt transfer doesn't return.
+ ///
+
+ private void OnReadTimeout()
+ {
+ try
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a report timed out.");
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+ CloseCommunications();
+ MyMarshalDataToForm(FormActions.EnableGetInputReportInterruptTransfer, "");
+ _transferInProgress = false;
+ _sendOrGet = SendOrGet.Send;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Timeout if write via interrupt transfer doesn't return.
+ ///
+
+ private void OnWriteTimeout()
+ {
+ try
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to write a report timed out.");
+ MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
+ CloseCommunications();
+ MyMarshalDataToForm(FormActions.EnableSendOutputReportInterrupt, "");
+ _transferInProgress = false;
+ _sendOrGet = SendOrGet.Get;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Alternat sending and getting a report.
+ ///
+
+ private void PeriodicTransfers()
+ {
+ try
+ {
+ if (!_transferInProgress)
+ {
+ if (_reportType == ReportTypes.Feature)
+ {
+ SendOrGetFeatureReport();
+ }
+ else
+ {
+ // Output and Input reports
+
+ SendOutputReportOrGetInputReport();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Start doing periodic transfers.
+ ///
+
+ private void PeriodicTransfersStart()
+ {
+ // Don't allow changing the transfer type while transfers are in progress.
+
+ if (radFeature.Checked)
+ {
+ radInputOutputControl.Enabled = false;
+ radInputOutputInterrupt.Enabled = false;
+ }
+ else if (radInputOutputControl.Checked)
+ {
+ radFeature.Enabled = false;
+ radInputOutputInterrupt.Enabled = false;
+ }
+ else if (radInputOutputInterrupt.Checked)
+ {
+ radFeature.Enabled = false;
+ radInputOutputControl.Enabled = false;
+ }
+
+ // Change the command button's text.
+
+ cmdPeriodicTransfers.Text = "Stop";
+
+ // Enable the timer event to trigger a set of transfers.
+
+ _periodicTransfers.Start();
+
+ cmdPeriodicTransfers.Enabled = true;
+
+ if (radInputOutputInterrupt.Checked)
+ {
+ _transferType = TransferTypes.Interrupt;
+ _reportType = ReportTypes.Output;
+ }
+ else if (radInputOutputControl.Checked)
+ {
+ _transferType = TransferTypes.Control;
+ _reportType = ReportTypes.Output;
+ }
+ else if (radFeature.Checked)
+ {
+ _transferType = TransferTypes.Control;
+ _reportType = ReportTypes.Feature;
+ }
+ _periodicTransfersRequested = true;
+ PeriodicTransfers();
+ }
+
+ ///
+ /// Stop doing periodic transfers.
+ ///
+
+ private void PeriodicTransfersStop()
+ {
+ // Stop doing continuous transfers.
+
+ _periodicTransfersRequested = false;
+
+ // Disable the timer that triggers the transfers.
+
+ _periodicTransfers.Stop();
+ cmdPeriodicTransfers.Enabled = true;
+
+ // Change the command button's text.
+
+ cmdPeriodicTransfers.Text = "Start";
+
+ // Re-allow changing the transfer type.
+
+ radFeature.Enabled = true;
+ radInputOutputControl.Enabled = true;
+ radInputOutputInterrupt.Enabled = true;
+ }
+
+ private void radInputOutputControl_CheckedChanged(object sender, EventArgs e)
+ {
+ }
+
+ private void radInputOutputInterrupt_CheckedChanged(object sender, EventArgs e)
+ {
+ }
+
+ private void radFeature_CheckedChanged(object sender, EventArgs e)
+ {
+ }
+
+ ///
+ /// Request a Feature report.
+ /// Assumes report ID = 0.
+ ///
+
+ private void RequestToGetFeatureReport()
+ {
+ String byteValue = null;
+
+ try
+ {
+ // If the device hasn't been detected, was removed, or timed out on a previous attempt
+ // to access it, look for the device.
+
+ if (!_deviceHandleObtained)
+ {
+ _deviceHandleObtained = FindTheHid();
+ }
+
+ if (_deviceHandleObtained)
+ {
+ Byte[] inFeatureReportBuffer = null;
+
+ if ((_myHid.Capabilities.FeatureReportByteLength > 0))
+ {
+ // The HID has a Feature report.
+ // Read a report from the device.
+
+ // Set the size of the Feature report buffer.
+
+ if ((_myHid.Capabilities.FeatureReportByteLength > 0))
+ {
+ inFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
+ }
+
+ // Read a report.
+
+ Boolean success = _myHid.GetFeatureReport(_hidHandle, ref inFeatureReportBuffer);
+
+ if (success)
+ {
+ DisplayReportData(inFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Read);
+ }
+ else
+ {
+ CloseCommunications();
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a Feature report failed.");
+ ScrollToBottomOfListBox();
+ }
+ }
+ else
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
+ ScrollToBottomOfListBox();
+ }
+ }
+ _transferInProgress = false;
+ cmdGetFeatureReport.Enabled = true;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request an Input report.
+ /// Assumes report ID = 0.
+ ///
+
+ private async void RequestToGetInputReport()
+ {
+ const Int32 readTimeout = 5000;
+
+ String byteValue = null;
+ Byte[] inputReportBuffer = null;
+
+ try
+ {
+ Boolean success = false;
+
+ // If the device hasn't been detected, was removed, or timed out on a previous attempt
+ // to access it, look for the device.
+
+ if (!_deviceHandleObtained)
+ {
+ _deviceHandleObtained = FindTheHid();
+ }
+
+ if (_deviceHandleObtained)
+ {
+ // Don't attempt to exchange reports if valid handles aren't available
+ // (as for a mouse or keyboard under Windows 2000 and later.)
+
+ if (!_hidHandle.IsInvalid)
+ {
+ // Read an Input report.
+
+ // Don't attempt to send an Input report if the HID has no Input report.
+ // (The HID spec requires all HIDs to have an interrupt IN endpoint,
+ // which suggests that all HIDs must support Input reports.)
+
+ if (_myHid.Capabilities.InputReportByteLength > 0)
+ {
+ // Set the size of the Input report buffer.
+
+ inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
+
+ if (_transferType.Equals(TransferTypes.Control))
+ {
+ {
+ _transferInProgress = true;
+
+ // Read a report using a control transfer.
+
+ success = _myHid.GetInputReportViaControlTransfer(_hidHandle, ref inputReportBuffer);
+ cmdGetInputReportControl.Enabled = true;
+ _transferInProgress = false;
+ }
+ }
+ else
+ {
+ {
+ _transferInProgress = true;
+
+ // Read a report using interrupt transfers.
+ // Timeout if no report available.
+ // To enable reading a report without blocking the calling thread, uses Filestream's ReadAsync method.
+
+ // Create a delegate to execute on a timeout.
+
+ Action onReadTimeoutAction = OnReadTimeout;
+
+ // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
+
+ var cts = new CancellationTokenSource();
+
+ // Cancel the read if it hasn't completed after a timeout.
+
+ cts.CancelAfter(readTimeout);
+
+ // Specify the function to call on a timeout.
+
+ cts.Token.Register(onReadTimeoutAction);
+
+ // Stops waiting when data is available or on timeout:
+
+ Int32 bytesRead = await _myHid.GetInputReportViaInterruptTransfer(_deviceData, inputReportBuffer, cts);
+
+ // Arrive here only if the operation completed.
+
+ // Dispose to stop the timeout timer.
+
+ cts.Dispose();
+
+ _transferInProgress = false;
+ cmdGetInputReportInterrupt.Enabled = true;
+
+ if (bytesRead > 0)
+ {
+ success = true;
+ Debug.Print("bytes read (includes report ID) = " + Convert.ToString(bytesRead));
+ }
+ }
+ }
+ }
+ else
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "No attempt to read an Input report was made.");
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have an Input report.");
+ }
+ }
+ else
+ {
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "Invalid handle.");
+ MyMarshalDataToForm(FormActions.AddItemToListBox,
+ "No attempt to write an Output report or read an Input report was made.");
+ }
+
+ if (success)
+ {
+ DisplayReportData(inputReportBuffer, ReportTypes.Input, ReportReadOrWritten.Read);
+ }
+ else
+ {
+ CloseCommunications();
+ MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read an Input report has failed.");
+ ScrollToBottomOfListBox();
+ }
+ }
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Sends a Feature report.
+ /// Assumes report ID = 0.
+ ///
+
+ private void RequestToSendFeatureReport()
+ {
+ String byteValue = null;
+
+ try
+ {
+ _transferInProgress = true;
+
+ // If the device hasn't been detected, was removed, or timed out on a previous attempt
+ // to access it, look for the device.
+
+ if (!_deviceHandleObtained)
+ {
+ _deviceHandleObtained = FindTheHid();
+ }
+
+ if (_deviceHandleObtained)
+ {
+ GetBytesToSend();
+
+ if ((_myHid.Capabilities.FeatureReportByteLength > 0))
+ {
+ // The HID has a Feature report.
+ // Set the size of the Feature report buffer.
+
+ var outFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
+
+ // Store the report ID in the buffer.
+
+ outFeatureReportBuffer[0] = 0;
+
+ // Store the report data following the report ID.
+ // Use the data in the combo boxes on the form.
+
+ outFeatureReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
+
+ if (outFeatureReportBuffer.GetUpperBound(0) > 1)
+ {
+ outFeatureReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
+ }
+
+ // Write a report to the device
+
+ Boolean success = _myHid.SendFeatureReport(_hidHandle, outFeatureReportBuffer);
+
+ if (success)
+ {
+ DisplayReportData(outFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Written);
+ }
+ else
+ {
+ CloseCommunications();
+ AccessForm(FormActions.AddItemToListBox, "The attempt to send a Feature report failed.");
+ ScrollToBottomOfListBox();
+ }
+ }
+
+ else
+ {
+ AccessForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
+ ScrollToBottomOfListBox();
+ }
+
+ }
+ _transferInProgress = false;
+ cmdSendFeatureReport.Enabled = true;
+ ScrollToBottomOfListBox();
+
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Sends an Output report.
+ /// Assumes report ID = 0.
+ ///
+
+ private async void RequestToSendOutputReport()
+ {
+ const Int32 writeTimeout = 5000;
+ String byteValue = null;
+
+ try
+ {
+ // If the device hasn't been detected, was removed, or timed out on a previous attempt
+ // to access it, look for the device.
+
+ if (!_deviceHandleObtained)
+ {
+ _deviceHandleObtained = FindTheHid();
+ }
+
+ if (_deviceHandleObtained)
+ {
+ GetBytesToSend();
+ }
+ // Don't attempt to exchange reports if valid handles aren't available
+ // (as for a mouse or keyboard.)
+
+ if (!_hidHandle.IsInvalid)
+ {
+ // Don't attempt to send an Output report if the HID has no Output report.
+
+ if (_myHid.Capabilities.OutputReportByteLength > 0)
+ {
+ // Set the size of the Output report buffer.
+
+ var outputReportBuffer = new Byte[_myHid.Capabilities.OutputReportByteLength];
+
+ // Store the report ID in the first byte of the buffer:
+
+ outputReportBuffer[0] = 0;
+
+ // Store the report data following the report ID.
+ // Use the data in the combo boxes on the form.
+
+ outputReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
+
+ if (outputReportBuffer.GetUpperBound(0) > 1)
+ {
+ outputReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
+ }
+
+ // Write a report.
+
+ Boolean success;
+
+ if (_transferType.Equals(TransferTypes.Control))
+ {
+ {
+ _transferInProgress = true;
+
+ // Use a control transfer to send the report,
+ // even if the HID has an interrupt OUT endpoint.
+
+ success = _myHid.SendOutputReportViaControlTransfer(_hidHandle, outputReportBuffer);
+
+ _transferInProgress = false;
+ cmdSendOutputReportControl.Enabled = true;
+ }
+ }
+ else
+ {
+ Debug.Print("interrupt");
+ _transferInProgress = true;
+
+ // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
+
+ var cts = new CancellationTokenSource();
+
+ // Create a delegate to execute on a timeout.
+
+ Action onWriteTimeoutAction = OnWriteTimeout;
+
+ // Cancel the read if it hasn't completed after a timeout.
+
+ cts.CancelAfter(writeTimeout);
+
+ // Specify the function to call on a timeout.
+
+ cts.Token.Register(onWriteTimeoutAction);
+
+ // Send an Output report and wait for completion or timeout.
+
+ success = await _myHid.SendOutputReportViaInterruptTransfer(_deviceData, _hidHandle, outputReportBuffer, cts);
+
+ // Get here only if the operation completes without a timeout.
+
+ _transferInProgress = false;
+ cmdSendOutputReportInterrupt.Enabled = true;
+
+ // Dispose to stop the timeout timer.
+
+ cts.Dispose();
+ }
+ if (success)
+ {
+ DisplayReportData(outputReportBuffer, ReportTypes.Output, ReportReadOrWritten.Written);
+ }
+ else
+ {
+ CloseCommunications();
+ AccessForm(FormActions.AddItemToListBox, "The attempt to write an Output report failed.");
+ ScrollToBottomOfListBox();
+ }
+ }
+ }
+ else
+ {
+ AccessForm(FormActions.AddItemToListBox, "The HID doesn't have an Output report.");
+ }
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Scroll to the bottom of the list box and trim as needed.
+ ///
+
+ private void ScrollToBottomOfListBox()
+ {
+ try
+ {
+ LstResults.SelectedIndex = LstResults.Items.Count - 1;
+
+ // If the list box is getting too large, trim its contents by removing the earliest data.
+
+ if (LstResults.Items.Count > 1000)
+ {
+ Int32 count;
+ for (count = 1; count <= 500; count++)
+ {
+ LstResults.Items.RemoveAt(4);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to send or get a Feature report.
+ ///
+
+ private void SendOrGetFeatureReport()
+ {
+ try
+ {
+ // If the device hasn't been detected, was removed, or timed out on a previous attempt
+ // to access it, look for the device.
+
+ if (!_deviceHandleObtained)
+ {
+ _deviceHandleObtained = FindTheHid();
+ }
+
+ if (_deviceHandleObtained)
+ {
+ switch (_sendOrGet)
+ {
+ case SendOrGet.Send:
+ RequestToSendFeatureReport();
+ _sendOrGet = SendOrGet.Get;
+ break;
+ case SendOrGet.Get:
+ RequestToGetFeatureReport();
+ _sendOrGet = SendOrGet.Send;
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Request to send an Output report or get an Input report.
+ ///
+
+ private void SendOutputReportOrGetInputReport()
+ {
+ try
+ {
+ // If the device hasn't been detected, was removed, or timed out on a previous attempt
+ // to access it, look for the device.
+
+ if (!_deviceHandleObtained)
+ {
+ _deviceHandleObtained = FindTheHid();
+ }
+
+ if (_deviceHandleObtained)
+ {
+ if (_sendOrGet == SendOrGet.Send)
+ {
+ RequestToSendOutputReport();
+ _sendOrGet = SendOrGet.Get;
+ }
+ else
+ {
+ RequestToGetInputReport();
+ _sendOrGet = SendOrGet.Send;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Set the number of Input buffers (the number of Input reports
+ /// the host will store) from the value in the text box.
+ ///
+
+ private void SetInputReportBufferSize()
+ {
+ try
+ {
+ if (!_transferInProgress)
+ {
+ // Get the number of buffers from the text box.
+
+ Int32 numberOfInputBuffers = Convert.ToInt32(txtInputReportBufferSize.Text);
+
+ // Set the number of buffers.
+
+ _myHid.SetNumberOfInputBuffers(_hidHandle, numberOfInputBuffers);
+
+ // Verify and display the result.
+
+ GetInputReportBufferSize();
+ }
+ else
+ {
+ DisplayTransferInProgressMessage();
+ }
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Perform actions that must execute when the program ends.
+ ///
+
+ private void Shutdown()
+ {
+ try
+ {
+ CloseCommunications();
+ DeviceNotificationsStop();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Perform actions that must execute when the program starts.
+ ///
+
+ private void Startup()
+ {
+ const Int32 periodicTransferInterval = 1000;
+ try
+ {
+ _myHid = new Hid();
+ InitializeDisplay();
+
+ _periodicTransfers = new System.Timers.Timer(periodicTransferInterval);
+ _periodicTransfers.Elapsed += DoPeriodicTransfers;
+ _periodicTransfers.Stop();
+ _periodicTransfers.SynchronizingObject = this;
+
+ // Default USB Vendor ID and Product ID:
+
+ txtVendorID.Text = "0925";
+ txtProductID.Text = "7001";
+
+ GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
+
+ DeviceNotificationsStart();
+ FindDeviceUsingWmi();
+ FindTheHid();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// The Product ID has changed in the text box. Call a routine to handle it.
+ ///
+
+ private void txtProductID_TextChanged(Object sender, EventArgs e)
+ {
+ try
+ {
+ DeviceHasChanged();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// The Vendor ID has changed in the text box. Call a routine to handle it.
+ ///
+
+ private void txtVendorID_TextChanged(Object sender, EventArgs e)
+ {
+ try
+ {
+ DeviceHasChanged();
+ }
+ catch (Exception ex)
+ {
+ DisplayException(Name, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Provides a central mechanism for exception handling.
+ /// Displays a message box that describes the exception.
+ ///
+ ///
+ /// the module where the exception occurred.
+ /// the exception
+
+ internal static void DisplayException(String moduleName, Exception e)
+ {
+ // Create an error message.
+
+ String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
+
+ const String caption = "Unexpected Exception";
+
+ MessageBox.Show(message, caption, MessageBoxButtons.OK);
+ Debug.Write(message);
+
+ // Get the last error and display it.
+
+ Int32 error = Marshal.GetLastWin32Error();
+
+ Debug.WriteLine("The last Win32 Error was: " + error);
+ }
+
+ [STAThread]
+ internal static void Main() { Application.Run(new FrmMain()); }
+ private static FrmMain _transDefaultFormFrmMain;
+ internal static FrmMain TransDefaultFormFrmMain
+ {
+ get
+ {
+ if (_transDefaultFormFrmMain == null)
+ {
+ _transDefaultFormFrmMain = new FrmMain();
+ }
+ return _transDefaultFormFrmMain;
+ }
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 FrmMain.resX
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/FrmMain.resX Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ 25
+
+
\ No newline at end of file
diff -r 000000000000 -r 316364bd7d25 GenericHid.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/GenericHid.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,24 @@
+
+using System.Windows.Forms;
+
+namespace GenericHid
+{
+ ///
+ /// Runs the application and provides access to the instance of the form.
+ ///
+
+ public class GenericHid
+ {
+ internal static FrmMain FrmMy;
+
+ ///
+ /// Displays the application's main form.
+ ///
+
+ public static void Main()
+ {
+ FrmMy = new FrmMain();
+ Application.Run(FrmMy);
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 GenericHid.csproj
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/GenericHid.csproj Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,194 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}
+ WinExe
+ Properties
+ GenericHid
+ GenericHid
+ GenericHid.FrmMain
+
+
+ 3.5
+
+
+ v4.5
+
+ false
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 6.2.0.0
+ false
+ true
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 2
+ 285212672
+ false
+
+
+ pdbonly
+ false
+ bin\Release\
+ TRACE
+ prompt
+ 2
+ 285212672
+ false
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ 285212672
+ 2
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x86\Release\
+ TRACE
+ 285212672
+ 2
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ 285212672
+ 2
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x64\Release\
+ TRACE
+ 285212672
+ 2
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ 74AEA279A1F2ABCF00D2AB2668EE07AB57384C56
+
+
+ GenericHid_TemporaryKey.pfx
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+ Designer
+ FrmMain.cs
+
+
+ Designer
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4.5 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
\ No newline at end of file
diff -r 000000000000 -r 316364bd7d25 GenericHid.csproj.user
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/GenericHid.csproj.user Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,31 @@
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ publish\
+
+
+
+
+
+ en-US
+ false
+
+
\ No newline at end of file
diff -r 000000000000 -r 316364bd7d25 Generic_Hid_cs_v62.sln
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Generic_Hid_cs_v62.sln Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,32 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenericHid", "GenericHid.csproj", "{A6E0F52F-4599-4758-B956-9E8420FD28A8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Debug|x64.ActiveCfg = Debug|x64
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Debug|x64.Build.0 = Debug|x64
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Debug|x86.ActiveCfg = Debug|x86
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Debug|x86.Build.0 = Debug|x86
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Release|x64.ActiveCfg = Debug|x64
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Release|x64.Build.0 = Debug|x64
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Release|x86.ActiveCfg = Release|x86
+ {A6E0F52F-4599-4758-B956-9E8420FD28A8}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff -r 000000000000 -r 316364bd7d25 Hid.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Hid.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,739 @@
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace GenericHid
+{
+ ///
+ /// Supports Windows API functions for accessing HID-class USB devices.
+ /// Includes routines for retrieving information about the configuring a HID and
+ /// sending and receiving reports via control and interrupt transfers.
+ ///
+
+ internal sealed partial class Hid
+ {
+ // Used in error messages.
+
+ private const String ModuleName = "Hid";
+
+ internal NativeMethods.HIDP_CAPS Capabilities;
+ internal NativeMethods.HIDD_ATTRIBUTES DeviceAttributes;
+
+ // For viewing results of API calls in debug.write statements:
+
+ internal static Debugging MyDebugging = new Debugging();
+
+ ///
+ /// Provides a central mechanism for exception handling.
+ /// Displays a message box that describes the exception.
+ ///
+ ///
+ /// the module where the exception occurred.
+ /// the exception
+
+ internal static void DisplayException(String moduleName, Exception e)
+ {
+ // Create an error message.
+
+ String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
+
+ const String caption = "Unexpected Exception";
+
+ MessageBox.Show(message, caption, MessageBoxButtons.OK);
+ Debug.Write(message);
+
+ // Get the last error and display it.
+ Int32 error = Marshal.GetLastWin32Error();
+
+ Debug.WriteLine("The last Win32 Error was: " + error);
+ }
+
+ ///
+ /// Remove any Input reports waiting in the buffer.
+ ///
+ /// a handle to a device.
+ ///
+ /// True on success, False on failure.
+ ///
+
+ internal Boolean FlushQueue(SafeFileHandle hidHandle)
+ {
+ 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.
+ // ***
+
+ Boolean success = NativeMethods.HidD_FlushQueue(hidHandle);
+
+ return success;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Get HID attributes.
+ ///
+ /// HID handle retrieved with CreateFile
+ /// HID attributes structure
+ /// true on success
+
+ internal Boolean GetAttributes(SafeFileHandle hidHandle, ref NativeMethods.HIDD_ATTRIBUTES deviceAttributes)
+ {
+ Boolean success;
+ try
+ {
+ // ***
+ // API function:
+ // HidD_GetAttributes
+
+ // Purpose:
+ // Retrieves a HIDD_ATTRIBUTES structure containing the Vendor ID,
+ // Product ID, and Product Version Number for a device.
+
+ // Accepts:
+ // A handle returned by CreateFile.
+ // A pointer to receive a HIDD_ATTRIBUTES structure.
+
+ // Returns:
+ // True on success, False on failure.
+ // ***
+
+ success = NativeMethods.HidD_GetAttributes(hidHandle, ref deviceAttributes);
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ return success;
+ }
+
+ ///
+ /// Retrieves a structure with information about a device's capabilities.
+ ///
+ ///
+ /// a handle to a device.
+ ///
+ ///
+ /// An HIDP_CAPS structure.
+ ///
+
+ internal NativeMethods.HIDP_CAPS GetDeviceCapabilities(SafeFileHandle hidHandle)
+ {
+ var preparsedData = new IntPtr();
+
+ 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.
+ // ***
+
+ NativeMethods.HidD_GetPreparsedData(hidHandle, ref preparsedData);
+
+ // ***
+ // 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.
+ // ***
+
+ Int32 result = NativeMethods.HidP_GetCaps(preparsedData, ref Capabilities);
+ if ((result != 0))
+ {
+ Debug.WriteLine("");
+ Debug.WriteLine(" Usage: " + Convert.ToString(Capabilities.Usage, 16));
+ Debug.WriteLine(" Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
+ Debug.WriteLine(" Input Report Byte Length: " + Capabilities.InputReportByteLength);
+ Debug.WriteLine(" Output Report Byte Length: " + Capabilities.OutputReportByteLength);
+ Debug.WriteLine(" Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
+ Debug.WriteLine(" Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
+ Debug.WriteLine(" Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
+ Debug.WriteLine(" Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
+ Debug.WriteLine(" Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
+ Debug.WriteLine(" Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
+ Debug.WriteLine(" Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
+ Debug.WriteLine(" Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
+ Debug.WriteLine(" Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
+ Debug.WriteLine(" Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
+ Debug.WriteLine(" Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
+
+ // ***
+ // 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.
+ // ***
+
+ Int32 vcSize = Capabilities.NumberInputValueCaps;
+ var valueCaps = new Byte[vcSize];
+
+ NativeMethods.HidP_GetValueCaps(NativeMethods.HidP_Input, valueCaps, ref vcSize, preparsedData);
+
+ // (To use this data, copy the ValueCaps byte array into an array of structures.)
+ }
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ finally
+ {
+ // ***
+ // 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.
+ // ***
+
+ if (preparsedData != IntPtr.Zero)
+ {
+ NativeMethods.HidD_FreePreparsedData(preparsedData);
+ }
+ }
+ return Capabilities;
+ }
+
+ ///
+ /// reads a Feature report from the device.
+ ///
+ ///
+ /// the handle for learning about the device and exchanging Feature reports.
+ /// contains the requested report.
+
+ internal Boolean GetFeatureReport(SafeFileHandle hidHandle, ref Byte[] inFeatureReportBuffer)
+ {
+ try
+ {
+ Boolean success = false;
+
+ // ***
+ // 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.
+ // ***
+
+ if (!hidHandle.IsInvalid && !hidHandle.IsClosed)
+ {
+ success = NativeMethods.HidD_GetFeature(hidHandle, inFeatureReportBuffer, inFeatureReportBuffer.Length);
+
+ Debug.Print("HidD_GetFeature success = " + success);
+ }
+ return success;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Get the HID-class GUID
+ ///
+ /// the GUID
+
+ internal Guid GetHidGuid()
+ {
+ Guid hidGuid = Guid.Empty;
+ try
+ {
+ // ***
+ // API function: 'HidD_GetHidGuid
+
+ // Purpose: Retrieves the interface class GUID for the HID class.
+
+ // Accepts: A System.Guid object for storing the GUID.
+ // ***
+
+ NativeMethods.HidD_GetHidGuid(ref hidGuid);
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ return hidGuid;
+ }
+
+ ///
+ /// 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.
+ ///
+ ///
+ /// a HIDP_CAPS structure retrieved with HidP_GetCaps.
+ ///
+ ///
+ /// A String describing the Usage.
+ ///
+
+ internal String GetHidUsage(NativeMethods.HIDP_CAPS myCapabilities)
+ {
+ String usageDescription = "";
+
+ try
+ {
+ // Create32-bit Usage from Usage Page and Usage ID.
+
+ Int32 usage = myCapabilities.UsagePage * 256 + myCapabilities.Usage;
+
+ if (usage == Convert.ToInt32(0X102))
+ {
+ usageDescription = "mouse";
+ }
+ if (usage == Convert.ToInt32(0X106))
+ {
+ usageDescription = "keyboard";
+ }
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+
+ return usageDescription;
+ }
+
+ ///
+ /// reads an Input report from the device using a control transfer.
+ ///
+ /// the handle for learning about the device and exchanging Feature reports.
+ /// contains the requested report.
+
+ internal Boolean GetInputReportViaControlTransfer(SafeFileHandle hidHandle, ref Byte[] inputReportBuffer)
+ {
+ var success = false;
+
+ try
+ {
+ // ***
+ // API function: HidD_GetInputReport
+
+ // Purpose: Attempts to read an Input report from the device using a control transfer.
+
+ // 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.
+ // ***
+
+ if (!hidHandle.IsInvalid && !hidHandle.IsClosed)
+ {
+ success = NativeMethods.HidD_GetInputReport(hidHandle, inputReportBuffer, inputReportBuffer.Length + 1);
+ Debug.Print("HidD_GetInputReport success = " + success);
+ }
+ return success;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Reads an Input report from the device using an interrupt transfer.
+ ///
+ ///
+ /// the Filestream for writing data.
+ /// contains the report ID and report data.
+ ///
+ /// True on success. False on failure.
+ ///
+
+ internal async Task GetInputReportViaInterruptTransfer(FileStream deviceData, Byte[] inputReportBuffer, CancellationTokenSource cts)
+ {
+ try
+ {
+ Int32 bytesRead = 0;
+
+ // Begin reading an Input report.
+
+ Task t = deviceData.ReadAsync(inputReportBuffer, 0, inputReportBuffer.Length, cts.Token);
+
+ bytesRead = await t;
+
+ // Gets to here only if the read operation completed before a timeout.
+
+ Debug.Print("Asynchronous read completed. Bytes read = " + Convert.ToString(bytesRead));
+
+ // The operation has one of these completion states:
+
+ switch (t.Status)
+ {
+ case TaskStatus.RanToCompletion:
+ Debug.Print("Input report received from device");
+ break;
+ case TaskStatus.Canceled:
+ Debug.Print("Task canceled");
+ break;
+ case TaskStatus.Faulted:
+ Debug.Print("Unhandled exception");
+ break;
+ }
+ return bytesRead;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Retrieves the number of Input reports the HID driver will store.
+ ///
+ ///
+ /// a handle to a device
+ /// an integer to hold the returned value.
+ ///
+ ///
+ /// True on success, False on failure.
+ ///
+
+ internal Boolean GetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, ref Int32 numberOfInputBuffers)
+ {
+ 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
+ // ldest report.
+
+ // Accepts: a handle to a device and an integer to hold the number of buffers.
+
+ // Returns: True on success, False on failure.
+ // ***
+
+ Boolean success = NativeMethods.HidD_GetNumInputBuffers(hidDeviceObject, ref numberOfInputBuffers);
+
+ return success;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Timeout if read or write via interrupt transfer doesn't return.
+ ///
+
+ internal void OnTimeout()
+ {
+ try
+ {
+ // No action required.
+
+ Debug.Print("timeout");
+ }
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Attempts to open a handle to a HID.
+ ///
+ /// device path name returned by SetupDiGetDeviceInterfaceDetail
+ /// true if requesting read/write access for Input and Output reports
+ /// hidHandle - a handle to the HID
+
+ internal SafeFileHandle OpenHandle(String devicePathName, Boolean readAndWrite)
+ {
+ SafeFileHandle hidHandle;
+
+ try
+ {
+ if (readAndWrite)
+ {
+ // ***
+ // API function:
+ // CreateFile
+
+ // Purpose:
+ // Retrieves a handle to a device.
+
+ // Accepts:
+ // A device path name returned by SetupDiGetDeviceInterfaceDetail
+ // The type of access requested (read/write).
+ // FILE_SHARE attributes to allow other processes to access the device while this handle is open.
+ // A Security structure or IntPtr.Zero.
+ // A creation disposition value. Use OPEN_EXISTING for devices.
+ // Flags and attributes for files. Not used for devices.
+ // Handle to a template file. Not used.
+
+ // Returns: a handle without read or write access.
+ // This enables obtaining information about all HIDs, even system
+ // keyboards and mice.
+ // Separate handles are used for reading and writing.
+ // ***
+
+ hidHandle = FileIo.CreateFile(devicePathName, FileIo.GenericRead | FileIo.GenericWrite, FileIo.FileShareRead | FileIo.FileShareWrite, IntPtr.Zero, FileIo.OpenExisting, 0, IntPtr.Zero);
+ }
+ else
+ {
+ hidHandle = FileIo.CreateFile(devicePathName, 0, FileIo.FileShareRead | FileIo.FileShareWrite, IntPtr.Zero, FileIo.OpenExisting, 0, IntPtr.Zero);
+ }
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ return hidHandle;
+ }
+
+ ///
+ /// Writes a Feature report to the device.
+ ///
+ ///
+ /// contains the report ID and report data.
+ /// handle to the device.
+ ///
+ ///
+ /// True on success. False on failure.
+ ///
+
+ internal Boolean SendFeatureReport(SafeFileHandle hidHandle, Byte[] outFeatureReportBuffer)
+ {
+ 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.
+ // ***
+
+ Boolean success = NativeMethods.HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);
+
+ Debug.Print("HidD_SetFeature success = " + success);
+
+ return success;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Writes an Output report to the device using a control transfer.
+ ///
+ ///
+ /// contains the report ID and report data.
+ /// handle to the device.
+ ///
+ ///
+ /// True on success. False on failure.
+ ///
+
+ internal Boolean SendOutputReportViaControlTransfer(SafeFileHandle hidHandle, Byte[] outputReportBuffer)
+ {
+ try
+ {
+ // ***
+ // API function: HidD_SetOutputReport
+
+ // Purpose:
+ // Attempts to send an Output report to the device using a control transfer.
+
+ // 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.
+ // ***
+
+ Boolean success = NativeMethods.HidD_SetOutputReport(hidHandle, outputReportBuffer, outputReportBuffer.Length + 1);
+
+ Debug.Print("HidD_SetOutputReport success = " + success);
+
+ return success;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// Writes an Output report to the device using an interrupt transfer.
+ ///
+ ///
+ /// the Filestream for writing data.
+ /// SafeFileHandle to the device.
+ /// contains the report ID and report data.
+ /// CancellationTokenSource
+ ///
+ ///
+ /// 1 on success. 0 on failure.
+ ///
+
+ internal async Task SendOutputReportViaInterruptTransfer
+ (FileStream fileStreamDeviceData, SafeFileHandle hidHandle, Byte[] outputReportBuffer, CancellationTokenSource cts)
+ {
+ try
+ {
+ var success = false;
+
+ // Begin writing the Output report.
+
+ Task t = fileStreamDeviceData.WriteAsync(outputReportBuffer, 0, outputReportBuffer.Length, cts.Token);
+
+ await t;
+
+ // Gets to here only if the write operation completed before a timeout.
+
+ Debug.Print("Asynchronous write completed");
+
+ // The operation has one of these completion states:
+
+ switch (t.Status)
+ {
+ case TaskStatus.RanToCompletion:
+ success = true;
+ Debug.Print("Output report written to device");
+ break;
+ case TaskStatus.Canceled:
+ Debug.Print("Task canceled");
+ break;
+ case TaskStatus.Faulted:
+ Debug.Print("Unhandled exception");
+ break;
+ }
+
+ return success;
+ }
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+
+ ///
+ /// sets the number of input reports the host HID driver store.
+ ///
+ ///
+ /// a handle to the device.
+ /// the requested number of input reports.
+ ///
+ ///
+ /// True on success. False on failure.
+ ///
+
+ internal Boolean SetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, Int32 numberBuffers)
+ {
+ 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.
+ // ***
+
+ NativeMethods.HidD_SetNumInputBuffers(hidDeviceObject, numberBuffers);
+ return true;
+ }
+
+ catch (Exception ex)
+ {
+ DisplayException(ModuleName, ex);
+ throw;
+ }
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 HidDeclarations.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/HidDeclarations.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,135 @@
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Runtime.InteropServices;
+
+namespace GenericHid
+{
+ ///
+ /// API declarations for HID communications.
+ ///
+ internal sealed partial class Hid
+ {
+ internal static class NativeMethods
+ {
+ // from hidpi.h
+ // Typedef enum defines a set of integer constants for HidP_Report_Type
+
+ internal const Int16 HidP_Input = 0;
+ internal const Int16 HidP_Output = 1;
+ internal const Int16 HidP_Feature = 2;
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct HIDD_ATTRIBUTES
+ {
+ internal Int32 Size;
+ internal UInt16 VendorID;
+ internal UInt16 ProductID;
+ internal UInt16 VersionNumber;
+ }
+
+ internal struct HIDP_CAPS
+ {
+ internal Int16 Usage;
+ internal Int16 UsagePage;
+ internal Int16 InputReportByteLength;
+ internal Int16 OutputReportByteLength;
+ internal Int16 FeatureReportByteLength;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)] internal Int16[] Reserved;
+ internal Int16 NumberLinkCollectionNodes;
+ internal Int16 NumberInputButtonCaps;
+ internal Int16 NumberInputValueCaps;
+ internal Int16 NumberInputDataIndices;
+ internal Int16 NumberOutputButtonCaps;
+ internal Int16 NumberOutputValueCaps;
+ internal Int16 NumberOutputDataIndices;
+ internal Int16 NumberFeatureButtonCaps;
+ internal Int16 NumberFeatureValueCaps;
+ internal Int16 NumberFeatureDataIndices;
+ }
+
+ // If IsRange is false, UsageMin is the Usage and UsageMax is unused.
+ // If IsStringRange is false, StringMin is the String index and StringMax is unused.
+ // If IsDesignatorRange is false, DesignatorMin is the designator index and DesignatorMax is unused.
+
+ internal struct HidP_Value_Caps
+ {
+ internal Int16 UsagePage;
+ internal Byte ReportID;
+ internal Int32 IsAlias;
+ internal Int16 BitField;
+ internal Int16 LinkCollection;
+ internal Int16 LinkUsage;
+ internal Int16 LinkUsagePage;
+ internal Int32 IsRange;
+ internal Int32 IsStringRange;
+ internal Int32 IsDesignatorRange;
+ internal Int32 IsAbsolute;
+ internal Int32 HasNull;
+ internal Byte Reserved;
+ internal Int16 BitSize;
+ internal Int16 ReportCount;
+ internal Int16 Reserved2;
+ internal Int16 Reserved3;
+ internal Int16 Reserved4;
+ internal Int16 Reserved5;
+ internal Int16 Reserved6;
+ internal Int32 LogicalMin;
+ internal Int32 LogicalMax;
+ internal Int32 PhysicalMin;
+ internal Int32 PhysicalMax;
+ internal Int16 UsageMin;
+ internal Int16 UsageMax;
+ internal Int16 StringMin;
+ internal Int16 StringMax;
+ internal Int16 DesignatorMin;
+ internal Int16 DesignatorMax;
+ internal Int16 DataIndexMin;
+ internal Int16 DataIndexMax;
+ }
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_FlushQueue(SafeFileHandle HidDeviceObject);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_FreePreparsedData(IntPtr PreparsedData);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_GetAttributes(SafeFileHandle HidDeviceObject, ref HIDD_ATTRIBUTES Attributes);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_GetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
+ Int32 ReportBufferLength);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_GetInputReport(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
+ Int32 ReportBufferLength);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern void HidD_GetHidGuid(ref Guid HidGuid);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_GetNumInputBuffers(SafeFileHandle HidDeviceObject, ref Int32 NumberBuffers);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_GetPreparsedData(SafeFileHandle HidDeviceObject, ref IntPtr PreparsedData);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_SetFeature(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
+ Int32 ReportBufferLength);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_SetNumInputBuffers(SafeFileHandle HidDeviceObject, Int32 NumberBuffers);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Boolean HidD_SetOutputReport(SafeFileHandle HidDeviceObject, Byte[] lpReportBuffer,
+ Int32 ReportBufferLength);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Int32 HidP_GetCaps(IntPtr PreparsedData, ref HIDP_CAPS Capabilities);
+
+ [DllImport("hid.dll", SetLastError = true)]
+ internal static extern Int32 HidP_GetValueCaps(Int32 ReportType, Byte[] ValueCaps, ref Int32 ValueCapsLength,
+ IntPtr PreparsedData);
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 Properties/Resources.Designer.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Properties/Resources.Designer.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.18010
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace GenericHid.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GenericHid.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 Properties/Resources.resx
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Properties/Resources.resx Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff -r 000000000000 -r 316364bd7d25 Properties/Settings.Designer.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Properties/Settings.Designer.cs Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.18010
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace GenericHid.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff -r 000000000000 -r 316364bd7d25 Properties/Settings.settings
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Properties/Settings.settings Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff -r 000000000000 -r 316364bd7d25 app.config
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app.config Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,3 @@
+
+
+
diff -r 000000000000 -r 316364bd7d25 publish/GenericHid.application
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/publish/GenericHid.application Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ oQgb8A8n+lzj+3t+OgYSWwxoRg2BjZwoA6qP23iuoq0=
+
+
+
+Lq11Sw3U1N8vRticxZzSjoQ6oqyNni1fUjnATzMnmvE=RaX+F7wItRwo1xWOj5oNucSLJAEG+ZMa+gP92gUY2DeHBZJ3xl+8UYF/kuuSOf4DBNquvXRHyLXeegzkFttrqtO704gxqcIbXBcZi7w0PXZNmw+kN/8ykkWCShQiz8f3IYjqjQV199fxw3NAciCpWCLNSAMRYtVX6VyIEQCI6ns=vZK+hjF855eH6ywa/BZBvxkMJFFIIFjX0riqpVp0M088+99Ygevu3AGL1ajEdjQwry8w4ZXnz4jUfHSC2nhBKONyLrzV2dQH+RwonfAW8ExhueAb7u/pG77yb3T+kRbiHNPuRP8nlFTzm+riq/k1A1EqAK2n6MeVFUyk85S3xtU=AQABCN=LVR2012\janNr/7DS53yGSNQxZA8cHgQphhjotTpOqFPw/G1Vh1qZI=VEtiDTr4D9sGpmtS0wEej0Kmlx+zXyxZglD+CUVKbqW6YbPgfVbgZTRPtps+asBMqCusZUVUqtnwIvFJ89GwlKr+59nMUMlxiPuHFrnM8LJqWTMT05lJFO9P1h3t2U0pkCkbD+tFIpcLUxuVJmG+Lx9SH+nYnxY90QbhgAR43eg=vZK+hjF855eH6ywa/BZBvxkMJFFIIFjX0riqpVp0M088+99Ygevu3AGL1ajEdjQwry8w4ZXnz4jUfHSC2nhBKONyLrzV2dQH+RwonfAW8ExhueAb7u/pG77yb3T+kRbiHNPuRP8nlFTzm+riq/k1A1EqAK2n6MeVFUyk85S3xtU=AQABMIIBxTCCAS6gAwIBAgIQG1z/tZx30LZKDzrL/KUXPjANBgkqhkiG9w0BAQsFADAhMR8wHQYDVQQDHhYATABWAFIAMgAwADEAMgBcAGoAYQBuMB4XDTEzMTAzMDAxMzYxNloXDTE0MTAzMDA3MzYxNlowITEfMB0GA1UEAx4WAEwAVgBSADIAMAAxADIAXABqAGEAbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvZK+hjF855eH6ywa/BZBvxkMJFFIIFjX0riqpVp0M088+99Ygevu3AGL1ajEdjQwry8w4ZXnz4jUfHSC2nhBKONyLrzV2dQH+RwonfAW8ExhueAb7u/pG77yb3T+kRbiHNPuRP8nlFTzm+riq/k1A1EqAK2n6MeVFUyk85S3xtUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQB5WjMIunQoSYZTqVnK1+emQt2+v/SzZc1oYY1G5ikE/t92Phyu0E9PgA6nXavF2IMrzOnmnNasTO9ygFQ+ck96TyD1FsQW9XRYxYdCn5oC+Caelwm5CPHRI2PKnw15IRDT9hHFj4AxYMSnN7uPXO+7eOjAbtRnynn0KAq+1PsFAA==
\ No newline at end of file
diff -r 000000000000 -r 316364bd7d25 readme.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.txt Wed May 14 07:52:21 2014 +0200
@@ -0,0 +1,136 @@
+ ///
+ /// Project: GenericHid
+ ///
+ /// ***********************************************************************
+ /// Software License Agreement
+ ///
+ /// Licensor grants any person obtaining a copy of this software ("You")
+ /// a worldwide, royalty-free, non-exclusive license, for the duration of
+ /// the copyright, free of charge, to store and execute the Software in a
+ /// computer system and to incorporate the Software or any portion of it
+ /// in computer programs You write.
+ ///
+ /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ /// THE SOFTWARE.
+ /// ***********************************************************************
+ ///
+ /// Author
+ /// Jan Axelson
+ ///
+ /// This software was written using Visual Studio Express 2012 for Windows
+ /// Desktop building for the .NET Framework v4.5.
+ ///
+ /// Purpose:
+ /// Demonstrates USB communications with a generic HID-class device
+ ///
+ /// Requirements:
+ /// Windows Vista or later and an attached USB generic Human Interface Device (HID).
+ /// (Does not run on Windows XP or earlier because .NET Framework 4.5 will not install on these OSes.)
+ ///
+ /// Description:
+ /// Finds an attached device that matches the vendor and product IDs in the form's
+ /// text boxes.
+ ///
+ /// Retrieves the device's capabilities.
+ /// Sends and requests HID reports.
+ ///
+ /// Uses the System.Management class and Windows Management Instrumentation (WMI) to detect
+ /// when a device is attached or removed.
+ ///
+ /// A list box displays the data sent and received along with error and status messages.
+ /// You can select data to send and 1-time or periodic transfers.
+ ///
+ /// You can change the size of the host's Input report buffer and request to use control
+ /// transfers only to exchange Input and Output reports.
+ ///
+ /// To view additional debugging messages, in the Visual Studio development environment,
+ /// from the main menu, select Build > Configuration Manager > Active Solution Configuration
+ /// and select Configuration > Debug and from the main menu, select View > Output.
+ ///
+ /// The application uses asynchronous FileStreams to read Input reports and write Output
+ /// reports so the application's main thread doesn't have to wait for the device to retrieve a
+ /// report when the HID driver's buffer is empty or send a report when the device's endpoint is busy.
+ ///
+ /// For code that finds a device and opens handles to it, see the FindTheHid routine in frmMain.cs.
+ /// For code that reads from the device, see GetInputReportViaInterruptTransfer,
+ /// GetInputReportViaControlTransfer, and GetFeatureReport in Hid.cs.
+ /// For code that writes to the device, see SendInputReportViaInterruptTransfer,
+ /// SendInputReportViaControlTransfer, and SendFeatureReport in Hid.cs.
+ ///
+ /// This project includes the following modules:
+ ///
+ /// GenericHid.cs - runs the application.
+ /// FrmMain.cs - routines specific to the form.
+ /// Hid.cs - routines specific to HID communications.
+ /// DeviceManagement.cs - routine for obtaining a handle to a device from its GUID.
+ /// Debugging.cs - contains a routine for displaying API error messages.
+ /// HidDeclarations.cs - Declarations for API functions used by Hid.cs.
+ /// FileIODeclarations.cs - Declarations for file-related API functions.
+ /// DeviceManagementDeclarations.cs - Declarations for API functions used by DeviceManagement.cs.
+ /// DebuggingDeclarations.cs - Declarations for API functions used by Debugging.cs.
+ ///
+ /// Companion device firmware for several device CPUs is available from www.Lvr.com/hidpage.htm
+ /// You can use any generic HID (not a system mouse or keyboard) that sends and receives reports.
+ /// This application will not detect or communicate with non-HID-class devices.
+ ///
+ /// For more information about HIDs and USB, and additional example device firmware to use
+ /// with this application, visit Lakeview Research at http://Lvr.com
+ /// Send comments, bug reports, etc. to jan@Lvr.com or post on my PORTS forum: http://www.lvr.com/forum
+ ///
+ /// V6.2
+ /// 11/12/13
+ /// Disabled form buttons when a transfer is in progress.
+ /// Other minor edits for clarity and readability.
+ /// Will NOT run on Windows XP or earlier, see below.
+ ///
+ /// V6.1
+ /// 10/28/13
+ /// Uses the .NET System.Management class to detect device arrival and removal with WMI instead of Win32 RegisterDeviceNotification.
+ /// Other minor edits.
+ /// Will NOT run on Windows XP or earlier, see below.
+ ///
+ /// V6.0
+ /// 2/8/13
+ /// This version will NOT run on Windows XP or earlier because the code uses .NET Framework 4.5 to support asynchronous FileStreams.
+ /// The .NET Framework 4.5 redistributable is compatible with Windows 8, Windows 7 SP1, Windows Server 2008 R2 SP1,
+ /// Windows Server 2008 SP2, Windows Vista SP2, and Windows Vista SP3.
+ /// For compatibility, replaced ToInt32 with ToInt64 here:
+ /// IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
+ /// and here:
+ /// if ((deviceNotificationHandle.ToInt64() == IntPtr.Zero.ToInt64()))
+ /// For compatibility if the charset isn't English, added System.Globalization.CultureInfo.InvariantCulture here:
+ /// if ((String.Compare(DeviceNameString, mydevicePathName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))
+ /// Replaced all Microsoft.VisualBasic namespace code with other .NET equivalents.
+ /// Revised user interface for more flexibility.
+ /// Moved interrupt-transfer and other HID-specific code to Hid.cs.
+ /// Used JetBrains ReSharper to clean up the code: http://www.jetbrains.com/resharper/
+ ///
+ /// V5.0
+ /// 3/30/11
+ /// Replaced ReadFile and WriteFile with FileStreams. Thanks to Joe Dunne and John on my Ports forum for tips on this.
+ /// Simplified Hid.cs.
+ /// Replaced the form timer with a system timer.
+ ///
+ /// V4.6
+ /// 1/12/10
+ /// Supports Vendor IDs and Product IDs up to FFFFh.
+ ///
+ /// V4.52
+ /// 11/10/09
+ /// Changed HIDD_ATTRIBUTES to use UInt16
+ ///
+ /// V4.51
+ /// 2/11/09
+ /// Moved Free_ and similar to Finally blocks to ensure they execute.
+ ///
+ /// V4.5
+ /// 2/9/09
+ /// Changes to support 64-bit systems, memory management, and other corrections.
+ /// Big thanks to Peter Nielsen.
+ ///
+ ///