# 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<ClassDiagram MajorVersion="1" MinorVersion="1"> + <Class Name="GenericHid.Debugging" Collapsed="true"> + <Position X="0.5" Y="0.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AQAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI=</HashCode> + <FileName>Debugging.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.DeviceManagement" Collapsed="true"> + <Position X="2.25" Y="0.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAIQAAAAACEAABAAEAAEAgBDAgAIAQCEIAgBkAAAA=</HashCode> + <FileName>DeviceManagement.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.FileIO" Collapsed="true"> + <Position X="4" Y="0.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAQAAAAAAAAAAAAAgAQAgAgAAAAAAAAAAAABAAAAAAQ=</HashCode> + <FileName>FileIODeclarations.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.FrmMain"> + <Position X="0.5" Y="1.5" Width="1.5" /> + <NestedTypes> + <Delegate Name="GenericHid.FrmMain.MarshalToForm" Collapsed="true"> + <TypeIdentifier> + <NewMemberFileName>FrmMain.cs</NewMemberFileName> + </TypeIdentifier> + </Delegate> + </NestedTypes> + <TypeIdentifier> + <HashCode>ICUA1BAQNaMYBREAgFCQgUIDUERCJwAKCDHCxEEQUEA=</HashCode> + <FileName>FrmMain.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.GenericHid" Collapsed="true"> + <Position X="2.25" Y="1.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAABAAAAAA=</HashCode> + <FileName>GenericHid.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.Hid" Collapsed="true"> + <Position X="4" Y="1.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>ADSAUARIUAAAgAQAAAAJAFEAAEgAAAAAACgVABgAACE=</HashCode> + <FileName>Hid.cs</FileName> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.Properties.Resources" Collapsed="true"> + <Position X="0.5" Y="2.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAABEAAAAQAAAAAAAAAAAAAAAIA=</HashCode> + </TypeIdentifier> + </Class> + <Class Name="GenericHid.Properties.Settings" Collapsed="true"> + <Position X="2.25" Y="2.5" Width="1.5" /> + <TypeIdentifier> + <HashCode>AAAAAAAAAAAAAAAAAAAAIAAAAAABAAAAAAAAAAAAAAA=</HashCode> + </TypeIdentifier> + </Class> + <Font Name="Tahoma" Size="10" /> +</ClassDiagram> \ 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 +{ + /// <summary> + /// Used only in Debug.Write statements. + /// </summary> + /// + internal sealed partial class Debugging + { + /// <summary> + /// Get text that describes the result of an API call. + /// </summary> + /// + /// <param name="functionName"> the name of the API function. </param> + /// + /// <returns> + /// The text. + /// </returns> + + 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 +{ + /// <summary> + /// Win32 API declarations for Debug.Write statements. + /// </summary> + /// + 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 +{ + /// <summary> + /// Routine for detecting devices using Win32 SetupDi functions. + /// </summary> + /// + sealed internal partial class DeviceManagement + { + private const String ModuleName = "Device Management"; + + /// <summary> + /// Provides a central mechanism for exception handling. + /// Displays a message box that describes the exception. + /// </summary> + /// + /// <param name="name"> the module where the exception occurred. </param> + /// <param name="e"> the exception </param> + + 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; + } + } + + /// <summary> + /// Use SetupDi API functions to retrieve the device path name of an + /// attached device that belongs to a device interface class. + /// </summary> + /// + /// <param name="myGuid"> an interface class GUID. </param> + /// <param name="devicePathName"> a pointer to the device path name + /// of an attached device. </param> + /// + /// <returns> + /// True if a device is found, False if not. + /// </returns> + + 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 + { + ///<summary > + // API declarations relating to device management (SetupDixxx and + // RegisterDeviceNotification functions). + /// </summary> + + // 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 +{ + /// <summary> + /// Win32 API declarations relating to file I/O. + /// </summary> + /// + 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 +{ + ///<summary> + /// 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. + /// + /// </summary> + + 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); + + /// <summary> + /// Performs various application-specific functions that + /// involve accessing the application's form. + /// </summary> + /// + /// <param name="action"> a FormActions member that names the action to perform on the form</param> + /// <param name="formText"> text that the form displays or the code uses for + /// another purpose. Actions that don't use text ignore this parameter. </param> + + 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; + } + } + + /// <summary> + /// Add a handler to detect arrival of devices using WMI. + /// </summary> + + 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(); + } + } + + /// <summary> + /// Add a handler to detect removal of devices using WMI. + /// </summary> + + 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(); + } + } + + /// <summary> + /// Close the handle and FileStreams for a device. + /// </summary> + /// + 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; + } + + /// <summary> + /// Search for a specific device. + /// </summary> + + 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; + } + } + + /// <summary> + /// Request to get a Feature report from the device. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + + 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; + } + } + + /// <summary> + /// Request to get an Input report from the device using a control transfer. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + + 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; + } + } + + /// <summary> + /// Request to get an Input report retrieved using interrupt transfers. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + /// + 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; + } + } + + /// <summary> + /// Set the number of Input reports the HID driver will store. + /// </summary> + + private void cmdInputReportBufferSize_Click(Object sender, EventArgs e) + { + try + { + if (_transferInProgress) + { + DisplayTransferInProgressMessage(); + } + else + { + SetInputReportBufferSize(); + } + } + catch + (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Alternate sending and getting a report. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + + 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; + } + } + + /// <summary> + /// Request to send a Feature report using a control transfer. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + + 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; + } + } + + /// <summary> + /// Request to send an Output report using a control transfer. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + /// + 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; + } + } + + /// <summary> + /// Request to send an Output report using an interrupt transfer. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + + 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; + } + } + + /// <summary> + /// Called on arrival of any device. + /// Calls a routine that searches to see if the desired device is present. + /// </summary> + + 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; + } + } + + /// <summary> + /// Called if the user changes the Vendor ID or Product ID in the text box. + /// </summary> + + 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; + } + } + + /// <summary> + /// Add handlers to detect device arrival and removal. + /// </summary> + + private void DeviceNotificationsStart() + { + AddDeviceArrivedHandler(); + AddDeviceRemovedHandler(); + } + + /// <summary> + /// Stop receiving notifications about device arrival and removal + /// </summary> + + private void DeviceNotificationsStop() + { + try + { + if (_deviceArrivedWatcher != null) + _deviceArrivedWatcher.Stop(); + if (_deviceRemovedWatcher != null) + _deviceRemovedWatcher.Stop(); + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Called on removal of any device. + /// Calls a routine that searches to see if the desired device is still present. + /// </summary> + /// + 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; + } + } + + /// <summary> + /// Displays received or written report data. + /// </summary> + /// + /// <param name="buffer"> contains the report data. </param> + /// <param name="currentReportType" > "Input", "Output", or "Feature"</param> + /// <param name="currentReadOrWritten" > "read" for Input and IN Feature reports, "written" for Output and OUT Feature reports.</param> + + 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; + } + } + + /// <summary> + /// Display a message if the user clicks a button when a transfer is in progress. + /// </summary> + /// + private void DisplayTransferInProgressMessage() + { + AccessForm(FormActions.AddItemToListBox, "Command not executed because a transfer is in progress."); + ScrollToBottomOfListBox(); + } + + /// <summary> + /// Do periodic transfers. + /// </summary> + /// <param name="source"></param> + /// <param name="e"></param> + /// <remarks> + /// The timer is enabled only if continuous (periodic) transfers have been requested. + /// </remarks> + + private void DoPeriodicTransfers(object source, ElapsedEventArgs e) + { + try + { + PeriodicTransfers(); + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Enable the command buttons on the form. + /// Needed after attempting a transfer and device not found. + /// </summary> + /// + private void EnableFormControls() + { + cmdGetInputReportInterrupt.Enabled = true; + cmdSendOutputReportControl.Enabled = true; + cmdGetInputReportControl.Enabled = true; + cmdGetFeatureReport.Enabled = true; + cmdSendFeatureReport.Enabled = true; + cmdPeriodicTransfers.Enabled = true; + cmdSendOutputReportInterrupt.Enabled = true; + } + + /// <summary> + /// Use the System.Management class to find a device by Vendor ID and Product ID using WMI. If found, display device properties. + /// </summary> + /// <remarks> + /// 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. + /// </remarks> + + 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; + } + } + + /// <summary> + /// 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. + /// </summary> + /// + /// <returns> + /// True if the device is detected, False if not detected. + /// </returns> + + 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; + } + } + + /// <summary> + /// Perform shutdown operations. + /// </summary> + + private void frmMain_Closed(Object eventSender, EventArgs eventArgs) + { + try + { + Shutdown(); + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Perform startup operations. + /// </summary> + + 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; + } + } + + /// <summary> + /// Find and display the number of Input buffers + /// (the number of Input reports the HID driver will store). + /// </summary> + + 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; + } + } + + /// <summary> + /// Retrieve a Vendor ID and Product ID in hexadecimal + /// from the form's text boxes and convert the text to Int32s. + /// </summary> + /// + /// <param name="myVendorId"> the Vendor ID</param> + /// <param name="myProductId"> the Product ID</param> + + 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; + } + } + + /// <summary> + /// Initialize the elements on the form. + /// </summary> + + 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; + } + } + + /// <summary> + /// Enables accessing a form's controls from another thread + /// </summary> + /// + /// <param name="action"> a FormActions member that names the action to perform on the form </param> + /// <param name="textToDisplay"> text that the form displays or the code uses for + /// another purpose. Actions that don't use text ignore this parameter. </param> + + 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; + } + } + + /// <summary> + /// Timeout if read via interrupt transfer doesn't return. + /// </summary> + + 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; + } + } + + /// <summary> + /// Timeout if write via interrupt transfer doesn't return. + /// </summary> + + 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; + } + } + + /// <summary> + /// Alternat sending and getting a report. + /// </summary> + + private void PeriodicTransfers() + { + try + { + if (!_transferInProgress) + { + if (_reportType == ReportTypes.Feature) + { + SendOrGetFeatureReport(); + } + else + { + // Output and Input reports + + SendOutputReportOrGetInputReport(); + } + } + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Start doing periodic transfers. + /// </summary> + + 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(); + } + + /// <summary> + /// Stop doing periodic transfers. + /// </summary> + + 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) + { + } + + /// <summary> + /// Request a Feature report. + /// Assumes report ID = 0. + /// </summary> + + 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; + } + } + + /// <summary> + /// Request an Input report. + /// Assumes report ID = 0. + /// </summary> + + 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; + } + } + + /// <summary> + /// Sends a Feature report. + /// Assumes report ID = 0. + /// </summary> + + 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; + } + } + + /// <summary> + /// Sends an Output report. + /// Assumes report ID = 0. + /// </summary> + + 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; + } + } + + /// <summary> + /// Scroll to the bottom of the list box and trim as needed. + /// </summary> + + 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; + } + } + + /// <summary> + /// Request to send or get a Feature report. + /// </summary> + + 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; + } + } + + /// <summary> + /// Request to send an Output report or get an Input report. + /// </summary> + + 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; + } + } + + /// <summary> + /// Set the number of Input buffers (the number of Input reports + /// the host will store) from the value in the text box. + /// </summary> + + 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; + } + } + + /// <summary> + /// Perform actions that must execute when the program ends. + /// </summary> + + private void Shutdown() + { + try + { + CloseCommunications(); + DeviceNotificationsStop(); + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Perform actions that must execute when the program starts. + /// </summary> + + 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; + } + } + + /// <summary> + /// The Product ID has changed in the text box. Call a routine to handle it. + /// </summary> + + private void txtProductID_TextChanged(Object sender, EventArgs e) + { + try + { + DeviceHasChanged(); + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// The Vendor ID has changed in the text box. Call a routine to handle it. + /// </summary> + + private void txtVendorID_TextChanged(Object sender, EventArgs e) + { + try + { + DeviceHasChanged(); + } + catch (Exception ex) + { + DisplayException(Name, ex); + throw; + } + } + + /// <summary> + /// Provides a central mechanism for exception handling. + /// Displays a message box that describes the exception. + /// </summary> + /// + /// <param name="moduleName"> the module where the exception occurred. </param> + /// <param name="e"> the exception </param> + + 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <metadata name="ToolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>17, 17</value> + </metadata> + <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <value>25</value> + </metadata> +</root> \ 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 +{ + /// <summary> + /// Runs the application and provides access to the instance of the form. + /// </summary> + + public class GenericHid + { + internal static FrmMain FrmMy; + + /// <summary> + /// Displays the application's main form. + /// </summary> + + 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.30729</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{A6E0F52F-4599-4758-B956-9E8420FD28A8}</ProjectGuid> + <OutputType>WinExe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>GenericHid</RootNamespace> + <AssemblyName>GenericHid</AssemblyName> + <StartupObject>GenericHid.FrmMain</StartupObject> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>3.5</OldToolsVersion> + <UpgradeBackupLocation> + </UpgradeBackupLocation> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <TargetFrameworkProfile /> + <IsWebBootstrapper>false</IsWebBootstrapper> + <PublishUrl>publish\</PublishUrl> + <Install>true</Install> + <InstallFrom>Disk</InstallFrom> + <UpdateEnabled>false</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>6.2.0.0</ApplicationVersion> + <UseApplicationTrust>false</UseApplicationTrust> + <PublishWizardCompleted>true</PublishWizardCompleted> + <BootstrapperEnabled>true</BootstrapperEnabled> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>2</WarningLevel> + <BaseAddress>285212672</BaseAddress> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>2</WarningLevel> + <BaseAddress>285212672</BaseAddress> + <Prefer32Bit>false</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\x86\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <BaseAddress>285212672</BaseAddress> + <WarningLevel>2</WarningLevel> + <DebugType>full</DebugType> + <PlatformTarget>x86</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> + <OutputPath>bin\x86\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <BaseAddress>285212672</BaseAddress> + <WarningLevel>2</WarningLevel> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x86</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\x64\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <BaseAddress>285212672</BaseAddress> + <WarningLevel>2</WarningLevel> + <DebugType>full</DebugType> + <PlatformTarget>x64</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + <OutputPath>bin\x64\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <BaseAddress>285212672</BaseAddress> + <WarningLevel>2</WarningLevel> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x64</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup> + <ManifestCertificateThumbprint>74AEA279A1F2ABCF00D2AB2668EE07AB57384C56</ManifestCertificateThumbprint> + </PropertyGroup> + <PropertyGroup> + <ManifestKeyFile>GenericHid_TemporaryKey.pfx</ManifestKeyFile> + </PropertyGroup> + <PropertyGroup> + <GenerateManifests>true</GenerateManifests> + </PropertyGroup> + <PropertyGroup> + <SignManifests>true</SignManifests> + </PropertyGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ItemGroup> + <Reference Include="microsoft.visualbasic" /> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Management" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="AssemblyInfo.cs" /> + <Compile Include="Debugging.cs" /> + <Compile Include="DebuggingDeclarations.cs" /> + <Compile Include="DeviceManagement.cs" /> + <Compile Include="DeviceManagementDeclarations.cs" /> + <Compile Include="FileIODeclarations.cs" /> + <Compile Include="FrmMain.cs"> + <SubType>Form</SubType> + </Compile> + <Compile Include="GenericHid.cs" /> + <Compile Include="Hid.cs" /> + <Compile Include="HidDeclarations.cs" /> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + <DependentUpon>Settings.settings</DependentUpon> + </Compile> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="FrmMain.resX"> + <SubType>Designer</SubType> + <DependentUpon>FrmMain.cs</DependentUpon> + </EmbeddedResource> + <EmbeddedResource Include="Properties\Resources.resx"> + <SubType>Designer</SubType> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> + <None Include="app.config" /> + <None Include="ClassDiagram1.cd" /> + <None Include="GenericHid_TemporaryKey.pfx" /> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + </ItemGroup> + <ItemGroup> + <Content Include="readme.txt" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include=".NETFramework,Version=v4.5"> + <Visible>False</Visible> + <ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1</ProductName> + <Install>false</Install> + </BootstrapperPackage> + </ItemGroup> +</Project> \ 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0"> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <StartWithIE>true</StartWithIE> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <StartWithIE>true</StartWithIE> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> + <StartWithIE>true</StartWithIE> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> + <StartWithIE>true</StartWithIE> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + <StartWithIE>true</StartWithIE> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + <StartWithIE>true</StartWithIE> + </PropertyGroup> + <PropertyGroup> + <PublishUrlHistory>publish\</PublishUrlHistory> + <InstallUrlHistory /> + <SupportUrlHistory /> + <UpdateUrlHistory /> + <BootstrapperUrlHistory /> + <ErrorReportUrlHistory /> + <FallbackCulture>en-US</FallbackCulture> + <VerifyUploadedFiles>false</VerifyUploadedFiles> + </PropertyGroup> +</Project> \ 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 +{ + /// <summary> + /// 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. + /// </summary> + + 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(); + + /// <summary> + /// Provides a central mechanism for exception handling. + /// Displays a message box that describes the exception. + /// </summary> + /// + /// <param name="moduleName"> the module where the exception occurred. </param> + /// <param name="e"> the exception </param> + + 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); + } + + /// <summary> + /// Remove any Input reports waiting in the buffer. + /// </summary> + /// <param name="hidHandle"> a handle to a device. </param> + /// <returns> + /// True on success, False on failure. + /// </returns> + + 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; + } + } + + /// <summary> + /// Get HID attributes. + /// </summary> + /// <param name="hidHandle"> HID handle retrieved with CreateFile </param> + /// <param name="deviceAttributes"> HID attributes structure </param> + /// <returns> true on success </returns> + + 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; + } + + /// <summary> + /// Retrieves a structure with information about a device's capabilities. + /// </summary> + /// + /// <param name="hidHandle"> a handle to a device. </param> + /// + /// <returns> + /// An HIDP_CAPS structure. + /// </returns> + + 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; + } + + /// <summary> + /// reads a Feature report from the device. + /// </summary> + /// + /// <param name="hidHandle"> the handle for learning about the device and exchanging Feature reports. </param> + /// <param name="inFeatureReportBuffer"> contains the requested report.</param> + + 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; + } + } + + /// <summary> + /// Get the HID-class GUID + /// </summary> + /// <returns> the GUID </returns> + + 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; + } + + /// <summary> + /// 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. + /// </summary> + /// + /// <param name="myCapabilities"> a HIDP_CAPS structure retrieved with HidP_GetCaps. </param> + /// + /// <returns> + /// A String describing the Usage. + /// </returns> + + 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; + } + + /// <summary> + /// reads an Input report from the device using a control transfer. + /// </summary> + /// <param name="hidHandle"> the handle for learning about the device and exchanging Feature reports. </param> + /// <param name="inputReportBuffer"> contains the requested report. </param> + + 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; + } + } + + /// <summary> + /// Reads an Input report from the device using an interrupt transfer. + /// </summary> + /// + /// <param name="deviceData"> the Filestream for writing data. </param> + /// <param name="inputReportBuffer"> contains the report ID and report data. </param> + /// <returns> + /// True on success. False on failure. + /// </returns> + + internal async Task<Int32> GetInputReportViaInterruptTransfer(FileStream deviceData, Byte[] inputReportBuffer, CancellationTokenSource cts) + { + try + { + Int32 bytesRead = 0; + + // Begin reading an Input report. + + Task<Int32> 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; + } + } + + /// <summary> + /// Retrieves the number of Input reports the HID driver will store. + /// </summary> + /// + /// <param name="hidDeviceObject"> a handle to a device </param> + /// <param name="numberOfInputBuffers"> an integer to hold the returned value. </param> + /// + /// <returns> + /// True on success, False on failure. + /// </returns> + + 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; + } + } + + /// <summary> + /// Timeout if read or write via interrupt transfer doesn't return. + /// </summary> + + internal void OnTimeout() + { + try + { + // No action required. + + Debug.Print("timeout"); + } + catch (Exception ex) + { + DisplayException(ModuleName, ex); + throw; + } + } + + /// <summary> + /// Attempts to open a handle to a HID. + /// </summary> + /// <param name="devicePathName"> device path name returned by SetupDiGetDeviceInterfaceDetail </param> + /// <param name="readAndWrite"> true if requesting read/write access for Input and Output reports </param> + /// <returns> hidHandle - a handle to the HID </returns> + + 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; + } + + /// <summary> + /// Writes a Feature report to the device. + /// </summary> + /// + /// <param name="outFeatureReportBuffer"> contains the report ID and report data. </param> + /// <param name="hidHandle"> handle to the device. </param> + /// + /// <returns> + /// True on success. False on failure. + /// </returns> + + 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; + } + } + + /// <summary> + /// Writes an Output report to the device using a control transfer. + /// </summary> + /// + /// <param name="outputReportBuffer"> contains the report ID and report data. </param> + /// <param name="hidHandle"> handle to the device. </param> + /// + /// <returns> + /// True on success. False on failure. + /// </returns> + + 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; + } + } + + /// <summary> + /// Writes an Output report to the device using an interrupt transfer. + /// </summary> + /// + /// <param name="fileStreamDeviceData"> the Filestream for writing data. </param> + /// <param name="hidHandle"> SafeFileHandle to the device. </param> + /// <param name="outputReportBuffer"> contains the report ID and report data. </param> + /// <param name="cts"> CancellationTokenSource </param> + /// + /// <returns> + /// 1 on success. 0 on failure. + /// </returns> + + internal async Task<Boolean> 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; + } + } + + /// <summary> + /// sets the number of input reports the host HID driver store. + /// </summary> + /// + /// <param name="hidDeviceObject"> a handle to the device.</param> + /// <param name="numberBuffers"> the requested number of input reports. </param> + /// + /// <returns> + /// True on success. False on failure. + /// </returns> + + 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 +{ + /// <summary> + /// API declarations for HID communications. + /// </summary> + 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 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// 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. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace GenericHid.Properties { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // 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() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [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; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [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 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1">this is my long string</data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + [base64 mime encoded serialized .NET Framework object] + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + [base64 mime encoded string representing a byte array form of the .NET Framework object] + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root> \ 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 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// 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. +// </auto-generated> +//------------------------------------------------------------------------------ + +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 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> +</SettingsFile> 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 @@ +<?xml version="1.0"?> +<configuration> +<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<asmv1:assembly xsi:schemaLocation="urn:schemas-microsoft-com:asm.v1 assembly.adaptive.xsd" manifestVersion="1.0" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns="urn:schemas-microsoft-com:asm.v2" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xrml="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:co.v1="urn:schemas-microsoft-com:clickonce.v1" xmlns:co.v2="urn:schemas-microsoft-com:clickonce.v2"> + <assemblyIdentity name="GenericHid.application" version="6.2.0.0" publicKeyToken="e912df4371957e61" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /> + <description asmv2:publisher="GenericHid" asmv2:product="GenericHid" xmlns="urn:schemas-microsoft-com:asm.v1" /> + <deployment install="true" mapFileExtensions="true" /> + <compatibleFrameworks xmlns="urn:schemas-microsoft-com:clickonce.v2"> + <framework targetVersion="4.5" profile="Full" supportedRuntime="4.0.30319" /> + </compatibleFrameworks> + <dependency> + <dependentAssembly dependencyType="install" codebase="Application Files\GenericHid_6_2_0_0\GenericHid.exe.manifest" size="7558"> + <assemblyIdentity name="GenericHid.exe" version="6.2.0.0" publicKeyToken="e912df4371957e61" language="neutral" processorArchitecture="msil" type="win32" /> + <hash> + <dsig:Transforms> + <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" /> + </dsig:Transforms> + <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /> + <dsig:DigestValue>oQgb8A8n+lzj+3t+OgYSWwxoRg2BjZwoA6qP23iuoq0=</dsig:DigestValue> + </hash> + </dependentAssembly> + </dependency> +<publisherIdentity name="CN=LVR2012\jan" issuerKeyHash="70f83b2370f422d4e3355b5c66f809cda26371c5" /><Signature Id="StrongNameSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>Lq11Sw3U1N8vRticxZzSjoQ6oqyNni1fUjnATzMnmvE=</DigestValue></Reference></SignedInfo><SignatureValue>RaX+F7wItRwo1xWOj5oNucSLJAEG+ZMa+gP92gUY2DeHBZJ3xl+8UYF/kuuSOf4DBNquvXRHyLXeegzkFttrqtO704gxqcIbXBcZi7w0PXZNmw+kN/8ykkWCShQiz8f3IYjqjQV199fxw3NAciCpWCLNSAMRYtVX6VyIEQCI6ns=</SignatureValue><KeyInfo Id="StrongNameKeyInfo"><KeyValue><RSAKeyValue><Modulus>vZK+hjF855eH6ywa/BZBvxkMJFFIIFjX0riqpVp0M088+99Ygevu3AGL1ajEdjQwry8w4ZXnz4jUfHSC2nhBKONyLrzV2dQH+RwonfAW8ExhueAb7u/pG77yb3T+kRbiHNPuRP8nlFTzm+riq/k1A1EqAK2n6MeVFUyk85S3xtU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><msrel:RelData xmlns:msrel="http://schemas.microsoft.com/windows/rel/2005/reldata"><r:license xmlns:r="urn:mpeg:mpeg21:2003:01-REL-R-NS" xmlns:as="http://schemas.microsoft.com/windows/pki/2005/Authenticode"><r:grant><as:ManifestInformation Hash="f19a27334fc039525f2d9e8daca23a848ed29cc59cd8462fdfd4d40d4b75ad2e" Description="" Url=""><as:assemblyIdentity name="GenericHid.application" version="6.2.0.0" publicKeyToken="e912df4371957e61" language="neutral" processorArchitecture="msil" xmlns="urn:schemas-microsoft-com:asm.v1" /></as:ManifestInformation><as:SignedBy /><as:AuthenticodePublisher><as:X509SubjectName>CN=LVR2012\jan</as:X509SubjectName></as:AuthenticodePublisher></r:grant><r:issuer><Signature Id="AuthenticodeSignature" xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" /><DigestValue>Nr/7DS53yGSNQxZA8cHgQphhjotTpOqFPw/G1Vh1qZI=</DigestValue></Reference></SignedInfo><SignatureValue>VEtiDTr4D9sGpmtS0wEej0Kmlx+zXyxZglD+CUVKbqW6YbPgfVbgZTRPtps+asBMqCusZUVUqtnwIvFJ89GwlKr+59nMUMlxiPuHFrnM8LJqWTMT05lJFO9P1h3t2U0pkCkbD+tFIpcLUxuVJmG+Lx9SH+nYnxY90QbhgAR43eg=</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>vZK+hjF855eH6ywa/BZBvxkMJFFIIFjX0riqpVp0M088+99Ygevu3AGL1ajEdjQwry8w4ZXnz4jUfHSC2nhBKONyLrzV2dQH+RwonfAW8ExhueAb7u/pG77yb3T+kRbiHNPuRP8nlFTzm+riq/k1A1EqAK2n6MeVFUyk85S3xtU=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue><X509Data><X509Certificate>MIIBxTCCAS6gAwIBAgIQG1z/tZx30LZKDzrL/KUXPjANBgkqhkiG9w0BAQsFADAhMR8wHQYDVQQDHhYATABWAFIAMgAwADEAMgBcAGoAYQBuMB4XDTEzMTAzMDAxMzYxNloXDTE0MTAzMDA3MzYxNlowITEfMB0GA1UEAx4WAEwAVgBSADIAMAAxADIAXABqAGEAbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvZK+hjF855eH6ywa/BZBvxkMJFFIIFjX0riqpVp0M088+99Ygevu3AGL1ajEdjQwry8w4ZXnz4jUfHSC2nhBKONyLrzV2dQH+RwonfAW8ExhueAb7u/pG77yb3T+kRbiHNPuRP8nlFTzm+riq/k1A1EqAK2n6MeVFUyk85S3xtUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQB5WjMIunQoSYZTqVnK1+emQt2+v/SzZc1oYY1G5ikE/t92Phyu0E9PgA6nXavF2IMrzOnmnNasTO9ygFQ+ck96TyD1FsQW9XRYxYdCn5oC+Caelwm5CPHRI2PKnw15IRDT9hHFj4AxYMSnN7uPXO+7eOjAbtRnynn0KAq+1PsFAA==</X509Certificate></X509Data></KeyInfo></Signature></r:issuer></r:license></msrel:RelData></KeyInfo></Signature></asmv1:assembly> \ 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 @@ + ///<summary> + /// 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. + /// + /// </summary>