sl@0: using Microsoft.Win32.SafeHandles;
sl@0: using System;
sl@0: using System.Diagnostics;
sl@0: using System.Globalization;
sl@0: using System.IO;
sl@0: using System.Management;
sl@0: using System.Runtime.InteropServices;
sl@0: using System.Threading;
sl@0: using System.Timers;
sl@0: using System.Windows.Forms;
sl@3: using System.Collections.Generic;
sl@3: using System.Drawing;
sl@5: using System.Text.RegularExpressions;
sl@0:
sl@0: namespace GenericHid
sl@0: {
sl@0: ///
sl@0: /// Project: GenericHid
sl@2: ///
sl@0: /// ***********************************************************************
sl@0: /// Software License Agreement
sl@0: ///
sl@2: /// Licensor grants any person obtaining a copy of this software ("You")
sl@2: /// a worldwide, royalty-free, non-exclusive license, for the duration of
sl@2: /// the copyright, free of charge, to store and execute the Software in a
sl@2: /// computer system and to incorporate the Software or any portion of it
sl@2: /// in computer programs You write.
sl@2: ///
sl@0: /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
sl@0: /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
sl@0: /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
sl@0: /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
sl@0: /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
sl@0: /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
sl@0: /// THE SOFTWARE.
sl@0: /// ***********************************************************************
sl@2: ///
sl@2: /// Author
sl@2: /// Jan Axelson
sl@2: ///
sl@0: /// This software was written using Visual Studio Express 2012 for Windows
sl@0: /// Desktop building for the .NET Framework v4.5.
sl@2: ///
sl@2: /// Purpose:
sl@0: /// Demonstrates USB communications with a generic HID-class device
sl@2: ///
sl@0: /// Requirements:
sl@0: /// Windows Vista or later and an attached USB generic Human Interface Device (HID).
sl@2: /// (Does not run on Windows XP or earlier because .NET Framework 4.5 will not install on these OSes.)
sl@2: ///
sl@0: /// Description:
sl@2: /// Finds an attached device that matches the vendor and product IDs in the form's
sl@0: /// text boxes.
sl@2: ///
sl@0: /// Retrieves the device's capabilities.
sl@0: /// Sends and requests HID reports.
sl@2: ///
sl@2: /// Uses the System.Management class and Windows Management Instrumentation (WMI) to detect
sl@0: /// when a device is attached or removed.
sl@2: ///
sl@0: /// A list box displays the data sent and received along with error and status messages.
sl@0: /// You can select data to send and 1-time or periodic transfers.
sl@2: ///
sl@0: /// You can change the size of the host's Input report buffer and request to use control
sl@0: /// transfers only to exchange Input and Output reports.
sl@2: ///
sl@0: /// To view additional debugging messages, in the Visual Studio development environment,
sl@2: /// from the main menu, select Build > Configuration Manager > Active Solution Configuration
sl@0: /// and select Configuration > Debug and from the main menu, select View > Output.
sl@2: ///
sl@2: /// The application uses asynchronous FileStreams to read Input reports and write Output
sl@2: /// reports so the application's main thread doesn't have to wait for the device to retrieve a
sl@2: /// report when the HID driver's buffer is empty or send a report when the device's endpoint is busy.
sl@2: ///
sl@0: /// For code that finds a device and opens handles to it, see the FindTheHid routine in frmMain.cs.
sl@2: /// For code that reads from the device, see GetInputReportViaInterruptTransfer,
sl@0: /// GetInputReportViaControlTransfer, and GetFeatureReport in Hid.cs.
sl@2: /// For code that writes to the device, see SendInputReportViaInterruptTransfer,
sl@0: /// SendInputReportViaControlTransfer, and SendFeatureReport in Hid.cs.
sl@2: ///
sl@0: /// This project includes the following modules:
sl@2: ///
sl@0: /// GenericHid.cs - runs the application.
sl@0: /// FrmMain.cs - routines specific to the form.
sl@0: /// Hid.cs - routines specific to HID communications.
sl@0: /// DeviceManagement.cs - routine for obtaining a handle to a device from its GUID.
sl@0: /// Debugging.cs - contains a routine for displaying API error messages.
sl@0: /// HidDeclarations.cs - Declarations for API functions used by Hid.cs.
sl@0: /// FileIODeclarations.cs - Declarations for file-related API functions.
sl@0: /// DeviceManagementDeclarations.cs - Declarations for API functions used by DeviceManagement.cs.
sl@0: /// DebuggingDeclarations.cs - Declarations for API functions used by Debugging.cs.
sl@2: ///
sl@0: /// Companion device firmware for several device CPUs is available from www.Lvr.com/hidpage.htm
sl@0: /// You can use any generic HID (not a system mouse or keyboard) that sends and receives reports.
sl@0: /// This application will not detect or communicate with non-HID-class devices.
sl@2: ///
sl@0: /// For more information about HIDs and USB, and additional example device firmware to use
sl@2: /// with this application, visit Lakeview Research at http://Lvr.com
sl@2: /// Send comments, bug reports, etc. to jan@Lvr.com or post on my PORTS forum: http://www.lvr.com/forum
sl@2: ///
sl@0: /// V6.2
sl@0: /// 11/12/13
sl@0: /// Disabled form buttons when a transfer is in progress.
sl@0: /// Other minor edits for clarity and readability.
sl@0: /// Will NOT run on Windows XP or earlier, see below.
sl@2: ///
sl@0: /// V6.1
sl@0: /// 10/28/13
sl@0: /// Uses the .NET System.Management class to detect device arrival and removal with WMI instead of Win32 RegisterDeviceNotification.
sl@0: /// Other minor edits.
sl@0: /// Will NOT run on Windows XP or earlier, see below.
sl@2: ///
sl@0: /// V6.0
sl@0: /// 2/8/13
sl@0: /// This version will NOT run on Windows XP or earlier because the code uses .NET Framework 4.5 to support asynchronous FileStreams.
sl@2: /// The .NET Framework 4.5 redistributable is compatible with Windows 8, Windows 7 SP1, Windows Server 2008 R2 SP1,
sl@0: /// Windows Server 2008 SP2, Windows Vista SP2, and Windows Vista SP3.
sl@0: /// For compatibility, replaced ToInt32 with ToInt64 here:
sl@0: /// IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
sl@0: /// and here:
sl@0: /// if ((deviceNotificationHandle.ToInt64() == IntPtr.Zero.ToInt64()))
sl@0: /// For compatibility if the charset isn't English, added System.Globalization.CultureInfo.InvariantCulture here:
sl@0: /// if ((String.Compare(DeviceNameString, mydevicePathName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))
sl@0: /// Replaced all Microsoft.VisualBasic namespace code with other .NET equivalents.
sl@0: /// Revised user interface for more flexibility.
sl@0: /// Moved interrupt-transfer and other HID-specific code to Hid.cs.
sl@0: /// Used JetBrains ReSharper to clean up the code: http://www.jetbrains.com/resharper/
sl@2: ///
sl@0: /// V5.0
sl@0: /// 3/30/11
sl@0: /// Replaced ReadFile and WriteFile with FileStreams. Thanks to Joe Dunne and John on my Ports forum for tips on this.
sl@0: /// Simplified Hid.cs.
sl@0: /// Replaced the form timer with a system timer.
sl@2: ///
sl@0: /// V4.6
sl@0: /// 1/12/10
sl@0: /// Supports Vendor IDs and Product IDs up to FFFFh.
sl@0: ///
sl@0: /// V4.52
sl@0: /// 11/10/09
sl@0: /// Changed HIDD_ATTRIBUTES to use UInt16
sl@2: ///
sl@0: /// V4.51
sl@0: /// 2/11/09
sl@0: /// Moved Free_ and similar to Finally blocks to ensure they execute.
sl@2: ///
sl@0: /// V4.5
sl@0: /// 2/9/09
sl@2: /// Changes to support 64-bit systems, memory management, and other corrections.
sl@0: /// Big thanks to Peter Nielsen.
sl@2: ///
sl@0: ///
sl@0:
sl@0: internal class FrmMain
sl@0: : Form
sl@0: {
sl@0: #region '"Windows Form Designer generated code "'
sl@0: public FrmMain()
sl@0: //: base()
sl@0: {
sl@0: // This call is required by the Windows Form Designer.
sl@0: InitializeComponent();
sl@0: }
sl@0: // Form overrides dispose to clean up the component list.
sl@0: protected override void Dispose(bool Disposing1)
sl@0: {
sl@0: if (Disposing1)
sl@0: {
sl@0: if (components != null)
sl@0: {
sl@0: components.Dispose();
sl@0: }
sl@0: }
sl@0: base.Dispose(Disposing1);
sl@0: }
sl@0:
sl@0: // Required by the Windows Form Designer
sl@0: private System.ComponentModel.IContainer components;
sl@0: public System.Windows.Forms.ToolTip ToolTip1;
sl@0: public System.Windows.Forms.TextBox TxtBytesReceived;
sl@0: public System.Windows.Forms.GroupBox FraBytesReceived;
sl@0: public System.Windows.Forms.CheckBox ChkAutoincrement;
sl@0: public System.Windows.Forms.ComboBox CboByte1;
sl@0: public System.Windows.Forms.ComboBox CboByte0;
sl@0: public System.Windows.Forms.GroupBox FraBytesToSend;
sl@0: public System.Windows.Forms.ListBox LstResults;
sl@0: // NOTE: The following procedure is required by the Windows Form Designer
sl@0: // It can be modified using the Windows Form Designer.
sl@2: // Do not modify it using the code editor.
sl@0: internal System.Windows.Forms.GroupBox fraInputReportBufferSize;
sl@0: internal System.Windows.Forms.TextBox txtInputReportBufferSize;
sl@0: internal System.Windows.Forms.Button cmdInputReportBufferSize;
sl@0: internal System.Windows.Forms.GroupBox fraDeviceIdentifiers;
sl@0: internal System.Windows.Forms.Label lblVendorID;
sl@0: internal System.Windows.Forms.TextBox txtVendorID;
sl@0: internal System.Windows.Forms.Label lblProductID;
sl@0: internal System.Windows.Forms.TextBox txtProductID;
sl@0: internal System.Windows.Forms.Button cmdFindDevice;
sl@0: private Button cmdGetInputReportInterrupt;
sl@0: public GroupBox fraInterruptTransfers;
sl@0: private Button cmdSendOutputReportControl;
sl@0: private Button cmdGetInputReportControl;
sl@0: public GroupBox fraControlTransfers;
sl@0: private Button cmdGetFeatureReport;
sl@0: private Button cmdSendFeatureReport;
sl@0: private Button cmdPeriodicTransfers;
sl@0: public GroupBox fraSendAndGetContinuous;
sl@0: private RadioButton radFeature;
sl@0: private RadioButton radInputOutputControl;
sl@0: private RadioButton radInputOutputInterrupt;
sl@3: private TreeView treeViewDevices;
sl@0: private Button cmdSendOutputReportInterrupt;
sl@0:
sl@0: [System.Diagnostics.DebuggerStepThrough()]
sl@0: private void InitializeComponent()
sl@0: {
sl@3: this.components = new System.ComponentModel.Container();
sl@3: this.ToolTip1 = new System.Windows.Forms.ToolTip(this.components);
sl@3: this.FraBytesReceived = new System.Windows.Forms.GroupBox();
sl@3: this.TxtBytesReceived = new System.Windows.Forms.TextBox();
sl@3: this.FraBytesToSend = new System.Windows.Forms.GroupBox();
sl@3: this.ChkAutoincrement = new System.Windows.Forms.CheckBox();
sl@3: this.CboByte1 = new System.Windows.Forms.ComboBox();
sl@3: this.CboByte0 = new System.Windows.Forms.ComboBox();
sl@3: this.LstResults = new System.Windows.Forms.ListBox();
sl@3: this.fraInputReportBufferSize = new System.Windows.Forms.GroupBox();
sl@3: this.cmdInputReportBufferSize = new System.Windows.Forms.Button();
sl@3: this.txtInputReportBufferSize = new System.Windows.Forms.TextBox();
sl@3: this.fraDeviceIdentifiers = new System.Windows.Forms.GroupBox();
sl@3: this.txtProductID = new System.Windows.Forms.TextBox();
sl@3: this.lblProductID = new System.Windows.Forms.Label();
sl@3: this.txtVendorID = new System.Windows.Forms.TextBox();
sl@3: this.lblVendorID = new System.Windows.Forms.Label();
sl@3: this.cmdFindDevice = new System.Windows.Forms.Button();
sl@3: this.cmdSendOutputReportInterrupt = new System.Windows.Forms.Button();
sl@3: this.cmdGetInputReportInterrupt = new System.Windows.Forms.Button();
sl@3: this.fraInterruptTransfers = new System.Windows.Forms.GroupBox();
sl@3: this.cmdPeriodicTransfers = new System.Windows.Forms.Button();
sl@3: this.cmdSendOutputReportControl = new System.Windows.Forms.Button();
sl@3: this.cmdGetInputReportControl = new System.Windows.Forms.Button();
sl@3: this.fraControlTransfers = new System.Windows.Forms.GroupBox();
sl@3: this.cmdGetFeatureReport = new System.Windows.Forms.Button();
sl@3: this.cmdSendFeatureReport = new System.Windows.Forms.Button();
sl@3: this.fraSendAndGetContinuous = new System.Windows.Forms.GroupBox();
sl@3: this.radFeature = new System.Windows.Forms.RadioButton();
sl@3: this.radInputOutputControl = new System.Windows.Forms.RadioButton();
sl@3: this.radInputOutputInterrupt = new System.Windows.Forms.RadioButton();
sl@3: this.treeViewDevices = new System.Windows.Forms.TreeView();
sl@3: this.FraBytesReceived.SuspendLayout();
sl@3: this.FraBytesToSend.SuspendLayout();
sl@3: this.fraInputReportBufferSize.SuspendLayout();
sl@3: this.fraDeviceIdentifiers.SuspendLayout();
sl@3: this.fraInterruptTransfers.SuspendLayout();
sl@3: this.fraControlTransfers.SuspendLayout();
sl@3: this.fraSendAndGetContinuous.SuspendLayout();
sl@3: this.SuspendLayout();
sl@3: //
sl@3: // FraBytesReceived
sl@3: //
sl@3: this.FraBytesReceived.BackColor = System.Drawing.SystemColors.Control;
sl@3: this.FraBytesReceived.Controls.Add(this.TxtBytesReceived);
sl@3: this.FraBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.FraBytesReceived.ForeColor = System.Drawing.SystemColors.ControlText;
sl@3: this.FraBytesReceived.Location = new System.Drawing.Point(495, 353);
sl@3: this.FraBytesReceived.Name = "FraBytesReceived";
sl@3: this.FraBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.FraBytesReceived.Size = new System.Drawing.Size(112, 136);
sl@3: this.FraBytesReceived.TabIndex = 4;
sl@3: this.FraBytesReceived.TabStop = false;
sl@3: this.FraBytesReceived.Text = "Bytes Received";
sl@3: //
sl@3: // TxtBytesReceived
sl@3: //
sl@3: this.TxtBytesReceived.AcceptsReturn = true;
sl@3: this.TxtBytesReceived.BackColor = System.Drawing.SystemColors.Window;
sl@3: this.TxtBytesReceived.Cursor = System.Windows.Forms.Cursors.IBeam;
sl@3: this.TxtBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.TxtBytesReceived.ForeColor = System.Drawing.SystemColors.WindowText;
sl@3: this.TxtBytesReceived.Location = new System.Drawing.Point(18, 24);
sl@3: this.TxtBytesReceived.MaxLength = 0;
sl@3: this.TxtBytesReceived.Multiline = true;
sl@3: this.TxtBytesReceived.Name = "TxtBytesReceived";
sl@3: this.TxtBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.TxtBytesReceived.Size = new System.Drawing.Size(72, 96);
sl@3: this.TxtBytesReceived.TabIndex = 5;
sl@3: //
sl@3: // FraBytesToSend
sl@3: //
sl@3: this.FraBytesToSend.BackColor = System.Drawing.SystemColors.Control;
sl@3: this.FraBytesToSend.Controls.Add(this.ChkAutoincrement);
sl@3: this.FraBytesToSend.Controls.Add(this.CboByte1);
sl@3: this.FraBytesToSend.Controls.Add(this.CboByte0);
sl@3: this.FraBytesToSend.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.FraBytesToSend.ForeColor = System.Drawing.SystemColors.ControlText;
sl@3: this.FraBytesToSend.Location = new System.Drawing.Point(612, 235);
sl@3: this.FraBytesToSend.Name = "FraBytesToSend";
sl@3: this.FraBytesToSend.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.FraBytesToSend.Size = new System.Drawing.Size(160, 136);
sl@3: this.FraBytesToSend.TabIndex = 1;
sl@3: this.FraBytesToSend.TabStop = false;
sl@3: this.FraBytesToSend.Text = "Bytes to Send";
sl@3: //
sl@3: // ChkAutoincrement
sl@3: //
sl@3: this.ChkAutoincrement.BackColor = System.Drawing.SystemColors.Control;
sl@3: this.ChkAutoincrement.Cursor = System.Windows.Forms.Cursors.Default;
sl@3: this.ChkAutoincrement.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.ChkAutoincrement.ForeColor = System.Drawing.SystemColors.ControlText;
sl@3: this.ChkAutoincrement.Location = new System.Drawing.Point(8, 96);
sl@3: this.ChkAutoincrement.Name = "ChkAutoincrement";
sl@3: this.ChkAutoincrement.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.ChkAutoincrement.Size = new System.Drawing.Size(201, 35);
sl@3: this.ChkAutoincrement.TabIndex = 6;
sl@3: this.ChkAutoincrement.Text = "Autoincrement values";
sl@3: this.ChkAutoincrement.UseVisualStyleBackColor = false;
sl@3: //
sl@3: // CboByte1
sl@3: //
sl@3: this.CboByte1.BackColor = System.Drawing.SystemColors.Window;
sl@3: this.CboByte1.Cursor = System.Windows.Forms.Cursors.Default;
sl@3: this.CboByte1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
sl@3: this.CboByte1.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.CboByte1.ForeColor = System.Drawing.SystemColors.WindowText;
sl@3: this.CboByte1.Location = new System.Drawing.Point(8, 64);
sl@3: this.CboByte1.Name = "CboByte1";
sl@3: this.CboByte1.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.CboByte1.Size = new System.Drawing.Size(101, 22);
sl@3: this.CboByte1.TabIndex = 3;
sl@3: //
sl@3: // CboByte0
sl@3: //
sl@3: this.CboByte0.BackColor = System.Drawing.SystemColors.Window;
sl@3: this.CboByte0.Cursor = System.Windows.Forms.Cursors.Default;
sl@3: this.CboByte0.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
sl@3: this.CboByte0.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.CboByte0.ForeColor = System.Drawing.SystemColors.WindowText;
sl@3: this.CboByte0.Location = new System.Drawing.Point(8, 24);
sl@3: this.CboByte0.Name = "CboByte0";
sl@3: this.CboByte0.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.CboByte0.Size = new System.Drawing.Size(101, 22);
sl@3: this.CboByte0.TabIndex = 2;
sl@3: //
sl@3: // LstResults
sl@3: //
sl@3: this.LstResults.BackColor = System.Drawing.SystemColors.Window;
sl@3: this.LstResults.Cursor = System.Windows.Forms.Cursors.Default;
sl@3: this.LstResults.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.LstResults.ForeColor = System.Drawing.SystemColors.WindowText;
sl@3: this.LstResults.HorizontalScrollbar = true;
sl@3: this.LstResults.ItemHeight = 14;
sl@3: this.LstResults.Location = new System.Drawing.Point(12, 494);
sl@3: this.LstResults.Name = "LstResults";
sl@3: this.LstResults.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.LstResults.Size = new System.Drawing.Size(760, 256);
sl@3: this.LstResults.TabIndex = 0;
sl@3: //
sl@3: // fraInputReportBufferSize
sl@3: //
sl@3: this.fraInputReportBufferSize.Controls.Add(this.cmdInputReportBufferSize);
sl@3: this.fraInputReportBufferSize.Controls.Add(this.txtInputReportBufferSize);
sl@3: this.fraInputReportBufferSize.Location = new System.Drawing.Point(623, 44);
sl@3: this.fraInputReportBufferSize.Name = "fraInputReportBufferSize";
sl@3: this.fraInputReportBufferSize.Size = new System.Drawing.Size(149, 79);
sl@3: this.fraInputReportBufferSize.TabIndex = 9;
sl@3: this.fraInputReportBufferSize.TabStop = false;
sl@3: this.fraInputReportBufferSize.Text = "Input Report Buffer Size";
sl@3: //
sl@3: // cmdInputReportBufferSize
sl@3: //
sl@3: this.cmdInputReportBufferSize.Location = new System.Drawing.Point(6, 47);
sl@3: this.cmdInputReportBufferSize.Name = "cmdInputReportBufferSize";
sl@3: this.cmdInputReportBufferSize.Size = new System.Drawing.Size(136, 26);
sl@3: this.cmdInputReportBufferSize.TabIndex = 1;
sl@3: this.cmdInputReportBufferSize.Text = "Change Buffer Size";
sl@3: this.cmdInputReportBufferSize.Click += new System.EventHandler(this.cmdInputReportBufferSize_Click);
sl@3: //
sl@3: // txtInputReportBufferSize
sl@3: //
sl@3: this.txtInputReportBufferSize.Location = new System.Drawing.Point(6, 21);
sl@3: this.txtInputReportBufferSize.Name = "txtInputReportBufferSize";
sl@3: this.txtInputReportBufferSize.Size = new System.Drawing.Size(56, 20);
sl@3: this.txtInputReportBufferSize.TabIndex = 0;
sl@3: //
sl@3: // fraDeviceIdentifiers
sl@3: //
sl@3: this.fraDeviceIdentifiers.Controls.Add(this.txtProductID);
sl@3: this.fraDeviceIdentifiers.Controls.Add(this.lblProductID);
sl@3: this.fraDeviceIdentifiers.Controls.Add(this.txtVendorID);
sl@3: this.fraDeviceIdentifiers.Controls.Add(this.lblVendorID);
sl@3: this.fraDeviceIdentifiers.Location = new System.Drawing.Point(409, 12);
sl@3: this.fraDeviceIdentifiers.Name = "fraDeviceIdentifiers";
sl@3: this.fraDeviceIdentifiers.Size = new System.Drawing.Size(208, 96);
sl@3: this.fraDeviceIdentifiers.TabIndex = 10;
sl@3: this.fraDeviceIdentifiers.TabStop = false;
sl@3: this.fraDeviceIdentifiers.Text = "Device Identifiers";
sl@3: //
sl@3: // txtProductID
sl@3: //
sl@3: this.txtProductID.Location = new System.Drawing.Point(120, 56);
sl@3: this.txtProductID.Name = "txtProductID";
sl@3: this.txtProductID.Size = new System.Drawing.Size(72, 20);
sl@3: this.txtProductID.TabIndex = 3;
sl@3: this.txtProductID.Text = "1299";
sl@3: this.txtProductID.TextChanged += new System.EventHandler(this.txtProductID_TextChanged);
sl@3: //
sl@3: // lblProductID
sl@3: //
sl@3: this.lblProductID.Location = new System.Drawing.Point(16, 56);
sl@3: this.lblProductID.Name = "lblProductID";
sl@3: this.lblProductID.Size = new System.Drawing.Size(112, 23);
sl@3: this.lblProductID.TabIndex = 2;
sl@3: this.lblProductID.Text = "Product ID (hex):";
sl@3: //
sl@3: // txtVendorID
sl@3: //
sl@3: this.txtVendorID.Location = new System.Drawing.Point(120, 24);
sl@3: this.txtVendorID.Name = "txtVendorID";
sl@3: this.txtVendorID.Size = new System.Drawing.Size(72, 20);
sl@3: this.txtVendorID.TabIndex = 1;
sl@3: this.txtVendorID.Text = "0925";
sl@3: this.txtVendorID.TextChanged += new System.EventHandler(this.txtVendorID_TextChanged);
sl@3: //
sl@3: // lblVendorID
sl@3: //
sl@3: this.lblVendorID.Location = new System.Drawing.Point(16, 24);
sl@3: this.lblVendorID.Name = "lblVendorID";
sl@3: this.lblVendorID.Size = new System.Drawing.Size(112, 23);
sl@3: this.lblVendorID.TabIndex = 0;
sl@3: this.lblVendorID.Text = "Vendor ID (hex):";
sl@3: //
sl@3: // cmdFindDevice
sl@3: //
sl@3: this.cmdFindDevice.Location = new System.Drawing.Point(636, 12);
sl@3: this.cmdFindDevice.Name = "cmdFindDevice";
sl@3: this.cmdFindDevice.Size = new System.Drawing.Size(136, 26);
sl@3: this.cmdFindDevice.TabIndex = 11;
sl@3: this.cmdFindDevice.Text = "Find My Device";
sl@3: this.cmdFindDevice.Click += new System.EventHandler(this.cmdFindDevice_Click);
sl@3: //
sl@3: // cmdSendOutputReportInterrupt
sl@3: //
sl@3: this.cmdSendOutputReportInterrupt.Location = new System.Drawing.Point(21, 27);
sl@3: this.cmdSendOutputReportInterrupt.Name = "cmdSendOutputReportInterrupt";
sl@3: this.cmdSendOutputReportInterrupt.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdSendOutputReportInterrupt.TabIndex = 12;
sl@3: this.cmdSendOutputReportInterrupt.Text = "Send Output Report";
sl@3: this.cmdSendOutputReportInterrupt.UseVisualStyleBackColor = true;
sl@3: this.cmdSendOutputReportInterrupt.Click += new System.EventHandler(this.cmdSendOutputReportInterrupt_Click);
sl@3: //
sl@3: // cmdGetInputReportInterrupt
sl@3: //
sl@3: this.cmdGetInputReportInterrupt.Location = new System.Drawing.Point(21, 60);
sl@3: this.cmdGetInputReportInterrupt.Name = "cmdGetInputReportInterrupt";
sl@3: this.cmdGetInputReportInterrupt.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdGetInputReportInterrupt.TabIndex = 13;
sl@3: this.cmdGetInputReportInterrupt.Text = "Get Input Report";
sl@3: this.cmdGetInputReportInterrupt.UseVisualStyleBackColor = true;
sl@3: this.cmdGetInputReportInterrupt.Click += new System.EventHandler(this.cmdGetInputReportInterrupt_Click);
sl@3: //
sl@3: // fraInterruptTransfers
sl@3: //
sl@3: this.fraInterruptTransfers.BackColor = System.Drawing.SystemColors.Control;
sl@3: this.fraInterruptTransfers.Controls.Add(this.cmdSendOutputReportInterrupt);
sl@3: this.fraInterruptTransfers.Controls.Add(this.cmdGetInputReportInterrupt);
sl@3: this.fraInterruptTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.fraInterruptTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
sl@3: this.fraInterruptTransfers.Location = new System.Drawing.Point(338, 129);
sl@3: this.fraInterruptTransfers.Name = "fraInterruptTransfers";
sl@3: this.fraInterruptTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.fraInterruptTransfers.Size = new System.Drawing.Size(151, 100);
sl@3: this.fraInterruptTransfers.TabIndex = 14;
sl@3: this.fraInterruptTransfers.TabStop = false;
sl@3: this.fraInterruptTransfers.Text = "Interrupt Transfers";
sl@3: //
sl@3: // cmdPeriodicTransfers
sl@3: //
sl@3: this.cmdPeriodicTransfers.Location = new System.Drawing.Point(153, 36);
sl@3: this.cmdPeriodicTransfers.Name = "cmdPeriodicTransfers";
sl@3: this.cmdPeriodicTransfers.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdPeriodicTransfers.TabIndex = 16;
sl@3: this.cmdPeriodicTransfers.Text = "Start";
sl@3: this.cmdPeriodicTransfers.UseVisualStyleBackColor = true;
sl@3: this.cmdPeriodicTransfers.Click += new System.EventHandler(this.cmdPeriodicTransfers_Click);
sl@3: //
sl@3: // cmdSendOutputReportControl
sl@3: //
sl@3: this.cmdSendOutputReportControl.Location = new System.Drawing.Point(10, 27);
sl@3: this.cmdSendOutputReportControl.Name = "cmdSendOutputReportControl";
sl@3: this.cmdSendOutputReportControl.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdSendOutputReportControl.TabIndex = 12;
sl@3: this.cmdSendOutputReportControl.Text = "Send Output Report";
sl@3: this.cmdSendOutputReportControl.UseVisualStyleBackColor = true;
sl@3: this.cmdSendOutputReportControl.Click += new System.EventHandler(this.cmdSendOutputReportControl_Click);
sl@3: //
sl@3: // cmdGetInputReportControl
sl@3: //
sl@3: this.cmdGetInputReportControl.Location = new System.Drawing.Point(10, 60);
sl@3: this.cmdGetInputReportControl.Name = "cmdGetInputReportControl";
sl@3: this.cmdGetInputReportControl.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdGetInputReportControl.TabIndex = 13;
sl@3: this.cmdGetInputReportControl.Text = "Get Input Report";
sl@3: this.cmdGetInputReportControl.UseVisualStyleBackColor = true;
sl@3: this.cmdGetInputReportControl.Click += new System.EventHandler(this.cmdGetInputReportControl_Click);
sl@3: //
sl@3: // fraControlTransfers
sl@3: //
sl@3: this.fraControlTransfers.BackColor = System.Drawing.SystemColors.Control;
sl@3: this.fraControlTransfers.Controls.Add(this.cmdGetFeatureReport);
sl@3: this.fraControlTransfers.Controls.Add(this.cmdSendFeatureReport);
sl@3: this.fraControlTransfers.Controls.Add(this.cmdSendOutputReportControl);
sl@3: this.fraControlTransfers.Controls.Add(this.cmdGetInputReportControl);
sl@3: this.fraControlTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.fraControlTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
sl@3: this.fraControlTransfers.Location = new System.Drawing.Point(495, 129);
sl@3: this.fraControlTransfers.Name = "fraControlTransfers";
sl@3: this.fraControlTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.fraControlTransfers.Size = new System.Drawing.Size(277, 100);
sl@3: this.fraControlTransfers.TabIndex = 15;
sl@3: this.fraControlTransfers.TabStop = false;
sl@3: this.fraControlTransfers.Text = "Control Transfers";
sl@3: //
sl@3: // cmdGetFeatureReport
sl@3: //
sl@3: this.cmdGetFeatureReport.Location = new System.Drawing.Point(141, 60);
sl@3: this.cmdGetFeatureReport.Name = "cmdGetFeatureReport";
sl@3: this.cmdGetFeatureReport.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdGetFeatureReport.TabIndex = 15;
sl@3: this.cmdGetFeatureReport.Text = "Get Feature Report";
sl@3: this.cmdGetFeatureReport.UseVisualStyleBackColor = true;
sl@3: this.cmdGetFeatureReport.Click += new System.EventHandler(this.cmdGetFeatureReport_Click);
sl@3: //
sl@3: // cmdSendFeatureReport
sl@3: //
sl@3: this.cmdSendFeatureReport.Location = new System.Drawing.Point(141, 27);
sl@3: this.cmdSendFeatureReport.Name = "cmdSendFeatureReport";
sl@3: this.cmdSendFeatureReport.Size = new System.Drawing.Size(118, 26);
sl@3: this.cmdSendFeatureReport.TabIndex = 14;
sl@3: this.cmdSendFeatureReport.Text = "Send Feature Report";
sl@3: this.cmdSendFeatureReport.UseVisualStyleBackColor = true;
sl@3: this.cmdSendFeatureReport.Click += new System.EventHandler(this.cmdSendFeatureReport_Click);
sl@3: //
sl@3: // fraSendAndGetContinuous
sl@3: //
sl@3: this.fraSendAndGetContinuous.BackColor = System.Drawing.SystemColors.Control;
sl@3: this.fraSendAndGetContinuous.Controls.Add(this.radFeature);
sl@3: this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputControl);
sl@3: this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputInterrupt);
sl@3: this.fraSendAndGetContinuous.Controls.Add(this.cmdPeriodicTransfers);
sl@3: this.fraSendAndGetContinuous.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.fraSendAndGetContinuous.ForeColor = System.Drawing.SystemColors.ControlText;
sl@3: this.fraSendAndGetContinuous.Location = new System.Drawing.Point(311, 235);
sl@3: this.fraSendAndGetContinuous.Name = "fraSendAndGetContinuous";
sl@3: this.fraSendAndGetContinuous.RightToLeft = System.Windows.Forms.RightToLeft.No;
sl@3: this.fraSendAndGetContinuous.Size = new System.Drawing.Size(295, 112);
sl@3: this.fraSendAndGetContinuous.TabIndex = 17;
sl@3: this.fraSendAndGetContinuous.TabStop = false;
sl@3: this.fraSendAndGetContinuous.Text = "Send and Get Continuous";
sl@3: //
sl@3: // radFeature
sl@3: //
sl@3: this.radFeature.AutoSize = true;
sl@3: this.radFeature.Location = new System.Drawing.Point(17, 76);
sl@3: this.radFeature.Name = "radFeature";
sl@3: this.radFeature.Size = new System.Drawing.Size(62, 18);
sl@3: this.radFeature.TabIndex = 19;
sl@3: this.radFeature.TabStop = true;
sl@3: this.radFeature.Text = "Feature";
sl@3: this.radFeature.UseVisualStyleBackColor = true;
sl@3: this.radFeature.CheckedChanged += new System.EventHandler(this.radFeature_CheckedChanged);
sl@3: //
sl@3: // radInputOutputControl
sl@3: //
sl@3: this.radInputOutputControl.AutoSize = true;
sl@3: this.radInputOutputControl.Location = new System.Drawing.Point(17, 52);
sl@3: this.radInputOutputControl.Name = "radInputOutputControl";
sl@3: this.radInputOutputControl.Size = new System.Drawing.Size(120, 18);
sl@3: this.radInputOutputControl.TabIndex = 18;
sl@3: this.radInputOutputControl.TabStop = true;
sl@3: this.radInputOutputControl.Text = "Input Output Control";
sl@3: this.radInputOutputControl.UseVisualStyleBackColor = true;
sl@3: this.radInputOutputControl.CheckedChanged += new System.EventHandler(this.radInputOutputControl_CheckedChanged);
sl@3: //
sl@3: // radInputOutputInterrupt
sl@3: //
sl@3: this.radInputOutputInterrupt.AutoSize = true;
sl@3: this.radInputOutputInterrupt.Location = new System.Drawing.Point(17, 28);
sl@3: this.radInputOutputInterrupt.Name = "radInputOutputInterrupt";
sl@3: this.radInputOutputInterrupt.Size = new System.Drawing.Size(126, 18);
sl@3: this.radInputOutputInterrupt.TabIndex = 17;
sl@3: this.radInputOutputInterrupt.TabStop = true;
sl@3: this.radInputOutputInterrupt.Text = "Input Output Interrupt";
sl@3: this.radInputOutputInterrupt.UseVisualStyleBackColor = true;
sl@3: this.radInputOutputInterrupt.CheckedChanged += new System.EventHandler(this.radInputOutputInterrupt_CheckedChanged);
sl@3: //
sl@3: // treeViewDevices
sl@3: //
sl@3: this.treeViewDevices.Location = new System.Drawing.Point(12, 12);
sl@3: this.treeViewDevices.Name = "treeViewDevices";
sl@3: this.treeViewDevices.Size = new System.Drawing.Size(284, 461);
sl@3: this.treeViewDevices.TabIndex = 18;
sl@5: this.treeViewDevices.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeViewDevices_AfterSelect);
sl@3: //
sl@3: // FrmMain
sl@3: //
sl@3: this.ClientSize = new System.Drawing.Size(784, 756);
sl@3: this.Controls.Add(this.treeViewDevices);
sl@3: this.Controls.Add(this.fraSendAndGetContinuous);
sl@3: this.Controls.Add(this.fraControlTransfers);
sl@3: this.Controls.Add(this.fraInterruptTransfers);
sl@3: this.Controls.Add(this.cmdFindDevice);
sl@3: this.Controls.Add(this.fraDeviceIdentifiers);
sl@3: this.Controls.Add(this.fraInputReportBufferSize);
sl@3: this.Controls.Add(this.FraBytesReceived);
sl@3: this.Controls.Add(this.FraBytesToSend);
sl@3: this.Controls.Add(this.LstResults);
sl@3: this.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
sl@3: this.Location = new System.Drawing.Point(21, 28);
sl@3: this.Name = "FrmMain";
sl@3: this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
sl@3: this.Text = "Generic HID Tester";
sl@3: this.Closed += new System.EventHandler(this.frmMain_Closed);
sl@3: this.Load += new System.EventHandler(this.frmMain_Load);
sl@3: this.FraBytesReceived.ResumeLayout(false);
sl@3: this.FraBytesReceived.PerformLayout();
sl@3: this.FraBytesToSend.ResumeLayout(false);
sl@3: this.fraInputReportBufferSize.ResumeLayout(false);
sl@3: this.fraInputReportBufferSize.PerformLayout();
sl@3: this.fraDeviceIdentifiers.ResumeLayout(false);
sl@3: this.fraDeviceIdentifiers.PerformLayout();
sl@3: this.fraInterruptTransfers.ResumeLayout(false);
sl@3: this.fraControlTransfers.ResumeLayout(false);
sl@3: this.fraSendAndGetContinuous.ResumeLayout(false);
sl@3: this.fraSendAndGetContinuous.PerformLayout();
sl@3: this.ResumeLayout(false);
sl@0:
sl@0: }
sl@2: #endregion '"Windows Form Designer generated code "'
sl@0:
sl@0: private Boolean _deviceDetected;
sl@0: private IntPtr _deviceNotificationHandle;
sl@0: private FileStream _deviceData;
sl@0: private FormActions _formActions;
sl@0: private SafeFileHandle _hidHandle;
sl@0: private String _hidUsage;
sl@0: private ManagementEventWatcher _deviceArrivedWatcher;
sl@0: private Boolean _deviceHandleObtained;
sl@0: private ManagementEventWatcher _deviceRemovedWatcher;
sl@0: private Int32 _myProductId;
sl@0: private Int32 _myVendorId;
sl@0: private Boolean _periodicTransfersRequested;
sl@0: private ReportReadOrWritten _readOrWritten;
sl@0: private ReportTypes _reportType;
sl@0: private SendOrGet _sendOrGet;
sl@0: private Boolean _transferInProgress;
sl@0: private TransferTypes _transferType;
sl@0:
sl@0: private static System.Timers.Timer _periodicTransfers;
sl@0:
sl@0: private readonly Debugging _myDebugging = new Debugging(); // For viewing results of API calls via Debug.Write.
sl@0: private readonly DeviceManagement _myDeviceManagement = new DeviceManagement();
sl@0: private Hid _myHid = new Hid();
sl@0:
sl@0: private enum FormActions
sl@0: {
sl@0: AddItemToListBox,
sl@0: DisableInputReportBufferSize,
sl@0: EnableGetInputReportInterruptTransfer,
sl@0: EnableInputReportBufferSize,
sl@0: EnableSendOutputReportInterrupt,
sl@0: ScrollToBottomOfListBox,
sl@3: SetInputReportBufferSize,
sl@3: AddDeviceToTreeView,
sl@3: ResetDeviceTreeView,
sl@4: SelectDeviceInTreeView,
sl@4: CompleteDeviceTreeView
sl@0: }
sl@0:
sl@0: private enum ReportReadOrWritten
sl@0: {
sl@0: Read,
sl@0: Written
sl@0: }
sl@0:
sl@0: private enum ReportTypes
sl@0: {
sl@0: Input,
sl@0: Output,
sl@0: Feature
sl@0: }
sl@0:
sl@0: private enum SendOrGet
sl@0: {
sl@0: Send,
sl@0: Get
sl@0: }
sl@0:
sl@0: private enum TransferTypes
sl@0: {
sl@0: Control,
sl@0: Interrupt
sl@0: }
sl@0:
sl@0: private enum WmiDeviceProperties
sl@0: {
sl@0: Name,
sl@0: Caption,
sl@0: Description,
sl@0: Manufacturer,
sl@0: PNPDeviceID,
sl@0: DeviceID,
sl@0: ClassGUID
sl@0: }
sl@0:
sl@0: internal FrmMain FrmMy;
sl@0:
sl@0: // This delegate has the same parameters as AccessForm.
sl@0: // Used in accessing the application's form from a different thread.
sl@0:
sl@3: private delegate void MarshalDataToForm(FormActions action, params string[] strings);
sl@0:
sl@0: ///
sl@0: /// Performs various application-specific functions that
sl@0: /// involve accessing the application's form.
sl@0: ///
sl@2: ///
sl@0: /// a FormActions member that names the action to perform on the form
sl@2: /// text that the form displays or the code uses for
sl@0: /// another purpose. Actions that don't use text ignore this parameter.
sl@0:
sl@3: private void AccessForm(FormActions action, params string[] strings)
sl@0: {
sl@0: try
sl@0: {
sl@0: // Select an action to perform on the form:
sl@0:
sl@0: switch (action)
sl@0: {
sl@0: case FormActions.AddItemToListBox:
sl@0:
sl@3: LstResults.Items.Add(strings[0]);
sl@0: break;
sl@0:
sl@0: case FormActions.DisableInputReportBufferSize:
sl@0:
sl@0: cmdInputReportBufferSize.Enabled = false;
sl@0: break;
sl@0:
sl@0: case FormActions.EnableGetInputReportInterruptTransfer:
sl@0:
sl@0: cmdGetInputReportInterrupt.Enabled = true;
sl@0: break;
sl@0:
sl@0: case FormActions.EnableInputReportBufferSize:
sl@0:
sl@0: cmdInputReportBufferSize.Enabled = true;
sl@0: break;
sl@0:
sl@0: case FormActions.EnableSendOutputReportInterrupt:
sl@0:
sl@0: cmdSendOutputReportInterrupt.Enabled = true;
sl@0: break;
sl@0:
sl@0: case FormActions.ScrollToBottomOfListBox:
sl@0:
sl@0: LstResults.SelectedIndex = LstResults.Items.Count - 1;
sl@0: break;
sl@0:
sl@0: case FormActions.SetInputReportBufferSize:
sl@0:
sl@3: txtInputReportBufferSize.Text = strings[0];
sl@0: break;
sl@3:
sl@3: case FormActions.AddDeviceToTreeView:
sl@3: {
sl@4: //Try and see if our device is already present
sl@4: TreeNode[] res = treeViewDevices.Nodes.Find(strings[0], false);
sl@4: foreach (TreeNode device in res)
sl@3: {
sl@4: if (device.ForeColor == Color.Red)
sl@4: {
sl@4: //Device was removed and has now been added back
sl@4: device.ForeColor = Color.Green;
sl@4: }
sl@4: else
sl@4: {
sl@4: //Device was already there set back our device color to black
sl@4: device.ForeColor = Color.Black;
sl@4: }
sl@3: }
sl@4:
sl@4: if (res.Length > 0)
sl@4: {
sl@4: //Our device is already there
sl@4: break;
sl@4: }
sl@4:
sl@4: //Build our node from our string array
sl@4: TreeNode newNode = new TreeNode(strings[0]);
sl@4: for (int i = 1; i < strings.Length; i++)
sl@4: {
sl@4: newNode.Nodes.Add(strings[i]);
sl@4: if (strings[i].StartsWith("Name: "))
sl@4: {
sl@4: //Found our name property, update our node text
sl@4: newNode.Text = strings[i].Substring(6, strings[i].Length - 6);
sl@4: }
sl@4: }
sl@4:
sl@4: //New device color is green
sl@4: newNode.ForeColor = Color.Green;
sl@4: newNode.Name = strings[0]; //Set ID as name to make sure we can find it
sl@4: treeViewDevices.Nodes.Add(newNode);
sl@3: }
sl@3: break;
sl@3:
sl@3: case FormActions.ResetDeviceTreeView:
sl@4: {
sl@4: //Mark all non removed/red device as purple/unknown
sl@4: foreach (TreeNode device in treeViewDevices.Nodes)
sl@4: {
sl@4: if (device.ForeColor != Color.Red)
sl@4: {
sl@4: device.ForeColor = Color.Purple;
sl@4: }
sl@4: }
sl@4: //treeViewDevices.Nodes.Clear();
sl@4: }
sl@4: break;
sl@4:
sl@4: case FormActions.CompleteDeviceTreeView:
sl@4: {
sl@4: //Our device list is now complete
sl@4: foreach (TreeNode device in treeViewDevices.Nodes)
sl@4: {
sl@4: //Purple devices need to be marked as red for removed
sl@4: if (device.ForeColor == Color.Purple)
sl@4: {
sl@4: device.ForeColor = Color.Red;
sl@4: }
sl@4: }
sl@4: }
sl@3: break;
sl@3:
sl@3: case FormActions.SelectDeviceInTreeView:
sl@3: {
sl@4: //treeViewDevices.SelectedNode = null;
sl@4: TreeNode[] res = treeViewDevices.Nodes.Find(strings[0], false);
sl@4: foreach (TreeNode device in res)
sl@4: {
sl@4: device.ForeColor = Color.Blue;
sl@4: //treeViewDevices.SelectedNode = res[0];
sl@4: //treeViewDevices.SelectedNode.ForeColor = Color.Blue;
sl@4: }
sl@3: }
sl@3:
sl@3:
sl@3: break;
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Add a handler to detect arrival of devices using WMI.
sl@0: ///
sl@0:
sl@0: private void AddDeviceArrivedHandler()
sl@0: {
sl@0: const Int32 pollingIntervalSeconds = 3;
sl@0: var scope = new ManagementScope("root\\CIMV2");
sl@0: scope.Options.EnablePrivileges = true;
sl@0:
sl@0: try
sl@0: {
sl@0: var q = new WqlEventQuery();
sl@0: q.EventClassName = "__InstanceCreationEvent";
sl@0: q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
sl@0: q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
sl@0: _deviceArrivedWatcher = new ManagementEventWatcher(scope, q);
sl@0: _deviceArrivedWatcher.EventArrived += DeviceAdded;
sl@0:
sl@0: _deviceArrivedWatcher.Start();
sl@0: }
sl@0: catch (Exception e)
sl@0: {
sl@0: Debug.WriteLine(e.Message);
sl@0: if (_deviceArrivedWatcher != null)
sl@0: _deviceArrivedWatcher.Stop();
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Add a handler to detect removal of devices using WMI.
sl@0: ///
sl@0:
sl@0: private void AddDeviceRemovedHandler()
sl@0: {
sl@0: const Int32 pollingIntervalSeconds = 3;
sl@0: var scope = new ManagementScope("root\\CIMV2");
sl@0: scope.Options.EnablePrivileges = true;
sl@0:
sl@0: try
sl@0: {
sl@0: var q = new WqlEventQuery();
sl@0: q.EventClassName = "__InstanceDeletionEvent";
sl@0: q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
sl@0: q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
sl@0: _deviceRemovedWatcher = new ManagementEventWatcher(scope, q);
sl@0: _deviceRemovedWatcher.EventArrived += DeviceRemoved;
sl@0: _deviceRemovedWatcher.Start();
sl@0: }
sl@0: catch (Exception e)
sl@0: {
sl@0: Debug.WriteLine(e.Message);
sl@0: if (_deviceRemovedWatcher != null)
sl@0: _deviceRemovedWatcher.Stop();
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Close the handle and FileStreams for a device.
sl@0: ///
sl@2: ///
sl@0: private void CloseCommunications()
sl@0: {
sl@0: if (_deviceData != null)
sl@0: {
sl@0: _deviceData.Close();
sl@0: }
sl@0:
sl@0: if ((_hidHandle != null) && (!(_hidHandle.IsInvalid)))
sl@0: {
sl@0: _hidHandle.Close();
sl@0: }
sl@0:
sl@0: // The next attempt to communicate will get a new handle and FileStreams.
sl@0:
sl@0: _deviceHandleObtained = false;
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Search for a specific device.
sl@0: ///
sl@0:
sl@0: private void cmdFindDevice_Click(Object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: _deviceDetected = FindDeviceUsingWmi();
sl@0: if (_deviceDetected)
sl@0: {
sl@0: FindTheHid();
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to get a Feature report from the device.
sl@0: ///
sl@0: ///
sl@0: ///
sl@0:
sl@0: private void cmdGetFeatureReport_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: // Don't allow another transfer request until this one completes.
sl@2: // Move the focus away from the button to prevent the focus from
sl@0: // switching to the next control in the tab order on disabling the button.
sl@0:
sl@0: fraControlTransfers.Focus();
sl@0: cmdGetFeatureReport.Enabled = false;
sl@0: _transferType = TransferTypes.Control;
sl@0: RequestToGetFeatureReport();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to get an Input report from the device using a control transfer.
sl@0: ///
sl@0: ///
sl@0: ///
sl@0:
sl@0: private void cmdGetInputReportControl_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: // Don't allow another transfer request until this one completes.
sl@2: // Move the focus away from the button to prevent the focus from
sl@0: // switching to the next control in the tab order on disabling the button.
sl@0:
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: fraControlTransfers.Focus();
sl@0: cmdGetInputReportControl.Enabled = false;
sl@0: _transferType = TransferTypes.Control;
sl@0: RequestToGetInputReport();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to get an Input report retrieved using interrupt transfers.
sl@0: ///
sl@0: ///
sl@0: ///
sl@2: ///
sl@0: private void cmdGetInputReportInterrupt_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: // Don't allow another transfer request until this one completes.
sl@2: // Move the focus away from the button to prevent the focus from
sl@0: // switching to the next control in the tab order on disabling the button.
sl@0:
sl@0: fraInterruptTransfers.Focus();
sl@0: cmdGetInputReportInterrupt.Enabled = false;
sl@0: _transferType = TransferTypes.Interrupt;
sl@0: RequestToGetInputReport();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Set the number of Input reports the HID driver will store.
sl@0: ///
sl@0:
sl@0: private void cmdInputReportBufferSize_Click(Object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: SetInputReportBufferSize();
sl@0: }
sl@0: }
sl@0: catch
sl@0: (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Alternate sending and getting a report.
sl@0: ///
sl@0: ///
sl@0: ///
sl@0:
sl@0: private void cmdPeriodicTransfers_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (cmdPeriodicTransfers.Text == "Start")
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: _sendOrGet = SendOrGet.Send;
sl@0: PeriodicTransfersStart();
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: PeriodicTransfersStop();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to send a Feature report using a control transfer.
sl@0: ///
sl@0: ///
sl@0: ///
sl@0:
sl@0: private void cmdSendFeatureReport_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: // Don't allow another transfer request until this one completes.
sl@2: // Move the focus away from the button to prevent the focus from
sl@0: // switching to the next control in the tab order on disabling the button.
sl@0:
sl@0: fraControlTransfers.Focus();
sl@0: cmdSendFeatureReport.Enabled = false;
sl@0: _transferType = TransferTypes.Control;
sl@0: RequestToSendFeatureReport();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to send an Output report using a control transfer.
sl@0: ///
sl@0: ///
sl@0: ///
sl@2: ///
sl@0: private void cmdSendOutputReportControl_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: // Don't allow another transfer request until this one completes.
sl@2: // Move the focus away from the button to prevent the focus from
sl@0: // switching to the next control in the tab order on disabling the button.
sl@0:
sl@0: fraControlTransfers.Focus();
sl@0: cmdSendOutputReportControl.Enabled = false;
sl@0: _transferType = TransferTypes.Control;
sl@0: RequestToSendOutputReport();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@2: /// Request to send an Output report using an interrupt transfer.
sl@0: ///
sl@0: ///
sl@0: ///
sl@0:
sl@0: private void cmdSendOutputReportInterrupt_Click(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_transferInProgress)
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: else
sl@0: {
sl@0: // Don't allow another transfer request until this one completes.
sl@2: // Move the focus away from the button to prevent the focus from
sl@0: // switching to the next control in the tab order on disabling the button.
sl@0:
sl@0: fraInterruptTransfers.Focus();
sl@0: cmdSendOutputReportInterrupt.Enabled = false;
sl@0: _transferType = TransferTypes.Interrupt;
sl@0: RequestToSendOutputReport();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Called on arrival of any device.
sl@0: /// Calls a routine that searches to see if the desired device is present.
sl@0: ///
sl@0:
sl@0: private void DeviceAdded(object sender, EventArrivedEventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: Debug.WriteLine("A USB device has been inserted");
sl@0:
sl@0: _deviceDetected = FindDeviceUsingWmi();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Called if the user changes the Vendor ID or Product ID in the text box.
sl@0: ///
sl@0:
sl@0: private void DeviceHasChanged()
sl@0: {
sl@0: try
sl@0: {
sl@0: // If a device was previously detected, stop receiving notifications about it.
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: DeviceNotificationsStop();
sl@0:
sl@0: CloseCommunications();
sl@0: }
sl@0: // Look for a device that matches the Vendor ID and Product ID in the text boxes.
sl@0:
sl@0: FindTheHid();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Add handlers to detect device arrival and removal.
sl@0: ///
sl@0:
sl@0: private void DeviceNotificationsStart()
sl@0: {
sl@0: AddDeviceArrivedHandler();
sl@0: AddDeviceRemovedHandler();
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Stop receiving notifications about device arrival and removal
sl@0: ///
sl@0:
sl@0: private void DeviceNotificationsStop()
sl@0: {
sl@0: try
sl@0: {
sl@0: if (_deviceArrivedWatcher != null)
sl@0: _deviceArrivedWatcher.Stop();
sl@0: if (_deviceRemovedWatcher != null)
sl@0: _deviceRemovedWatcher.Stop();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Called on removal of any device.
sl@0: /// Calls a routine that searches to see if the desired device is still present.
sl@0: ///
sl@2: ///
sl@0: private void DeviceRemoved(object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: Debug.WriteLine("A USB device has been removed");
sl@0:
sl@0: _deviceDetected = FindDeviceUsingWmi();
sl@0:
sl@0: if (!_deviceDetected)
sl@0: {
sl@0: _deviceHandleObtained = false;
sl@0: CloseCommunications();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Displays received or written report data.
sl@0: ///
sl@2: ///
sl@2: /// contains the report data.
sl@0: /// "Input", "Output", or "Feature"
sl@0: /// "read" for Input and IN Feature reports, "written" for Output and OUT Feature reports.
sl@0:
sl@0: private void DisplayReportData(Byte[] buffer, ReportTypes currentReportType, ReportReadOrWritten currentReadOrWritten)
sl@0: {
sl@0: try
sl@0: {
sl@0: Int32 count;
sl@0:
sl@0: LstResults.Items.Add(currentReportType.ToString() + " report has been " + currentReadOrWritten.ToString().ToLower() + ".");
sl@0:
sl@0: // Display the report data received in the form's list box.
sl@0:
sl@0: LstResults.Items.Add(" Report ID: " + String.Format("{0:X2} ", buffer[0]));
sl@0: LstResults.Items.Add(" Report Data:");
sl@0:
sl@0: TxtBytesReceived.Text = "";
sl@0:
sl@0: for (count = 1; count <= buffer.Length - 1; count++)
sl@0: {
sl@0: // Display bytes as 2-character Hex strings.
sl@0:
sl@0: String byteValue = String.Format("{0:X2} ", buffer[count]);
sl@0:
sl@0: LstResults.Items.Add(" " + byteValue);
sl@0:
sl@0: // Display the received bytes in the text box.
sl@0:
sl@0: TxtBytesReceived.SelectionStart = TxtBytesReceived.Text.Length;
sl@0: TxtBytesReceived.SelectedText = byteValue + Environment.NewLine;
sl@0: }
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Display a message if the user clicks a button when a transfer is in progress.
sl@0: ///
sl@2: ///
sl@0: private void DisplayTransferInProgressMessage()
sl@0: {
sl@0: AccessForm(FormActions.AddItemToListBox, "Command not executed because a transfer is in progress.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Do periodic transfers.
sl@0: ///
sl@0: ///
sl@0: ///
sl@0: ///
sl@0: /// The timer is enabled only if continuous (periodic) transfers have been requested.
sl@2: ///
sl@0:
sl@0: private void DoPeriodicTransfers(object source, ElapsedEventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: PeriodicTransfers();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Enable the command buttons on the form.
sl@0: /// Needed after attempting a transfer and device not found.
sl@0: ///
sl@2: ///
sl@0: private void EnableFormControls()
sl@0: {
sl@0: cmdGetInputReportInterrupt.Enabled = true;
sl@0: cmdSendOutputReportControl.Enabled = true;
sl@0: cmdGetInputReportControl.Enabled = true;
sl@0: cmdGetFeatureReport.Enabled = true;
sl@0: cmdSendFeatureReport.Enabled = true;
sl@0: cmdPeriodicTransfers.Enabled = true;
sl@0: cmdSendOutputReportInterrupt.Enabled = true;
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Use the System.Management class to find a device by Vendor ID and Product ID using WMI. If found, display device properties.
sl@0: ///
sl@2: ///
sl@0: /// During debugging, if you stop the firmware but leave the device attached, the device may still be detected as present
sl@2: /// but will be unable to communicate. The device will show up in Windows Device Manager as well.
sl@0: /// This situation is unlikely to occur with a final product.
sl@0: ///
sl@0:
sl@0: private Boolean FindDeviceUsingWmi()
sl@0: {
sl@0: try
sl@0: {
sl@3: MyMarshalDataToForm(FormActions.ResetDeviceTreeView);
sl@0: // Prepend "@" to string below to treat backslash as a normal character (not escape character):
sl@0:
sl@0: String deviceIdString = @"USB\VID_" + _myVendorId.ToString("X4") + "&PID_" + _myProductId.ToString("X4");
sl@0:
sl@0: _deviceDetected = false;
sl@0: var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity");
sl@2: int usbDeviceCounter = 0;
sl@0:
sl@0: foreach (ManagementObject queryObj in searcher.Get())
sl@0: {
sl@2: string deviceId = queryObj["PNPDeviceID"].ToString();
sl@2: if (deviceId.Contains(deviceIdString))
sl@2: {
sl@2: _deviceDetected = true;
sl@2: MyMarshalDataToForm(FormActions.AddItemToListBox, "My device found (WMI):");
sl@0:
sl@3: MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
sl@3: List device = new List();
sl@3: device.Add(deviceId);
sl@3: usbDeviceCounter++;
sl@2: // Display device properties.
sl@2: foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
sl@2: {
sl@2: MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
sl@3: device.Add((wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
sl@2: Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
sl@2: }
sl@2: MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
sl@2: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@3:
sl@3: MyMarshalDataToForm(FormActions.AddDeviceToTreeView, device.ToArray());
sl@3: MyMarshalDataToForm(FormActions.SelectDeviceInTreeView, deviceId);
sl@3:
sl@2: }
sl@3: else if (deviceId.StartsWith("USB\\VID"))
sl@2: {
sl@3: List device = new List();
sl@3: device.Add(deviceId);
sl@2: usbDeviceCounter++;
sl@3: // Add device properties.
sl@2: foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
sl@2: {
sl@3: device.Add((wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
sl@2: Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
sl@2: }
sl@3:
sl@3: MyMarshalDataToForm(FormActions.AddDeviceToTreeView, device.ToArray());
sl@2: }
sl@0: }
sl@2:
sl@4: //Complete our device TreeView
sl@4: MyMarshalDataToForm(FormActions.CompleteDeviceTreeView);
sl@4:
sl@4:
sl@2: MyMarshalDataToForm(FormActions.AddItemToListBox, "Found " + usbDeviceCounter /*searcher.Get().Count*/ + " USB HID devices");
sl@2:
sl@0: if (!_deviceDetected)
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "My device not found (WMI)");
sl@0: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@0: }
sl@0: return _deviceDetected;
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Call HID functions that use Win32 API functions to locate a HID-class device
sl@0: /// by its Vendor ID and Product ID. Open a handle to the device.
sl@0: ///
sl@2: ///
sl@0: ///
sl@0: /// True if the device is detected, False if not detected.
sl@0: ///
sl@0:
sl@0: private Boolean FindTheHid()
sl@0: {
sl@0: var devicePathName = new String[128];
sl@0: String myDevicePathName = "";
sl@0:
sl@0: try
sl@0: {
sl@0: _deviceHandleObtained = false;
sl@0: CloseCommunications();
sl@0:
sl@0: // Get the device's Vendor ID and Product ID from the form's text boxes.
sl@0:
sl@0: GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
sl@0:
sl@0: // Get the HID-class GUID.
sl@0:
sl@0: Guid hidGuid = _myHid.GetHidGuid();
sl@0:
sl@0: String functionName = "GetHidGuid";
sl@0: Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
sl@0: Debug.WriteLine(" GUID for system HIDs: " + hidGuid.ToString());
sl@0:
sl@0: // Fill an array with the device path names of all attached HIDs.
sl@0:
sl@0: Boolean availableHids = _myDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
sl@0:
sl@0: // If there is at least one HID, attempt to read the Vendor ID and Product ID
sl@0: // of each device until there is a match or all devices have been examined.
sl@0:
sl@0: if (availableHids)
sl@0: {
sl@0: Int32 memberIndex = 0;
sl@0:
sl@0: do
sl@0: {
sl@0: // Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice.
sl@0:
sl@0: _hidHandle = _myHid.OpenHandle(devicePathName[memberIndex], false);
sl@0:
sl@0: functionName = "CreateFile";
sl@0: Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
sl@0: Debug.WriteLine(" Returned handle: " + _hidHandle);
sl@0:
sl@0: if (!_hidHandle.IsInvalid)
sl@0: {
sl@2: // The returned handle is valid,
sl@0: // so find out if this is the device we're looking for.
sl@0:
sl@0: _myHid.DeviceAttributes.Size = Marshal.SizeOf(_myHid.DeviceAttributes);
sl@0:
sl@0: Boolean success = _myHid.GetAttributes(_hidHandle, ref _myHid.DeviceAttributes);
sl@0:
sl@0: if (success)
sl@0: {
sl@0: Debug.WriteLine(" HIDD_ATTRIBUTES structure filled without error.");
sl@0: Debug.WriteLine(" Structure size: " + _myHid.DeviceAttributes.Size);
sl@0: Debug.WriteLine(" Vendor ID: " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
sl@0: Debug.WriteLine(" Product ID: " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
sl@0: Debug.WriteLine(" Version Number: " + Convert.ToString(_myHid.DeviceAttributes.VersionNumber, 16));
sl@0:
sl@0: if ((_myHid.DeviceAttributes.VendorID == _myVendorId) && (_myHid.DeviceAttributes.ProductID == _myProductId))
sl@0: {
sl@0: Debug.WriteLine(" Handle obtained to my device");
sl@0:
sl@0: // Display the information in form's list box.
sl@0:
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "Handle obtained to my device:");
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, " Vendor ID= " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, " Product ID = " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
sl@0: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@0:
sl@0: _deviceHandleObtained = true;
sl@0:
sl@0: myDevicePathName = devicePathName[memberIndex];
sl@0: }
sl@0: else
sl@0: {
sl@0: // It's not a match, so close the handle.
sl@0:
sl@0: _deviceHandleObtained = false;
sl@0: _hidHandle.Close();
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: // There was a problem retrieving the information.
sl@0:
sl@0: Debug.WriteLine(" Error in filling HIDD_ATTRIBUTES structure.");
sl@0: _deviceHandleObtained = false;
sl@0: _hidHandle.Close();
sl@0: }
sl@0: }
sl@0:
sl@0: // Keep looking until we find the device or there are no devices left to examine.
sl@0:
sl@0: memberIndex = memberIndex + 1;
sl@0: }
sl@0: while (!((_deviceHandleObtained || (memberIndex == devicePathName.Length))));
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: // The device was detected.
sl@0: // Learn the capabilities of the device.
sl@0:
sl@0: _myHid.Capabilities = _myHid.GetDeviceCapabilities(_hidHandle);
sl@0:
sl@0: // Find out if the device is a system mouse or keyboard.
sl@0:
sl@0: _hidUsage = _myHid.GetHidUsage(_myHid.Capabilities);
sl@0:
sl@0: // Get the Input report buffer size.
sl@0:
sl@0: GetInputReportBufferSize();
sl@0: MyMarshalDataToForm(FormActions.EnableInputReportBufferSize, "");
sl@0:
sl@0: //Close the handle and reopen it with read/write access.
sl@0:
sl@0: _hidHandle.Close();
sl@0:
sl@0: _hidHandle = _myHid.OpenHandle(myDevicePathName, true);
sl@0:
sl@0: if (_hidHandle.IsInvalid)
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The device is a system " + _hidUsage + ".");
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 2000 and later obtain exclusive access to Input and Output reports for this devices.");
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 8 also obtains exclusive access to Feature reports.");
sl@0: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@0: }
sl@0: else
sl@0: {
sl@0: if (_myHid.Capabilities.InputReportByteLength > 0)
sl@0: {
sl@2: // Set the size of the Input report buffer.
sl@0:
sl@0: var inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
sl@0:
sl@0: _deviceData = new FileStream(_hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
sl@0: }
sl@0:
sl@0: if (_myHid.Capabilities.OutputReportByteLength > 0)
sl@0: {
sl@0: Byte[] outputReportBuffer = null;
sl@0: }
sl@0: // Flush any waiting reports in the input buffer. (optional)
sl@0:
sl@0: _myHid.FlushQueue(_hidHandle);
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "Device not found.");
sl@0: MyMarshalDataToForm(FormActions.DisableInputReportBufferSize, "");
sl@0: EnableFormControls();
sl@0: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@0: }
sl@0: return _deviceHandleObtained;
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Perform shutdown operations.
sl@0: ///
sl@0:
sl@0: private void frmMain_Closed(Object eventSender, EventArgs eventArgs)
sl@0: {
sl@0: try
sl@0: {
sl@0: Shutdown();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Perform startup operations.
sl@0: ///
sl@0:
sl@0: private void frmMain_Load(Object eventSender, EventArgs eventArgs)
sl@0: {
sl@0: try
sl@0: {
sl@0: FrmMy = this;
sl@0: Startup();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: private void GetBytesToSend()
sl@0: {
sl@0: try
sl@0: {
sl@0: // Get the bytes to send in a report from the combo boxes.
sl@0: // Increment the values if the autoincrement check box is selected.
sl@0:
sl@0: if (ChkAutoincrement.Checked)
sl@0: {
sl@0: if (CboByte0.SelectedIndex < 255)
sl@0: {
sl@0: CboByte0.SelectedIndex = CboByte0.SelectedIndex + 1;
sl@0: }
sl@0: else
sl@0: {
sl@0: CboByte0.SelectedIndex = 0;
sl@0: }
sl@0: if (CboByte1.SelectedIndex < 255)
sl@0: {
sl@0: CboByte1.SelectedIndex = CboByte1.SelectedIndex + 1;
sl@0: }
sl@0: else
sl@0: {
sl@0: CboByte1.SelectedIndex = 0;
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Find and display the number of Input buffers
sl@2: /// (the number of Input reports the HID driver will store).
sl@0: ///
sl@0:
sl@0: private void GetInputReportBufferSize()
sl@0: {
sl@0: Int32 numberOfInputBuffers = 0;
sl@0: Boolean success;
sl@0:
sl@0: try
sl@0: {
sl@0: // Get the number of input buffers.
sl@0:
sl@0: _myHid.GetNumberOfInputBuffers(_hidHandle, ref numberOfInputBuffers);
sl@0:
sl@0: // Display the result in the text box.
sl@0:
sl@0: MyMarshalDataToForm(FormActions.SetInputReportBufferSize, Convert.ToString(numberOfInputBuffers));
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@2: /// Retrieve a Vendor ID and Product ID in hexadecimal
sl@0: /// from the form's text boxes and convert the text to Int32s.
sl@0: ///
sl@2: ///
sl@0: /// the Vendor ID
sl@0: /// the Product ID
sl@0:
sl@0: private void GetVendorAndProductIDsFromTextBoxes(ref Int32 myVendorId, ref Int32 myProductId)
sl@0: {
sl@0: try
sl@0: {
sl@0: myVendorId = Int32.Parse(txtVendorID.Text, NumberStyles.AllowHexSpecifier);
sl@0: myProductId = Int32.Parse(txtProductID.Text, NumberStyles.AllowHexSpecifier);
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Initialize the elements on the form.
sl@0: ///
sl@0:
sl@0: private void InitializeDisplay()
sl@0: {
sl@0: try
sl@0: {
sl@0: // Create a dropdown list box for each byte to send in a report.
sl@0: // Display the values as 2-character hex strings.
sl@0:
sl@0: Int16 count;
sl@0: for (count = 0; count <= 255; count++)
sl@0: {
sl@0: String byteValue = String.Format("{0:X2} ", count);
sl@0: FrmMy.CboByte0.Items.Insert(count, byteValue);
sl@0: FrmMy.CboByte1.Items.Insert(count, byteValue);
sl@0: }
sl@0:
sl@0: // Select a default value for each box
sl@0:
sl@0: FrmMy.CboByte0.SelectedIndex = 0;
sl@0: FrmMy.CboByte1.SelectedIndex = 128;
sl@0: FrmMy.radInputOutputInterrupt.Checked = true;
sl@0:
sl@0: // Check the autoincrement box to increment the values each time a report is sent.
sl@0:
sl@0: ChkAutoincrement.CheckState = CheckState.Checked;
sl@0:
sl@0: // Don't allow the user to select an input report buffer size until there is
sl@0: // a handle to a HID.
sl@0:
sl@0: cmdInputReportBufferSize.Focus();
sl@0: cmdInputReportBufferSize.Enabled = false;
sl@0:
sl@0: LstResults.Items.Add("For a more detailed event log, view debug statements in Visual Studio's Output window:");
sl@0: LstResults.Items.Add("Click Build > Configuration Manager > Active Solution Configuration > Debug > Close.");
sl@0: LstResults.Items.Add("Then click View > Output.");
sl@0: LstResults.Items.Add("");
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@2: /// Enables accessing a form's controls from another thread
sl@0: ///
sl@2: ///
sl@0: /// a FormActions member that names the action to perform on the form
sl@2: /// text that the form displays or the code uses for
sl@0: /// another purpose. Actions that don't use text ignore this parameter.
sl@0:
sl@3: private void MyMarshalDataToForm(FormActions action, params string[] strings)
sl@0: {
sl@0: try
sl@0: {
sl@3: object[] args = { action, strings };
sl@0:
sl@0: // The AccessForm routine contains the code that accesses the form.
sl@0:
sl@0: MarshalDataToForm marshalDataToFormDelegate = AccessForm;
sl@0:
sl@0: // Execute AccessForm, passing the parameters in args.
sl@0:
sl@0: Invoke(marshalDataToFormDelegate, args);
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Timeout if read via interrupt transfer doesn't return.
sl@0: ///
sl@0:
sl@0: private void OnReadTimeout()
sl@0: {
sl@0: try
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a report timed out.");
sl@0: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@0: CloseCommunications();
sl@0: MyMarshalDataToForm(FormActions.EnableGetInputReportInterruptTransfer, "");
sl@0: _transferInProgress = false;
sl@0: _sendOrGet = SendOrGet.Send;
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Timeout if write via interrupt transfer doesn't return.
sl@0: ///
sl@0:
sl@0: private void OnWriteTimeout()
sl@0: {
sl@0: try
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to write a report timed out.");
sl@0: MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
sl@0: CloseCommunications();
sl@0: MyMarshalDataToForm(FormActions.EnableSendOutputReportInterrupt, "");
sl@0: _transferInProgress = false;
sl@0: _sendOrGet = SendOrGet.Get;
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Alternat sending and getting a report.
sl@0: ///
sl@0:
sl@0: private void PeriodicTransfers()
sl@0: {
sl@0: try
sl@0: {
sl@0: if (!_transferInProgress)
sl@0: {
sl@0: if (_reportType == ReportTypes.Feature)
sl@0: {
sl@0: SendOrGetFeatureReport();
sl@0: }
sl@0: else
sl@0: {
sl@0: // Output and Input reports
sl@0:
sl@0: SendOutputReportOrGetInputReport();
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Start doing periodic transfers.
sl@0: ///
sl@0:
sl@0: private void PeriodicTransfersStart()
sl@0: {
sl@0: // Don't allow changing the transfer type while transfers are in progress.
sl@0:
sl@0: if (radFeature.Checked)
sl@0: {
sl@0: radInputOutputControl.Enabled = false;
sl@0: radInputOutputInterrupt.Enabled = false;
sl@0: }
sl@0: else if (radInputOutputControl.Checked)
sl@0: {
sl@0: radFeature.Enabled = false;
sl@0: radInputOutputInterrupt.Enabled = false;
sl@0: }
sl@0: else if (radInputOutputInterrupt.Checked)
sl@0: {
sl@0: radFeature.Enabled = false;
sl@0: radInputOutputControl.Enabled = false;
sl@0: }
sl@0:
sl@0: // Change the command button's text.
sl@0:
sl@0: cmdPeriodicTransfers.Text = "Stop";
sl@0:
sl@0: // Enable the timer event to trigger a set of transfers.
sl@0:
sl@0: _periodicTransfers.Start();
sl@0:
sl@0: cmdPeriodicTransfers.Enabled = true;
sl@0:
sl@0: if (radInputOutputInterrupt.Checked)
sl@0: {
sl@0: _transferType = TransferTypes.Interrupt;
sl@0: _reportType = ReportTypes.Output;
sl@0: }
sl@0: else if (radInputOutputControl.Checked)
sl@0: {
sl@0: _transferType = TransferTypes.Control;
sl@0: _reportType = ReportTypes.Output;
sl@0: }
sl@0: else if (radFeature.Checked)
sl@0: {
sl@0: _transferType = TransferTypes.Control;
sl@0: _reportType = ReportTypes.Feature;
sl@0: }
sl@0: _periodicTransfersRequested = true;
sl@0: PeriodicTransfers();
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Stop doing periodic transfers.
sl@0: ///
sl@0:
sl@0: private void PeriodicTransfersStop()
sl@0: {
sl@0: // Stop doing continuous transfers.
sl@0:
sl@0: _periodicTransfersRequested = false;
sl@0:
sl@2: // Disable the timer that triggers the transfers.
sl@0:
sl@0: _periodicTransfers.Stop();
sl@0: cmdPeriodicTransfers.Enabled = true;
sl@0:
sl@0: // Change the command button's text.
sl@0:
sl@0: cmdPeriodicTransfers.Text = "Start";
sl@0:
sl@0: // Re-allow changing the transfer type.
sl@0:
sl@0: radFeature.Enabled = true;
sl@0: radInputOutputControl.Enabled = true;
sl@0: radInputOutputInterrupt.Enabled = true;
sl@0: }
sl@0:
sl@0: private void radInputOutputControl_CheckedChanged(object sender, EventArgs e)
sl@0: {
sl@0: }
sl@0:
sl@0: private void radInputOutputInterrupt_CheckedChanged(object sender, EventArgs e)
sl@0: {
sl@0: }
sl@0:
sl@0: private void radFeature_CheckedChanged(object sender, EventArgs e)
sl@0: {
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request a Feature report.
sl@0: /// Assumes report ID = 0.
sl@0: ///
sl@0:
sl@0: private void RequestToGetFeatureReport()
sl@0: {
sl@0: String byteValue = null;
sl@0:
sl@0: try
sl@0: {
sl@0: // If the device hasn't been detected, was removed, or timed out on a previous attempt
sl@0: // to access it, look for the device.
sl@0:
sl@0: if (!_deviceHandleObtained)
sl@0: {
sl@0: _deviceHandleObtained = FindTheHid();
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: Byte[] inFeatureReportBuffer = null;
sl@0:
sl@0: if ((_myHid.Capabilities.FeatureReportByteLength > 0))
sl@0: {
sl@2: // The HID has a Feature report.
sl@0: // Read a report from the device.
sl@0:
sl@2: // Set the size of the Feature report buffer.
sl@0:
sl@0: if ((_myHid.Capabilities.FeatureReportByteLength > 0))
sl@0: {
sl@0: inFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
sl@0: }
sl@0:
sl@0: // Read a report.
sl@0:
sl@0: Boolean success = _myHid.GetFeatureReport(_hidHandle, ref inFeatureReportBuffer);
sl@0:
sl@0: if (success)
sl@0: {
sl@0: DisplayReportData(inFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Read);
sl@0: }
sl@0: else
sl@0: {
sl@0: CloseCommunications();
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a Feature report failed.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0: }
sl@0: _transferInProgress = false;
sl@0: cmdGetFeatureReport.Enabled = true;
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request an Input report.
sl@0: /// Assumes report ID = 0.
sl@0: ///
sl@0:
sl@0: private async void RequestToGetInputReport()
sl@0: {
sl@0: const Int32 readTimeout = 5000;
sl@0:
sl@0: String byteValue = null;
sl@0: Byte[] inputReportBuffer = null;
sl@0:
sl@0: try
sl@0: {
sl@0: Boolean success = false;
sl@0:
sl@0: // If the device hasn't been detected, was removed, or timed out on a previous attempt
sl@0: // to access it, look for the device.
sl@0:
sl@0: if (!_deviceHandleObtained)
sl@0: {
sl@0: _deviceHandleObtained = FindTheHid();
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: // Don't attempt to exchange reports if valid handles aren't available
sl@0: // (as for a mouse or keyboard under Windows 2000 and later.)
sl@0:
sl@0: if (!_hidHandle.IsInvalid)
sl@0: {
sl@0: // Read an Input report.
sl@0:
sl@0: // Don't attempt to send an Input report if the HID has no Input report.
sl@0: // (The HID spec requires all HIDs to have an interrupt IN endpoint,
sl@0: // which suggests that all HIDs must support Input reports.)
sl@0:
sl@0: if (_myHid.Capabilities.InputReportByteLength > 0)
sl@0: {
sl@2: // Set the size of the Input report buffer.
sl@0:
sl@0: inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
sl@0:
sl@0: if (_transferType.Equals(TransferTypes.Control))
sl@0: {
sl@0: {
sl@0: _transferInProgress = true;
sl@0:
sl@0: // Read a report using a control transfer.
sl@0:
sl@0: success = _myHid.GetInputReportViaControlTransfer(_hidHandle, ref inputReportBuffer);
sl@0: cmdGetInputReportControl.Enabled = true;
sl@0: _transferInProgress = false;
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: {
sl@0: _transferInProgress = true;
sl@0:
sl@2: // Read a report using interrupt transfers.
sl@0: // Timeout if no report available.
sl@2: // To enable reading a report without blocking the calling thread, uses Filestream's ReadAsync method.
sl@0:
sl@0: // Create a delegate to execute on a timeout.
sl@0:
sl@0: Action onReadTimeoutAction = OnReadTimeout;
sl@0:
sl@0: // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
sl@0:
sl@0: var cts = new CancellationTokenSource();
sl@0:
sl@0: // Cancel the read if it hasn't completed after a timeout.
sl@0:
sl@0: cts.CancelAfter(readTimeout);
sl@0:
sl@0: // Specify the function to call on a timeout.
sl@0:
sl@0: cts.Token.Register(onReadTimeoutAction);
sl@0:
sl@0: // Stops waiting when data is available or on timeout:
sl@0:
sl@0: Int32 bytesRead = await _myHid.GetInputReportViaInterruptTransfer(_deviceData, inputReportBuffer, cts);
sl@0:
sl@0: // Arrive here only if the operation completed.
sl@0:
sl@2: // Dispose to stop the timeout timer.
sl@0:
sl@0: cts.Dispose();
sl@0:
sl@0: _transferInProgress = false;
sl@0: cmdGetInputReportInterrupt.Enabled = true;
sl@0:
sl@0: if (bytesRead > 0)
sl@0: {
sl@0: success = true;
sl@0: Debug.Print("bytes read (includes report ID) = " + Convert.ToString(bytesRead));
sl@0: }
sl@0: }
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "No attempt to read an Input report was made.");
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have an Input report.");
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "Invalid handle.");
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox,
sl@0: "No attempt to write an Output report or read an Input report was made.");
sl@0: }
sl@0:
sl@0: if (success)
sl@0: {
sl@0: DisplayReportData(inputReportBuffer, ReportTypes.Input, ReportReadOrWritten.Read);
sl@0: }
sl@0: else
sl@0: {
sl@0: CloseCommunications();
sl@0: MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read an Input report has failed.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Sends a Feature report.
sl@0: /// Assumes report ID = 0.
sl@0: ///
sl@0:
sl@0: private void RequestToSendFeatureReport()
sl@0: {
sl@0: String byteValue = null;
sl@0:
sl@0: try
sl@0: {
sl@0: _transferInProgress = true;
sl@0:
sl@0: // If the device hasn't been detected, was removed, or timed out on a previous attempt
sl@0: // to access it, look for the device.
sl@0:
sl@0: if (!_deviceHandleObtained)
sl@0: {
sl@0: _deviceHandleObtained = FindTheHid();
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: GetBytesToSend();
sl@0:
sl@0: if ((_myHid.Capabilities.FeatureReportByteLength > 0))
sl@0: {
sl@0: // The HID has a Feature report.
sl@2: // Set the size of the Feature report buffer.
sl@0:
sl@0: var outFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
sl@0:
sl@0: // Store the report ID in the buffer.
sl@0:
sl@0: outFeatureReportBuffer[0] = 0;
sl@0:
sl@0: // Store the report data following the report ID.
sl@0: // Use the data in the combo boxes on the form.
sl@0:
sl@0: outFeatureReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
sl@0:
sl@0: if (outFeatureReportBuffer.GetUpperBound(0) > 1)
sl@0: {
sl@0: outFeatureReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
sl@0: }
sl@0:
sl@0: // Write a report to the device
sl@0:
sl@0: Boolean success = _myHid.SendFeatureReport(_hidHandle, outFeatureReportBuffer);
sl@0:
sl@0: if (success)
sl@0: {
sl@0: DisplayReportData(outFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Written);
sl@0: }
sl@0: else
sl@0: {
sl@0: CloseCommunications();
sl@0: AccessForm(FormActions.AddItemToListBox, "The attempt to send a Feature report failed.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: AccessForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0:
sl@0: }
sl@0: _transferInProgress = false;
sl@0: cmdSendFeatureReport.Enabled = true;
sl@0: ScrollToBottomOfListBox();
sl@0:
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Sends an Output report.
sl@0: /// Assumes report ID = 0.
sl@0: ///
sl@0:
sl@0: private async void RequestToSendOutputReport()
sl@0: {
sl@0: const Int32 writeTimeout = 5000;
sl@0: String byteValue = null;
sl@0:
sl@0: try
sl@0: {
sl@0: // If the device hasn't been detected, was removed, or timed out on a previous attempt
sl@0: // to access it, look for the device.
sl@0:
sl@0: if (!_deviceHandleObtained)
sl@0: {
sl@0: _deviceHandleObtained = FindTheHid();
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: GetBytesToSend();
sl@0: }
sl@0: // Don't attempt to exchange reports if valid handles aren't available
sl@0: // (as for a mouse or keyboard.)
sl@0:
sl@0: if (!_hidHandle.IsInvalid)
sl@0: {
sl@0: // Don't attempt to send an Output report if the HID has no Output report.
sl@0:
sl@0: if (_myHid.Capabilities.OutputReportByteLength > 0)
sl@0: {
sl@2: // Set the size of the Output report buffer.
sl@0:
sl@0: var outputReportBuffer = new Byte[_myHid.Capabilities.OutputReportByteLength];
sl@0:
sl@0: // Store the report ID in the first byte of the buffer:
sl@0:
sl@0: outputReportBuffer[0] = 0;
sl@0:
sl@0: // Store the report data following the report ID.
sl@0: // Use the data in the combo boxes on the form.
sl@0:
sl@0: outputReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
sl@0:
sl@0: if (outputReportBuffer.GetUpperBound(0) > 1)
sl@0: {
sl@0: outputReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
sl@0: }
sl@0:
sl@0: // Write a report.
sl@0:
sl@0: Boolean success;
sl@0:
sl@0: if (_transferType.Equals(TransferTypes.Control))
sl@0: {
sl@0: {
sl@0: _transferInProgress = true;
sl@0:
sl@0: // Use a control transfer to send the report,
sl@0: // even if the HID has an interrupt OUT endpoint.
sl@0:
sl@0: success = _myHid.SendOutputReportViaControlTransfer(_hidHandle, outputReportBuffer);
sl@0:
sl@0: _transferInProgress = false;
sl@0: cmdSendOutputReportControl.Enabled = true;
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: Debug.Print("interrupt");
sl@0: _transferInProgress = true;
sl@0:
sl@0: // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
sl@0:
sl@0: var cts = new CancellationTokenSource();
sl@0:
sl@0: // Create a delegate to execute on a timeout.
sl@0:
sl@0: Action onWriteTimeoutAction = OnWriteTimeout;
sl@0:
sl@0: // Cancel the read if it hasn't completed after a timeout.
sl@0:
sl@0: cts.CancelAfter(writeTimeout);
sl@0:
sl@0: // Specify the function to call on a timeout.
sl@0:
sl@0: cts.Token.Register(onWriteTimeoutAction);
sl@0:
sl@0: // Send an Output report and wait for completion or timeout.
sl@0:
sl@0: success = await _myHid.SendOutputReportViaInterruptTransfer(_deviceData, _hidHandle, outputReportBuffer, cts);
sl@0:
sl@0: // Get here only if the operation completes without a timeout.
sl@0:
sl@0: _transferInProgress = false;
sl@0: cmdSendOutputReportInterrupt.Enabled = true;
sl@0:
sl@0: // Dispose to stop the timeout timer.
sl@0:
sl@0: cts.Dispose();
sl@0: }
sl@0: if (success)
sl@0: {
sl@0: DisplayReportData(outputReportBuffer, ReportTypes.Output, ReportReadOrWritten.Written);
sl@0: }
sl@0: else
sl@0: {
sl@0: CloseCommunications();
sl@0: AccessForm(FormActions.AddItemToListBox, "The attempt to write an Output report failed.");
sl@0: ScrollToBottomOfListBox();
sl@0: }
sl@0: }
sl@0: }
sl@0: else
sl@0: {
sl@0: AccessForm(FormActions.AddItemToListBox, "The HID doesn't have an Output report.");
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Scroll to the bottom of the list box and trim as needed.
sl@0: ///
sl@0:
sl@0: private void ScrollToBottomOfListBox()
sl@0: {
sl@0: try
sl@0: {
sl@0: LstResults.SelectedIndex = LstResults.Items.Count - 1;
sl@0:
sl@0: // If the list box is getting too large, trim its contents by removing the earliest data.
sl@0:
sl@0: if (LstResults.Items.Count > 1000)
sl@0: {
sl@0: Int32 count;
sl@0: for (count = 1; count <= 500; count++)
sl@0: {
sl@0: LstResults.Items.RemoveAt(4);
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to send or get a Feature report.
sl@0: ///
sl@0:
sl@0: private void SendOrGetFeatureReport()
sl@0: {
sl@0: try
sl@0: {
sl@0: // If the device hasn't been detected, was removed, or timed out on a previous attempt
sl@0: // to access it, look for the device.
sl@0:
sl@0: if (!_deviceHandleObtained)
sl@0: {
sl@0: _deviceHandleObtained = FindTheHid();
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: switch (_sendOrGet)
sl@0: {
sl@0: case SendOrGet.Send:
sl@0: RequestToSendFeatureReport();
sl@0: _sendOrGet = SendOrGet.Get;
sl@0: break;
sl@0: case SendOrGet.Get:
sl@0: RequestToGetFeatureReport();
sl@0: _sendOrGet = SendOrGet.Send;
sl@0: break;
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Request to send an Output report or get an Input report.
sl@0: ///
sl@0:
sl@0: private void SendOutputReportOrGetInputReport()
sl@0: {
sl@0: try
sl@0: {
sl@0: // If the device hasn't been detected, was removed, or timed out on a previous attempt
sl@0: // to access it, look for the device.
sl@0:
sl@0: if (!_deviceHandleObtained)
sl@0: {
sl@0: _deviceHandleObtained = FindTheHid();
sl@0: }
sl@0:
sl@0: if (_deviceHandleObtained)
sl@0: {
sl@0: if (_sendOrGet == SendOrGet.Send)
sl@0: {
sl@0: RequestToSendOutputReport();
sl@0: _sendOrGet = SendOrGet.Get;
sl@0: }
sl@0: else
sl@0: {
sl@0: RequestToGetInputReport();
sl@0: _sendOrGet = SendOrGet.Send;
sl@0: }
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@2: /// Set the number of Input buffers (the number of Input reports
sl@0: /// the host will store) from the value in the text box.
sl@0: ///
sl@0:
sl@0: private void SetInputReportBufferSize()
sl@0: {
sl@0: try
sl@0: {
sl@0: if (!_transferInProgress)
sl@0: {
sl@0: // Get the number of buffers from the text box.
sl@0:
sl@0: Int32 numberOfInputBuffers = Convert.ToInt32(txtInputReportBufferSize.Text);
sl@0:
sl@0: // Set the number of buffers.
sl@0:
sl@0: _myHid.SetNumberOfInputBuffers(_hidHandle, numberOfInputBuffers);
sl@0:
sl@0: // Verify and display the result.
sl@0:
sl@0: GetInputReportBufferSize();
sl@0: }
sl@0: else
sl@0: {
sl@0: DisplayTransferInProgressMessage();
sl@0: }
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Perform actions that must execute when the program ends.
sl@0: ///
sl@0:
sl@0: private void Shutdown()
sl@0: {
sl@0: try
sl@0: {
sl@0: CloseCommunications();
sl@0: DeviceNotificationsStop();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Perform actions that must execute when the program starts.
sl@0: ///
sl@0:
sl@0: private void Startup()
sl@0: {
sl@0: const Int32 periodicTransferInterval = 1000;
sl@0: try
sl@0: {
sl@0: _myHid = new Hid();
sl@0: InitializeDisplay();
sl@0:
sl@0: _periodicTransfers = new System.Timers.Timer(periodicTransferInterval);
sl@0: _periodicTransfers.Elapsed += DoPeriodicTransfers;
sl@0: _periodicTransfers.Stop();
sl@0: _periodicTransfers.SynchronizingObject = this;
sl@0:
sl@0: // Default USB Vendor ID and Product ID:
sl@0:
sl@0: txtVendorID.Text = "0925";
sl@0: txtProductID.Text = "7001";
sl@0:
sl@0: GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
sl@0:
sl@0: DeviceNotificationsStart();
sl@0: FindDeviceUsingWmi();
sl@0: FindTheHid();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// The Product ID has changed in the text box. Call a routine to handle it.
sl@0: ///
sl@0:
sl@0: private void txtProductID_TextChanged(Object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: DeviceHasChanged();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// The Vendor ID has changed in the text box. Call a routine to handle it.
sl@0: ///
sl@0:
sl@0: private void txtVendorID_TextChanged(Object sender, EventArgs e)
sl@0: {
sl@0: try
sl@0: {
sl@0: DeviceHasChanged();
sl@0: }
sl@0: catch (Exception ex)
sl@0: {
sl@0: DisplayException(Name, ex);
sl@0: throw;
sl@0: }
sl@0: }
sl@0:
sl@0: ///
sl@0: /// Provides a central mechanism for exception handling.
sl@0: /// Displays a message box that describes the exception.
sl@0: ///
sl@2: ///
sl@0: /// the module where the exception occurred.
sl@0: /// the exception
sl@0:
sl@0: internal static void DisplayException(String moduleName, Exception e)
sl@0: {
sl@0: // Create an error message.
sl@0:
sl@0: String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
sl@0:
sl@0: const String caption = "Unexpected Exception";
sl@0:
sl@0: MessageBox.Show(message, caption, MessageBoxButtons.OK);
sl@0: Debug.Write(message);
sl@0:
sl@2: // Get the last error and display it.
sl@0:
sl@0: Int32 error = Marshal.GetLastWin32Error();
sl@0:
sl@0: Debug.WriteLine("The last Win32 Error was: " + error);
sl@0: }
sl@0:
sl@0: [STAThread]
sl@0: internal static void Main() { Application.Run(new FrmMain()); }
sl@0: private static FrmMain _transDefaultFormFrmMain;
sl@0: internal static FrmMain TransDefaultFormFrmMain
sl@0: {
sl@0: get
sl@0: {
sl@0: if (_transDefaultFormFrmMain == null)
sl@0: {
sl@0: _transDefaultFormFrmMain = new FrmMain();
sl@0: }
sl@0: return _transDefaultFormFrmMain;
sl@0: }
sl@0: }
sl@5:
sl@5: private void treeViewDevices_AfterSelect(object sender, TreeViewEventArgs e)
sl@5: {
sl@5: //Node selected in our TreeView
sl@5: //Extract vendor and product IDs
sl@5: string deviceId = treeViewDevices.SelectedNode.Name;
sl@5: Regex regex = new Regex(@"VID_(....)&PID_(....).*");
sl@5: Match match = regex.Match(deviceId);
sl@5: if (match.Success)
sl@5: {
sl@5: //Take matches from each capturing group here. match.Groups[n].Value;
sl@5: //Put vendor and product ID in our text fields.
sl@5: txtVendorID.Text = match.Groups[1].Value;
sl@5: txtProductID.Text = match.Groups[2].Value;
sl@5: }
sl@5: }
sl@0: }
sl@0: }