FrmMain.cs
author sl
Wed, 14 May 2014 07:52:21 +0200
changeset 0 316364bd7d25
child 2 5f7e2c772e63
permissions -rw-r--r--
First drop from janaxelson.com
     1 using Microsoft.Win32.SafeHandles;
     2 using System;
     3 using System.Diagnostics;
     4 using System.Globalization;
     5 using System.IO;
     6 using System.Management;
     7 using System.Runtime.InteropServices;
     8 using System.Threading;
     9 using System.Timers;
    10 using System.Windows.Forms;
    11 
    12 namespace GenericHid
    13 {
    14 	///<summary>
    15 	/// Project: GenericHid
    16 	/// 
    17 	/// ***********************************************************************
    18 	/// Software License Agreement
    19 	///
    20 	/// Licensor grants any person obtaining a copy of this software ("You") 
    21 	/// a worldwide, royalty-free, non-exclusive license, for the duration of 
    22 	/// the copyright, free of charge, to store and execute the Software in a 
    23 	/// computer system and to incorporate the Software or any portion of it 
    24 	/// in computer programs You write.   
    25 	/// 
    26 	/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    27 	/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    28 	/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    29 	/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    30 	/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    31 	/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    32 	/// THE SOFTWARE.
    33 	/// ***********************************************************************
    34 	/// 
    35 	/// Author             
    36 	/// Jan Axelson        
    37 	/// 
    38 	/// This software was written using Visual Studio Express 2012 for Windows
    39 	/// Desktop building for the .NET Framework v4.5.
    40 	/// 
    41 	/// Purpose: 
    42 	/// Demonstrates USB communications with a generic HID-class device
    43 	/// 
    44 	/// Requirements:
    45 	/// Windows Vista or later and an attached USB generic Human Interface Device (HID).
    46 	/// (Does not run on Windows XP or earlier because .NET Framework 4.5 will not install on these OSes.) 
    47 	/// 
    48 	/// Description:
    49 	/// Finds an attached device that matches the vendor and product IDs in the form's 
    50 	/// text boxes.
    51 	/// 
    52 	/// Retrieves the device's capabilities.
    53 	/// Sends and requests HID reports.
    54 	/// 
    55 	/// Uses the System.Management class and Windows Management Instrumentation (WMI) to detect 
    56 	/// when a device is attached or removed.
    57 	/// 
    58 	/// A list box displays the data sent and received along with error and status messages.
    59 	/// You can select data to send and 1-time or periodic transfers.
    60 	/// 
    61 	/// You can change the size of the host's Input report buffer and request to use control
    62 	/// transfers only to exchange Input and Output reports.
    63 	/// 
    64 	/// To view additional debugging messages, in the Visual Studio development environment,
    65 	/// from the main menu, select Build > Configuration Manager > Active Solution Configuration 
    66 	/// and select Configuration > Debug and from the main menu, select View > Output.
    67 	/// 
    68 	/// The application uses asynchronous FileStreams to read Input reports and write Output 
    69 	/// reports so the application's main thread doesn't have to wait for the device to retrieve a 
    70 	/// report when the HID driver's buffer is empty or send a report when the device's endpoint is busy. 
    71 	/// 
    72 	/// For code that finds a device and opens handles to it, see the FindTheHid routine in frmMain.cs.
    73 	/// For code that reads from the device, see GetInputReportViaInterruptTransfer, 
    74 	/// GetInputReportViaControlTransfer, and GetFeatureReport in Hid.cs.
    75 	/// For code that writes to the device, see SendInputReportViaInterruptTransfer, 
    76 	/// SendInputReportViaControlTransfer, and SendFeatureReport in Hid.cs.
    77 	/// 
    78 	/// This project includes the following modules:
    79 	/// 
    80 	/// GenericHid.cs - runs the application.
    81 	/// FrmMain.cs - routines specific to the form.
    82 	/// Hid.cs - routines specific to HID communications.
    83 	/// DeviceManagement.cs - routine for obtaining a handle to a device from its GUID.
    84 	/// Debugging.cs - contains a routine for displaying API error messages.
    85 	/// HidDeclarations.cs - Declarations for API functions used by Hid.cs.
    86 	/// FileIODeclarations.cs - Declarations for file-related API functions.
    87 	/// DeviceManagementDeclarations.cs - Declarations for API functions used by DeviceManagement.cs.
    88 	/// DebuggingDeclarations.cs - Declarations for API functions used by Debugging.cs.
    89 	/// 
    90 	/// Companion device firmware for several device CPUs is available from www.Lvr.com/hidpage.htm
    91 	/// You can use any generic HID (not a system mouse or keyboard) that sends and receives reports.
    92 	/// This application will not detect or communicate with non-HID-class devices.
    93 	/// 
    94 	/// For more information about HIDs and USB, and additional example device firmware to use
    95 	/// with this application, visit Lakeview Research at http://Lvr.com 
    96 	/// Send comments, bug reports, etc. to jan@Lvr.com or post on my PORTS forum: http://www.lvr.com/forum 
    97 	/// 
    98 	/// V6.2
    99 	/// 11/12/13
   100 	/// Disabled form buttons when a transfer is in progress.
   101 	/// Other minor edits for clarity and readability.
   102 	/// Will NOT run on Windows XP or earlier, see below.
   103 	/// 
   104 	/// V6.1
   105 	/// 10/28/13
   106 	/// Uses the .NET System.Management class to detect device arrival and removal with WMI instead of Win32 RegisterDeviceNotification.
   107 	/// Other minor edits.
   108 	/// Will NOT run on Windows XP or earlier, see below.
   109 	///  
   110 	/// V6.0
   111 	/// 2/8/13
   112 	/// This version will NOT run on Windows XP or earlier because the code uses .NET Framework 4.5 to support asynchronous FileStreams.
   113 	/// The .NET Framework 4.5 redistributable is compatible with Windows 8, Windows 7 SP1, Windows Server 2008 R2 SP1, 
   114 	/// Windows Server 2008 SP2, Windows Vista SP2, and Windows Vista SP3.
   115 	/// For compatibility, replaced ToInt32 with ToInt64 here:
   116 	/// IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
   117 	/// and here:
   118 	/// if ((deviceNotificationHandle.ToInt64() == IntPtr.Zero.ToInt64()))
   119 	/// For compatibility if the charset isn't English, added System.Globalization.CultureInfo.InvariantCulture here:
   120 	/// if ((String.Compare(DeviceNameString, mydevicePathName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))
   121 	/// Replaced all Microsoft.VisualBasic namespace code with other .NET equivalents.
   122 	/// Revised user interface for more flexibility.
   123 	/// Moved interrupt-transfer and other HID-specific code to Hid.cs.
   124 	/// Used JetBrains ReSharper to clean up the code: http://www.jetbrains.com/resharper/
   125 	/// 
   126 	/// V5.0
   127 	/// 3/30/11
   128 	/// Replaced ReadFile and WriteFile with FileStreams. Thanks to Joe Dunne and John on my Ports forum for tips on this.
   129 	/// Simplified Hid.cs.
   130 	/// Replaced the form timer with a system timer.
   131 	/// 
   132 	/// V4.6
   133 	/// 1/12/10
   134 	/// Supports Vendor IDs and Product IDs up to FFFFh.
   135 	///
   136 	/// V4.52
   137 	/// 11/10/09
   138 	/// Changed HIDD_ATTRIBUTES to use UInt16
   139 	/// 
   140 	/// V4.51
   141 	/// 2/11/09
   142 	/// Moved Free_ and similar to Finally blocks to ensure they execute.
   143 	/// 
   144 	/// V4.5
   145 	/// 2/9/09
   146 	/// Changes to support 64-bit systems, memory management, and other corrections. 
   147 	/// Big thanks to Peter Nielsen.
   148 	///  
   149 	/// </summary>
   150 
   151 	internal class FrmMain
   152 		: Form
   153 	{
   154 		#region '"Windows Form Designer generated code "'
   155 		public FrmMain()
   156 		//: base()
   157 		{
   158 			// This call is required by the Windows Form Designer.
   159 			InitializeComponent();
   160 		}
   161 		// Form overrides dispose to clean up the component list.
   162 		protected override void Dispose(bool Disposing1)
   163 		{
   164 			if (Disposing1)
   165 			{
   166 				if (components != null)
   167 				{
   168 					components.Dispose();
   169 				}
   170 			}
   171 			base.Dispose(Disposing1);
   172 		}
   173 
   174 		// Required by the Windows Form Designer
   175 		private System.ComponentModel.IContainer components;
   176 		public System.Windows.Forms.ToolTip ToolTip1;
   177 		public System.Windows.Forms.TextBox TxtBytesReceived;
   178 		public System.Windows.Forms.GroupBox FraBytesReceived;
   179 		public System.Windows.Forms.CheckBox ChkAutoincrement;
   180 		public System.Windows.Forms.ComboBox CboByte1;
   181 		public System.Windows.Forms.ComboBox CboByte0;
   182 		public System.Windows.Forms.GroupBox FraBytesToSend;
   183 		public System.Windows.Forms.ListBox LstResults;
   184 		// NOTE: The following procedure is required by the Windows Form Designer
   185 		// It can be modified using the Windows Form Designer.
   186 		// Do not modify it using the code editor.   
   187 		internal System.Windows.Forms.GroupBox fraInputReportBufferSize;
   188 		internal System.Windows.Forms.TextBox txtInputReportBufferSize;
   189 		internal System.Windows.Forms.Button cmdInputReportBufferSize;
   190 		internal System.Windows.Forms.GroupBox fraDeviceIdentifiers;
   191 		internal System.Windows.Forms.Label lblVendorID;
   192 		internal System.Windows.Forms.TextBox txtVendorID;
   193 		internal System.Windows.Forms.Label lblProductID;
   194 		internal System.Windows.Forms.TextBox txtProductID;
   195 		internal System.Windows.Forms.Button cmdFindDevice;
   196 		private Button cmdGetInputReportInterrupt;
   197 		public GroupBox fraInterruptTransfers;
   198 		private Button cmdSendOutputReportControl;
   199 		private Button cmdGetInputReportControl;
   200 		public GroupBox fraControlTransfers;
   201 		private Button cmdGetFeatureReport;
   202 		private Button cmdSendFeatureReport;
   203 		private Button cmdPeriodicTransfers;
   204 		public GroupBox fraSendAndGetContinuous;
   205 		private RadioButton radFeature;
   206 		private RadioButton radInputOutputControl;
   207 		private RadioButton radInputOutputInterrupt;
   208 		private Button cmdSendOutputReportInterrupt;
   209 
   210 		[System.Diagnostics.DebuggerStepThrough()]
   211 		private void InitializeComponent()
   212 		{
   213 			this.components = new System.ComponentModel.Container();
   214 			this.ToolTip1 = new System.Windows.Forms.ToolTip(this.components);
   215 			this.FraBytesReceived = new System.Windows.Forms.GroupBox();
   216 			this.TxtBytesReceived = new System.Windows.Forms.TextBox();
   217 			this.FraBytesToSend = new System.Windows.Forms.GroupBox();
   218 			this.ChkAutoincrement = new System.Windows.Forms.CheckBox();
   219 			this.CboByte1 = new System.Windows.Forms.ComboBox();
   220 			this.CboByte0 = new System.Windows.Forms.ComboBox();
   221 			this.LstResults = new System.Windows.Forms.ListBox();
   222 			this.fraInputReportBufferSize = new System.Windows.Forms.GroupBox();
   223 			this.cmdInputReportBufferSize = new System.Windows.Forms.Button();
   224 			this.txtInputReportBufferSize = new System.Windows.Forms.TextBox();
   225 			this.fraDeviceIdentifiers = new System.Windows.Forms.GroupBox();
   226 			this.txtProductID = new System.Windows.Forms.TextBox();
   227 			this.lblProductID = new System.Windows.Forms.Label();
   228 			this.txtVendorID = new System.Windows.Forms.TextBox();
   229 			this.lblVendorID = new System.Windows.Forms.Label();
   230 			this.cmdFindDevice = new System.Windows.Forms.Button();
   231 			this.cmdSendOutputReportInterrupt = new System.Windows.Forms.Button();
   232 			this.cmdGetInputReportInterrupt = new System.Windows.Forms.Button();
   233 			this.fraInterruptTransfers = new System.Windows.Forms.GroupBox();
   234 			this.cmdPeriodicTransfers = new System.Windows.Forms.Button();
   235 			this.cmdSendOutputReportControl = new System.Windows.Forms.Button();
   236 			this.cmdGetInputReportControl = new System.Windows.Forms.Button();
   237 			this.fraControlTransfers = new System.Windows.Forms.GroupBox();
   238 			this.cmdGetFeatureReport = new System.Windows.Forms.Button();
   239 			this.cmdSendFeatureReport = new System.Windows.Forms.Button();
   240 			this.fraSendAndGetContinuous = new System.Windows.Forms.GroupBox();
   241 			this.radInputOutputInterrupt = new System.Windows.Forms.RadioButton();
   242 			this.radInputOutputControl = new System.Windows.Forms.RadioButton();
   243 			this.radFeature = new System.Windows.Forms.RadioButton();
   244 			this.FraBytesReceived.SuspendLayout();
   245 			this.FraBytesToSend.SuspendLayout();
   246 			this.fraInputReportBufferSize.SuspendLayout();
   247 			this.fraDeviceIdentifiers.SuspendLayout();
   248 			this.fraInterruptTransfers.SuspendLayout();
   249 			this.fraControlTransfers.SuspendLayout();
   250 			this.fraSendAndGetContinuous.SuspendLayout();
   251 			this.SuspendLayout();
   252 			// 
   253 			// fraBytesReceived
   254 			// 
   255 			this.FraBytesReceived.BackColor = System.Drawing.SystemColors.Control;
   256 			this.FraBytesReceived.Controls.Add(this.TxtBytesReceived);
   257 			this.FraBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   258 			this.FraBytesReceived.ForeColor = System.Drawing.SystemColors.ControlText;
   259 			this.FraBytesReceived.Location = new System.Drawing.Point(16, 272);
   260 			this.FraBytesReceived.Name = "FraBytesReceived";
   261 			this.FraBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
   262 			this.FraBytesReceived.Size = new System.Drawing.Size(112, 136);
   263 			this.FraBytesReceived.TabIndex = 4;
   264 			this.FraBytesReceived.TabStop = false;
   265 			this.FraBytesReceived.Text = "Bytes Received";
   266 			// 
   267 			// txtBytesReceived
   268 			// 
   269 			this.TxtBytesReceived.AcceptsReturn = true;
   270 			this.TxtBytesReceived.BackColor = System.Drawing.SystemColors.Window;
   271 			this.TxtBytesReceived.Cursor = System.Windows.Forms.Cursors.IBeam;
   272 			this.TxtBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   273 			this.TxtBytesReceived.ForeColor = System.Drawing.SystemColors.WindowText;
   274 			this.TxtBytesReceived.Location = new System.Drawing.Point(18, 24);
   275 			this.TxtBytesReceived.MaxLength = 0;
   276 			this.TxtBytesReceived.Multiline = true;
   277 			this.TxtBytesReceived.Name = "TxtBytesReceived";
   278 			this.TxtBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
   279 			this.TxtBytesReceived.Size = new System.Drawing.Size(72, 96);
   280 			this.TxtBytesReceived.TabIndex = 5;
   281 			// 
   282 			// fraBytesToSend
   283 			// 
   284 			this.FraBytesToSend.BackColor = System.Drawing.SystemColors.Control;
   285 			this.FraBytesToSend.Controls.Add(this.ChkAutoincrement);
   286 			this.FraBytesToSend.Controls.Add(this.CboByte1);
   287 			this.FraBytesToSend.Controls.Add(this.CboByte0);
   288 			this.FraBytesToSend.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   289 			this.FraBytesToSend.ForeColor = System.Drawing.SystemColors.ControlText;
   290 			this.FraBytesToSend.Location = new System.Drawing.Point(16, 128);
   291 			this.FraBytesToSend.Name = "FraBytesToSend";
   292 			this.FraBytesToSend.RightToLeft = System.Windows.Forms.RightToLeft.No;
   293 			this.FraBytesToSend.Size = new System.Drawing.Size(160, 136);
   294 			this.FraBytesToSend.TabIndex = 1;
   295 			this.FraBytesToSend.TabStop = false;
   296 			this.FraBytesToSend.Text = "Bytes to Send";
   297 			// 
   298 			// chkAutoincrement
   299 			// 
   300 			this.ChkAutoincrement.BackColor = System.Drawing.SystemColors.Control;
   301 			this.ChkAutoincrement.Cursor = System.Windows.Forms.Cursors.Default;
   302 			this.ChkAutoincrement.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   303 			this.ChkAutoincrement.ForeColor = System.Drawing.SystemColors.ControlText;
   304 			this.ChkAutoincrement.Location = new System.Drawing.Point(8, 96);
   305 			this.ChkAutoincrement.Name = "ChkAutoincrement";
   306 			this.ChkAutoincrement.RightToLeft = System.Windows.Forms.RightToLeft.No;
   307 			this.ChkAutoincrement.Size = new System.Drawing.Size(201, 35);
   308 			this.ChkAutoincrement.TabIndex = 6;
   309 			this.ChkAutoincrement.Text = "Autoincrement values";
   310 			this.ChkAutoincrement.UseVisualStyleBackColor = false;
   311 			// 
   312 			// cboByte1
   313 			// 
   314 			this.CboByte1.BackColor = System.Drawing.SystemColors.Window;
   315 			this.CboByte1.Cursor = System.Windows.Forms.Cursors.Default;
   316 			this.CboByte1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
   317 			this.CboByte1.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   318 			this.CboByte1.ForeColor = System.Drawing.SystemColors.WindowText;
   319 			this.CboByte1.Location = new System.Drawing.Point(8, 64);
   320 			this.CboByte1.Name = "CboByte1";
   321 			this.CboByte1.RightToLeft = System.Windows.Forms.RightToLeft.No;
   322 			this.CboByte1.Size = new System.Drawing.Size(101, 22);
   323 			this.CboByte1.TabIndex = 3;
   324 			// 
   325 			// cboByte0
   326 			// 
   327 			this.CboByte0.BackColor = System.Drawing.SystemColors.Window;
   328 			this.CboByte0.Cursor = System.Windows.Forms.Cursors.Default;
   329 			this.CboByte0.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
   330 			this.CboByte0.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   331 			this.CboByte0.ForeColor = System.Drawing.SystemColors.WindowText;
   332 			this.CboByte0.Location = new System.Drawing.Point(8, 24);
   333 			this.CboByte0.Name = "CboByte0";
   334 			this.CboByte0.RightToLeft = System.Windows.Forms.RightToLeft.No;
   335 			this.CboByte0.Size = new System.Drawing.Size(101, 22);
   336 			this.CboByte0.TabIndex = 2;
   337 			// 
   338 			// lstResults
   339 			// 
   340 			this.LstResults.BackColor = System.Drawing.SystemColors.Window;
   341 			this.LstResults.Cursor = System.Windows.Forms.Cursors.Default;
   342 			this.LstResults.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   343 			this.LstResults.ForeColor = System.Drawing.SystemColors.WindowText;
   344 			this.LstResults.HorizontalScrollbar = true;
   345 			this.LstResults.ItemHeight = 14;
   346 			this.LstResults.Location = new System.Drawing.Point(12, 424);
   347 			this.LstResults.Name = "LstResults";
   348 			this.LstResults.RightToLeft = System.Windows.Forms.RightToLeft.No;
   349 			this.LstResults.Size = new System.Drawing.Size(760, 326);
   350 			this.LstResults.TabIndex = 0;
   351 			// 
   352 			// fraInputReportBufferSize
   353 			// 
   354 			this.fraInputReportBufferSize.Controls.Add(this.cmdInputReportBufferSize);
   355 			this.fraInputReportBufferSize.Controls.Add(this.txtInputReportBufferSize);
   356 			this.fraInputReportBufferSize.Location = new System.Drawing.Point(248, 16);
   357 			this.fraInputReportBufferSize.Name = "fraInputReportBufferSize";
   358 			this.fraInputReportBufferSize.Size = new System.Drawing.Size(208, 96);
   359 			this.fraInputReportBufferSize.TabIndex = 9;
   360 			this.fraInputReportBufferSize.TabStop = false;
   361 			this.fraInputReportBufferSize.Text = "Input Report Buffer Size";
   362 			// 
   363 			// cmdInputReportBufferSize
   364 			// 
   365 			this.cmdInputReportBufferSize.Location = new System.Drawing.Point(96, 32);
   366 			this.cmdInputReportBufferSize.Name = "cmdInputReportBufferSize";
   367 			this.cmdInputReportBufferSize.Size = new System.Drawing.Size(96, 56);
   368 			this.cmdInputReportBufferSize.TabIndex = 1;
   369 			this.cmdInputReportBufferSize.Text = "Change Buffer Size";
   370 			this.cmdInputReportBufferSize.Click += new System.EventHandler(this.cmdInputReportBufferSize_Click);
   371 			// 
   372 			// txtInputReportBufferSize
   373 			// 
   374 			this.txtInputReportBufferSize.Location = new System.Drawing.Point(16, 40);
   375 			this.txtInputReportBufferSize.Name = "txtInputReportBufferSize";
   376 			this.txtInputReportBufferSize.Size = new System.Drawing.Size(56, 20);
   377 			this.txtInputReportBufferSize.TabIndex = 0;
   378 			// 
   379 			// fraDeviceIdentifiers
   380 			// 
   381 			this.fraDeviceIdentifiers.Controls.Add(this.txtProductID);
   382 			this.fraDeviceIdentifiers.Controls.Add(this.lblProductID);
   383 			this.fraDeviceIdentifiers.Controls.Add(this.txtVendorID);
   384 			this.fraDeviceIdentifiers.Controls.Add(this.lblVendorID);
   385 			this.fraDeviceIdentifiers.Location = new System.Drawing.Point(16, 16);
   386 			this.fraDeviceIdentifiers.Name = "fraDeviceIdentifiers";
   387 			this.fraDeviceIdentifiers.Size = new System.Drawing.Size(208, 96);
   388 			this.fraDeviceIdentifiers.TabIndex = 10;
   389 			this.fraDeviceIdentifiers.TabStop = false;
   390 			this.fraDeviceIdentifiers.Text = "Device Identifiers";
   391 			// 
   392 			// txtProductID
   393 			// 
   394 			this.txtProductID.Location = new System.Drawing.Point(120, 56);
   395 			this.txtProductID.Name = "txtProductID";
   396 			this.txtProductID.Size = new System.Drawing.Size(72, 20);
   397 			this.txtProductID.TabIndex = 3;
   398 			this.txtProductID.Text = "1299";
   399 			this.txtProductID.TextChanged += new System.EventHandler(this.txtProductID_TextChanged);
   400 			// 
   401 			// lblProductID
   402 			// 
   403 			this.lblProductID.Location = new System.Drawing.Point(16, 56);
   404 			this.lblProductID.Name = "lblProductID";
   405 			this.lblProductID.Size = new System.Drawing.Size(112, 23);
   406 			this.lblProductID.TabIndex = 2;
   407 			this.lblProductID.Text = "Product ID (hex):";
   408 			// 
   409 			// txtVendorID
   410 			// 
   411 			this.txtVendorID.Location = new System.Drawing.Point(120, 24);
   412 			this.txtVendorID.Name = "txtVendorID";
   413 			this.txtVendorID.Size = new System.Drawing.Size(72, 20);
   414 			this.txtVendorID.TabIndex = 1;
   415 			this.txtVendorID.Text = "0925";
   416 			this.txtVendorID.TextChanged += new System.EventHandler(this.txtVendorID_TextChanged);
   417 			// 
   418 			// lblVendorID
   419 			// 
   420 			this.lblVendorID.Location = new System.Drawing.Point(16, 24);
   421 			this.lblVendorID.Name = "lblVendorID";
   422 			this.lblVendorID.Size = new System.Drawing.Size(112, 23);
   423 			this.lblVendorID.TabIndex = 0;
   424 			this.lblVendorID.Text = "Vendor ID (hex):";
   425 			// 
   426 			// cmdFindDevice
   427 			// 
   428 			this.cmdFindDevice.Location = new System.Drawing.Point(483, 37);
   429 			this.cmdFindDevice.Name = "cmdFindDevice";
   430 			this.cmdFindDevice.Size = new System.Drawing.Size(136, 55);
   431 			this.cmdFindDevice.TabIndex = 11;
   432 			this.cmdFindDevice.Text = "Find My Device";
   433 			this.cmdFindDevice.Click += new System.EventHandler(this.cmdFindDevice_Click);
   434 			// 
   435 			// cmdSendOutputReportInterrupt
   436 			// 
   437 			this.cmdSendOutputReportInterrupt.Location = new System.Drawing.Point(10, 27);
   438 			this.cmdSendOutputReportInterrupt.Name = "cmdSendOutputReportInterrupt";
   439 			this.cmdSendOutputReportInterrupt.Size = new System.Drawing.Size(118, 50);
   440 			this.cmdSendOutputReportInterrupt.TabIndex = 12;
   441 			this.cmdSendOutputReportInterrupt.Text = "Send Output Report";
   442 			this.cmdSendOutputReportInterrupt.UseVisualStyleBackColor = true;
   443 			this.cmdSendOutputReportInterrupt.Click += new System.EventHandler(this.cmdSendOutputReportInterrupt_Click);
   444 			// 
   445 			// cmdGetInputReportInterrupt
   446 			// 
   447 			this.cmdGetInputReportInterrupt.Location = new System.Drawing.Point(10, 83);
   448 			this.cmdGetInputReportInterrupt.Name = "cmdGetInputReportInterrupt";
   449 			this.cmdGetInputReportInterrupt.Size = new System.Drawing.Size(118, 50);
   450 			this.cmdGetInputReportInterrupt.TabIndex = 13;
   451 			this.cmdGetInputReportInterrupt.Text = "Get Input Report";
   452 			this.cmdGetInputReportInterrupt.UseVisualStyleBackColor = true;
   453 			this.cmdGetInputReportInterrupt.Click += new System.EventHandler(this.cmdGetInputReportInterrupt_Click);
   454 			// 
   455 			// fraInterruptTransfers
   456 			// 
   457 			this.fraInterruptTransfers.BackColor = System.Drawing.SystemColors.Control;
   458 			this.fraInterruptTransfers.Controls.Add(this.cmdSendOutputReportInterrupt);
   459 			this.fraInterruptTransfers.Controls.Add(this.cmdGetInputReportInterrupt);
   460 			this.fraInterruptTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   461 			this.fraInterruptTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
   462 			this.fraInterruptTransfers.Location = new System.Drawing.Point(194, 128);
   463 			this.fraInterruptTransfers.Name = "fraInterruptTransfers";
   464 			this.fraInterruptTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
   465 			this.fraInterruptTransfers.Size = new System.Drawing.Size(145, 152);
   466 			this.fraInterruptTransfers.TabIndex = 14;
   467 			this.fraInterruptTransfers.TabStop = false;
   468 			this.fraInterruptTransfers.Text = "Interrupt Transfers";
   469 			// 
   470 			// cmdPeriodicTransfers
   471 			// 
   472 			this.cmdPeriodicTransfers.Location = new System.Drawing.Point(153, 36);
   473 			this.cmdPeriodicTransfers.Name = "cmdPeriodicTransfers";
   474 			this.cmdPeriodicTransfers.Size = new System.Drawing.Size(118, 51);
   475 			this.cmdPeriodicTransfers.TabIndex = 16;
   476 			this.cmdPeriodicTransfers.Text = "Start";
   477 			this.cmdPeriodicTransfers.UseVisualStyleBackColor = true;
   478 			this.cmdPeriodicTransfers.Click += new System.EventHandler(this.cmdPeriodicTransfers_Click);
   479 			// 
   480 			// cmdSendOutputReportControl
   481 			// 
   482 			this.cmdSendOutputReportControl.Location = new System.Drawing.Point(10, 27);
   483 			this.cmdSendOutputReportControl.Name = "cmdSendOutputReportControl";
   484 			this.cmdSendOutputReportControl.Size = new System.Drawing.Size(118, 50);
   485 			this.cmdSendOutputReportControl.TabIndex = 12;
   486 			this.cmdSendOutputReportControl.Text = "Send Output Report";
   487 			this.cmdSendOutputReportControl.UseVisualStyleBackColor = true;
   488 			this.cmdSendOutputReportControl.Click += new System.EventHandler(this.cmdSendOutputReportControl_Click);
   489 			// 
   490 			// cmdGetInputReportControl
   491 			// 
   492 			this.cmdGetInputReportControl.Location = new System.Drawing.Point(10, 83);
   493 			this.cmdGetInputReportControl.Name = "cmdGetInputReportControl";
   494 			this.cmdGetInputReportControl.Size = new System.Drawing.Size(118, 50);
   495 			this.cmdGetInputReportControl.TabIndex = 13;
   496 			this.cmdGetInputReportControl.Text = "Get Input Report";
   497 			this.cmdGetInputReportControl.UseVisualStyleBackColor = true;
   498 			this.cmdGetInputReportControl.Click += new System.EventHandler(this.cmdGetInputReportControl_Click);
   499 			// 
   500 			// fraControlTransfers
   501 			// 
   502 			this.fraControlTransfers.BackColor = System.Drawing.SystemColors.Control;
   503 			this.fraControlTransfers.Controls.Add(this.cmdGetFeatureReport);
   504 			this.fraControlTransfers.Controls.Add(this.cmdSendFeatureReport);
   505 			this.fraControlTransfers.Controls.Add(this.cmdSendOutputReportControl);
   506 			this.fraControlTransfers.Controls.Add(this.cmdGetInputReportControl);
   507 			this.fraControlTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   508 			this.fraControlTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
   509 			this.fraControlTransfers.Location = new System.Drawing.Point(359, 128);
   510 			this.fraControlTransfers.Name = "fraControlTransfers";
   511 			this.fraControlTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
   512 			this.fraControlTransfers.Size = new System.Drawing.Size(277, 152);
   513 			this.fraControlTransfers.TabIndex = 15;
   514 			this.fraControlTransfers.TabStop = false;
   515 			this.fraControlTransfers.Text = "Control Transfers";
   516 			// 
   517 			// cmdGetFeatureReport
   518 			// 
   519 			this.cmdGetFeatureReport.Location = new System.Drawing.Point(141, 83);
   520 			this.cmdGetFeatureReport.Name = "cmdGetFeatureReport";
   521 			this.cmdGetFeatureReport.Size = new System.Drawing.Size(118, 50);
   522 			this.cmdGetFeatureReport.TabIndex = 15;
   523 			this.cmdGetFeatureReport.Text = "Get Feature Report";
   524 			this.cmdGetFeatureReport.UseVisualStyleBackColor = true;
   525 			this.cmdGetFeatureReport.Click += new System.EventHandler(this.cmdGetFeatureReport_Click);
   526 			// 
   527 			// cmdSendFeatureReport
   528 			// 
   529 			this.cmdSendFeatureReport.Location = new System.Drawing.Point(141, 27);
   530 			this.cmdSendFeatureReport.Name = "cmdSendFeatureReport";
   531 			this.cmdSendFeatureReport.Size = new System.Drawing.Size(118, 50);
   532 			this.cmdSendFeatureReport.TabIndex = 14;
   533 			this.cmdSendFeatureReport.Text = "Send Feature Report";
   534 			this.cmdSendFeatureReport.UseVisualStyleBackColor = true;
   535 			this.cmdSendFeatureReport.Click += new System.EventHandler(this.cmdSendFeatureReport_Click);
   536 			// 
   537 			// fraSendAndGetContinuous
   538 			// 
   539 			this.fraSendAndGetContinuous.BackColor = System.Drawing.SystemColors.Control;
   540 			this.fraSendAndGetContinuous.Controls.Add(this.radFeature);
   541 			this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputControl);
   542 			this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputInterrupt);
   543 			this.fraSendAndGetContinuous.Controls.Add(this.cmdPeriodicTransfers);
   544 			this.fraSendAndGetContinuous.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   545 			this.fraSendAndGetContinuous.ForeColor = System.Drawing.SystemColors.ControlText;
   546 			this.fraSendAndGetContinuous.Location = new System.Drawing.Point(194, 296);
   547 			this.fraSendAndGetContinuous.Name = "fraSendAndGetContinuous";
   548 			this.fraSendAndGetContinuous.RightToLeft = System.Windows.Forms.RightToLeft.No;
   549 			this.fraSendAndGetContinuous.Size = new System.Drawing.Size(295, 112);
   550 			this.fraSendAndGetContinuous.TabIndex = 17;
   551 			this.fraSendAndGetContinuous.TabStop = false;
   552 			this.fraSendAndGetContinuous.Text = "Send and Get Continuous";
   553 			// 
   554 			// radInputOutputInterrupt
   555 			// 
   556 			this.radInputOutputInterrupt.AutoSize = true;
   557 			this.radInputOutputInterrupt.Location = new System.Drawing.Point(17, 28);
   558 			this.radInputOutputInterrupt.Name = "radInputOutputInterrupt";
   559 			this.radInputOutputInterrupt.Size = new System.Drawing.Size(126, 18);
   560 			this.radInputOutputInterrupt.TabIndex = 17;
   561 			this.radInputOutputInterrupt.TabStop = true;
   562 			this.radInputOutputInterrupt.Text = "Input Output Interrupt";
   563 			this.radInputOutputInterrupt.UseVisualStyleBackColor = true;
   564 			this.radInputOutputInterrupt.CheckedChanged += new System.EventHandler(this.radInputOutputInterrupt_CheckedChanged);
   565 			// 
   566 			// radInputOutputControl
   567 			// 
   568 			this.radInputOutputControl.AutoSize = true;
   569 			this.radInputOutputControl.Location = new System.Drawing.Point(17, 52);
   570 			this.radInputOutputControl.Name = "radInputOutputControl";
   571 			this.radInputOutputControl.Size = new System.Drawing.Size(120, 18);
   572 			this.radInputOutputControl.TabIndex = 18;
   573 			this.radInputOutputControl.TabStop = true;
   574 			this.radInputOutputControl.Text = "Input Output Control";
   575 			this.radInputOutputControl.UseVisualStyleBackColor = true;
   576 			this.radInputOutputControl.CheckedChanged += new System.EventHandler(this.radInputOutputControl_CheckedChanged);
   577 			// 
   578 			// radFeature
   579 			// 
   580 			this.radFeature.AutoSize = true;
   581 			this.radFeature.Location = new System.Drawing.Point(17, 76);
   582 			this.radFeature.Name = "radFeature";
   583 			this.radFeature.Size = new System.Drawing.Size(62, 18);
   584 			this.radFeature.TabIndex = 19;
   585 			this.radFeature.TabStop = true;
   586 			this.radFeature.Text = "Feature";
   587 			this.radFeature.UseVisualStyleBackColor = true;
   588 			this.radFeature.CheckedChanged += new System.EventHandler(this.radFeature_CheckedChanged);
   589 			// 
   590 			// FrmMain
   591 			// 
   592 			this.ClientSize = new System.Drawing.Size(784, 756);
   593 			this.Controls.Add(this.fraSendAndGetContinuous);
   594 			this.Controls.Add(this.fraControlTransfers);
   595 			this.Controls.Add(this.fraInterruptTransfers);
   596 			this.Controls.Add(this.cmdFindDevice);
   597 			this.Controls.Add(this.fraDeviceIdentifiers);
   598 			this.Controls.Add(this.fraInputReportBufferSize);
   599 			this.Controls.Add(this.FraBytesReceived);
   600 			this.Controls.Add(this.FraBytesToSend);
   601 			this.Controls.Add(this.LstResults);
   602 			this.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
   603 			this.Location = new System.Drawing.Point(21, 28);
   604 			this.Name = "FrmMain";
   605 			this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
   606 			this.Text = "Generic HID Tester";
   607 			this.Closed += new System.EventHandler(this.frmMain_Closed);
   608 			this.Load += new System.EventHandler(this.frmMain_Load);
   609 			this.FraBytesReceived.ResumeLayout(false);
   610 			this.FraBytesReceived.PerformLayout();
   611 			this.FraBytesToSend.ResumeLayout(false);
   612 			this.fraInputReportBufferSize.ResumeLayout(false);
   613 			this.fraInputReportBufferSize.PerformLayout();
   614 			this.fraDeviceIdentifiers.ResumeLayout(false);
   615 			this.fraDeviceIdentifiers.PerformLayout();
   616 			this.fraInterruptTransfers.ResumeLayout(false);
   617 			this.fraControlTransfers.ResumeLayout(false);
   618 			this.fraSendAndGetContinuous.ResumeLayout(false);
   619 			this.fraSendAndGetContinuous.PerformLayout();
   620 			this.ResumeLayout(false);
   621 
   622 		}
   623 		#endregion
   624 
   625 		private Boolean _deviceDetected;
   626 		private IntPtr _deviceNotificationHandle;
   627 		private FileStream _deviceData;
   628 		private FormActions _formActions;
   629 		private SafeFileHandle _hidHandle;
   630 		private String _hidUsage;
   631 		private ManagementEventWatcher _deviceArrivedWatcher;
   632 		private Boolean _deviceHandleObtained;
   633 		private ManagementEventWatcher _deviceRemovedWatcher;
   634 		private Int32 _myProductId;
   635 		private Int32 _myVendorId;
   636 		private Boolean _periodicTransfersRequested;
   637 		private ReportReadOrWritten _readOrWritten;
   638 		private ReportTypes _reportType;
   639 		private SendOrGet _sendOrGet;
   640 		private Boolean _transferInProgress;
   641 		private TransferTypes _transferType;
   642 
   643 		private static System.Timers.Timer _periodicTransfers;
   644 
   645 		private readonly Debugging _myDebugging = new Debugging(); //  For viewing results of API calls via Debug.Write.
   646 		private readonly DeviceManagement _myDeviceManagement = new DeviceManagement();
   647 		private Hid _myHid = new Hid();
   648 
   649 		private enum FormActions
   650 		{
   651 			AddItemToListBox,
   652 			DisableInputReportBufferSize,
   653 			EnableGetInputReportInterruptTransfer,
   654 			EnableInputReportBufferSize,
   655 			EnableSendOutputReportInterrupt,
   656 			ScrollToBottomOfListBox,
   657 			SetInputReportBufferSize
   658 		}
   659 
   660 		private enum ReportReadOrWritten
   661 		{
   662 			Read,
   663 			Written
   664 		}
   665 
   666 		private enum ReportTypes
   667 		{
   668 			Input,
   669 			Output,
   670 			Feature
   671 		}
   672 
   673 		private enum SendOrGet
   674 		{
   675 			Send,
   676 			Get
   677 		}
   678 
   679 		private enum TransferTypes
   680 		{
   681 			Control,
   682 			Interrupt
   683 		}
   684 
   685 		private enum WmiDeviceProperties
   686 		{
   687 			Name,
   688 			Caption,
   689 			Description,
   690 			Manufacturer,
   691 			PNPDeviceID,
   692 			DeviceID,
   693 			ClassGUID
   694 		}
   695 
   696 		internal FrmMain FrmMy;
   697 
   698 		//  This delegate has the same parameters as AccessForm.
   699 		//  Used in accessing the application's form from a different thread.
   700 
   701 		private delegate void MarshalDataToForm(FormActions action, String textToAdd);
   702 
   703 		///  <summary>
   704 		///  Performs various application-specific functions that
   705 		///  involve accessing the application's form.
   706 		///  </summary>
   707 		///  
   708 		///  <param name="action"> a FormActions member that names the action to perform on the form</param>
   709 		///  <param name="formText"> text that the form displays or the code uses for 
   710 		///  another purpose. Actions that don't use text ignore this parameter. </param>
   711 
   712 		private void AccessForm(FormActions action, String formText)
   713 		{
   714 			try
   715 			{
   716 				//  Select an action to perform on the form:
   717 
   718 				switch (action)
   719 				{
   720 					case FormActions.AddItemToListBox:
   721 
   722 						LstResults.Items.Add(formText);
   723 						break;
   724 
   725 					case FormActions.DisableInputReportBufferSize:
   726 
   727 						cmdInputReportBufferSize.Enabled = false;
   728 						break;
   729 
   730 					case FormActions.EnableGetInputReportInterruptTransfer:
   731 
   732 						cmdGetInputReportInterrupt.Enabled = true;
   733 						break;
   734 
   735 					case FormActions.EnableInputReportBufferSize:
   736 
   737 						cmdInputReportBufferSize.Enabled = true;
   738 						break;
   739 
   740 					case FormActions.EnableSendOutputReportInterrupt:
   741 
   742 						cmdSendOutputReportInterrupt.Enabled = true;
   743 						break;
   744 
   745 					case FormActions.ScrollToBottomOfListBox:
   746 
   747 						LstResults.SelectedIndex = LstResults.Items.Count - 1;
   748 						break;
   749 
   750 					case FormActions.SetInputReportBufferSize:
   751 
   752 						txtInputReportBufferSize.Text = formText;
   753 						break;
   754 				}
   755 			}
   756 			catch (Exception ex)
   757 			{
   758 				DisplayException(Name, ex);
   759 				throw;
   760 			}
   761 		}
   762 
   763 		///  <summary>
   764 		///  Add a handler to detect arrival of devices using WMI.
   765 		///  </summary>
   766 
   767 		private void AddDeviceArrivedHandler()
   768 		{
   769 			const Int32 pollingIntervalSeconds = 3;
   770 			var scope = new ManagementScope("root\\CIMV2");
   771 			scope.Options.EnablePrivileges = true;
   772 
   773 			try
   774 			{
   775 				var q = new WqlEventQuery();
   776 				q.EventClassName = "__InstanceCreationEvent";
   777 				q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
   778 				q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
   779 				_deviceArrivedWatcher = new ManagementEventWatcher(scope, q);
   780 				_deviceArrivedWatcher.EventArrived += DeviceAdded;
   781 
   782 				_deviceArrivedWatcher.Start();
   783 			}
   784 			catch (Exception e)
   785 			{
   786 				Debug.WriteLine(e.Message);
   787 				if (_deviceArrivedWatcher != null)
   788 					_deviceArrivedWatcher.Stop();
   789 			}
   790 		}
   791 
   792 		///  <summary>
   793 		///  Add a handler to detect removal of devices using WMI.
   794 		///  </summary>
   795 
   796 		private void AddDeviceRemovedHandler()
   797 		{
   798 			const Int32 pollingIntervalSeconds = 3;
   799 			var scope = new ManagementScope("root\\CIMV2");
   800 			scope.Options.EnablePrivileges = true;
   801 
   802 			try
   803 			{
   804 				var q = new WqlEventQuery();
   805 				q.EventClassName = "__InstanceDeletionEvent";
   806 				q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
   807 				q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
   808 				_deviceRemovedWatcher = new ManagementEventWatcher(scope, q);
   809 				_deviceRemovedWatcher.EventArrived += DeviceRemoved;
   810 				_deviceRemovedWatcher.Start();
   811 			}
   812 			catch (Exception e)
   813 			{
   814 				Debug.WriteLine(e.Message);
   815 				if (_deviceRemovedWatcher != null)
   816 					_deviceRemovedWatcher.Stop();
   817 			}
   818 		}
   819 
   820 		/// <summary>
   821 		/// Close the handle and FileStreams for a device.
   822 		/// </summary>
   823 		/// 
   824 		private void CloseCommunications()
   825 		{
   826 			if (_deviceData != null)
   827 			{
   828 				_deviceData.Close();
   829 			}
   830 
   831 			if ((_hidHandle != null) && (!(_hidHandle.IsInvalid)))
   832 			{
   833 				_hidHandle.Close();
   834 			}
   835 
   836 			// The next attempt to communicate will get a new handle and FileStreams.
   837 
   838 			_deviceHandleObtained = false;
   839 		}
   840 
   841 		///  <summary>
   842 		///  Search for a specific device.
   843 		///  </summary>
   844 
   845 		private void cmdFindDevice_Click(Object sender, EventArgs e)
   846 		{
   847 			try
   848 			{
   849 				if (_transferInProgress)
   850 				{
   851 					DisplayTransferInProgressMessage();
   852 				}
   853 				else
   854 				{
   855 					_deviceDetected = FindDeviceUsingWmi();
   856 					if (_deviceDetected)
   857 					{
   858 						FindTheHid();
   859 					}
   860 				}
   861 			}
   862 			catch (Exception ex)
   863 			{
   864 				DisplayException(Name, ex);
   865 				throw;
   866 			}
   867 		}
   868 
   869 		/// <summary>
   870 		/// Request to get a Feature report from the device.
   871 		/// </summary>
   872 		/// <param name="sender"></param>
   873 		/// <param name="e"></param>
   874 
   875 		private void cmdGetFeatureReport_Click(object sender, EventArgs e)
   876 		{
   877 			try
   878 			{
   879 				if (_transferInProgress)
   880 				{
   881 					DisplayTransferInProgressMessage();
   882 				}
   883 				else
   884 				{
   885 					//  Don't allow another transfer request until this one completes.
   886 					//  Move the focus away from the button to prevent the focus from 
   887 					//  switching to the next control in the tab order on disabling the button.
   888 
   889 					fraControlTransfers.Focus();
   890 					cmdGetFeatureReport.Enabled = false;
   891 					_transferType = TransferTypes.Control;
   892 					RequestToGetFeatureReport();
   893 				}
   894 			}
   895 			catch (Exception ex)
   896 			{
   897 				DisplayException(Name, ex);
   898 				throw;
   899 			}
   900 		}
   901 
   902 		/// <summary>
   903 		/// Request to get an Input report from the device using a control transfer.
   904 		/// </summary>
   905 		/// <param name="sender"></param>
   906 		/// <param name="e"></param>
   907 
   908 		private void cmdGetInputReportControl_Click(object sender, EventArgs e)
   909 		{
   910 			try
   911 			{
   912 				//  Don't allow another transfer request until this one completes.
   913 				//  Move the focus away from the button to prevent the focus from 
   914 				//  switching to the next control in the tab order on disabling the button.
   915 
   916 				if (_transferInProgress)
   917 				{
   918 					DisplayTransferInProgressMessage();
   919 				}
   920 				else
   921 				{
   922 					fraControlTransfers.Focus();
   923 					cmdGetInputReportControl.Enabled = false;
   924 					_transferType = TransferTypes.Control;
   925 					RequestToGetInputReport();
   926 				}
   927 			}
   928 			catch (Exception ex)
   929 			{
   930 				DisplayException(Name, ex);
   931 				throw;
   932 			}
   933 		}
   934 
   935 		/// <summary>
   936 		/// Request to get an Input report retrieved using interrupt transfers.
   937 		/// </summary>
   938 		/// <param name="sender"></param>
   939 		/// <param name="e"></param>
   940 		/// 
   941 		private void cmdGetInputReportInterrupt_Click(object sender, EventArgs e)
   942 		{
   943 			try
   944 			{
   945 				if (_transferInProgress)
   946 				{
   947 					DisplayTransferInProgressMessage();
   948 				}
   949 				else
   950 				{
   951 					//  Don't allow another transfer request until this one completes.
   952 					//  Move the focus away from the button to prevent the focus from 
   953 					//  switching to the next control in the tab order on disabling the button.
   954 
   955 					fraInterruptTransfers.Focus();
   956 					cmdGetInputReportInterrupt.Enabled = false;
   957 					_transferType = TransferTypes.Interrupt;
   958 					RequestToGetInputReport();
   959 				}
   960 			}
   961 			catch (Exception ex)
   962 			{
   963 				DisplayException(Name, ex);
   964 				throw;
   965 			}
   966 		}
   967 
   968 		///  <summary>
   969 		///  Set the number of Input reports the HID driver will store.
   970 		///  </summary>
   971 
   972 		private void cmdInputReportBufferSize_Click(Object sender, EventArgs e)
   973 		{
   974 			try
   975 			{
   976 				if (_transferInProgress)
   977 				{
   978 					DisplayTransferInProgressMessage();
   979 				}
   980 				else
   981 				{
   982 					SetInputReportBufferSize();
   983 				}
   984 			}
   985 			catch
   986 				(Exception ex)
   987 			{
   988 				DisplayException(Name, ex);
   989 				throw;
   990 			}
   991 		}
   992 
   993 		/// <summary>
   994 		/// Alternate sending and getting a report.
   995 		/// </summary>
   996 		/// <param name="sender"></param>
   997 		/// <param name="e"></param>
   998 
   999 		private void cmdPeriodicTransfers_Click(object sender, EventArgs e)
  1000 		{
  1001 			try
  1002 			{
  1003 				if (cmdPeriodicTransfers.Text == "Start")
  1004 				{
  1005 					if (_transferInProgress)
  1006 					{
  1007 						DisplayTransferInProgressMessage();
  1008 					}
  1009 					else
  1010 					{
  1011 						_sendOrGet = SendOrGet.Send;
  1012 						PeriodicTransfersStart();
  1013 					}
  1014 				}
  1015 				else
  1016 				{
  1017 					PeriodicTransfersStop();
  1018 				}
  1019 			}
  1020 			catch (Exception ex)
  1021 			{
  1022 				DisplayException(Name, ex);
  1023 				throw;
  1024 			}
  1025 		}
  1026 
  1027 		/// <summary>
  1028 		/// Request to send a Feature report using a control transfer.
  1029 		/// </summary>
  1030 		/// <param name="sender"></param>
  1031 		/// <param name="e"></param>
  1032 
  1033 		private void cmdSendFeatureReport_Click(object sender, EventArgs e)
  1034 		{
  1035 			try
  1036 			{
  1037 				if (_transferInProgress)
  1038 				{
  1039 					DisplayTransferInProgressMessage();
  1040 				}
  1041 				else
  1042 				{
  1043 					//  Don't allow another transfer request until this one completes.
  1044 					//  Move the focus away from the button to prevent the focus from 
  1045 					//  switching to the next control in the tab order on disabling the button.
  1046 
  1047 					fraControlTransfers.Focus();
  1048 					cmdSendFeatureReport.Enabled = false;
  1049 					_transferType = TransferTypes.Control;
  1050 					RequestToSendFeatureReport();
  1051 				}
  1052 			}
  1053 			catch (Exception ex)
  1054 			{
  1055 				DisplayException(Name, ex);
  1056 				throw;
  1057 			}
  1058 		}
  1059 
  1060 		/// <summary>
  1061 		/// Request to send an Output report using a control transfer.
  1062 		/// </summary>
  1063 		/// <param name="sender"></param>
  1064 		/// <param name="e"></param>
  1065 		/// 
  1066 		private void cmdSendOutputReportControl_Click(object sender, EventArgs e)
  1067 		{
  1068 			try
  1069 			{
  1070 				if (_transferInProgress)
  1071 				{
  1072 					DisplayTransferInProgressMessage();
  1073 				}
  1074 				else
  1075 				{
  1076 					//  Don't allow another transfer request until this one completes.
  1077 					//  Move the focus away from the button to prevent the focus from 
  1078 					//  switching to the next control in the tab order on disabling the button.
  1079 
  1080 					fraControlTransfers.Focus();
  1081 					cmdSendOutputReportControl.Enabled = false;
  1082 					_transferType = TransferTypes.Control;
  1083 					RequestToSendOutputReport();
  1084 				}
  1085 			}
  1086 			catch (Exception ex)
  1087 			{
  1088 				DisplayException(Name, ex);
  1089 				throw;
  1090 			}
  1091 		}
  1092 
  1093 		/// <summary>
  1094 		/// Request to send an Output report using an interrupt transfer.		
  1095 		/// </summary>
  1096 		/// <param name="sender"></param>
  1097 		/// <param name="e"></param>
  1098 
  1099 		private void cmdSendOutputReportInterrupt_Click(object sender, EventArgs e)
  1100 		{
  1101 			try
  1102 			{
  1103 				if (_transferInProgress)
  1104 				{
  1105 					DisplayTransferInProgressMessage();
  1106 				}
  1107 				else
  1108 				{
  1109 					//  Don't allow another transfer request until this one completes.
  1110 					//  Move the focus away from the button to prevent the focus from 
  1111 					//  switching to the next control in the tab order on disabling the button.
  1112 
  1113 					fraInterruptTransfers.Focus();
  1114 					cmdSendOutputReportInterrupt.Enabled = false;
  1115 					_transferType = TransferTypes.Interrupt;
  1116 					RequestToSendOutputReport();
  1117 				}
  1118 			}
  1119 			catch (Exception ex)
  1120 			{
  1121 				DisplayException(Name, ex);
  1122 				throw;
  1123 			}
  1124 		}
  1125 
  1126 		///  <summary>
  1127 		///  Called on arrival of any device.
  1128 		///  Calls a routine that searches to see if the desired device is present.
  1129 		///  </summary>
  1130 
  1131 		private void DeviceAdded(object sender, EventArrivedEventArgs e)
  1132 		{
  1133 			try
  1134 			{
  1135 				Debug.WriteLine("A USB device has been inserted");
  1136 
  1137 				_deviceDetected = FindDeviceUsingWmi();
  1138 			}
  1139 			catch (Exception ex)
  1140 			{
  1141 				DisplayException(Name, ex);
  1142 				throw;
  1143 			}
  1144 		}
  1145 
  1146 		///  <summary>
  1147 		///  Called if the user changes the Vendor ID or Product ID in the text box.
  1148 		///  </summary>
  1149 
  1150 		private void DeviceHasChanged()
  1151 		{
  1152 			try
  1153 			{
  1154 				//  If a device was previously detected, stop receiving notifications about it.
  1155 
  1156 				if (_deviceHandleObtained)
  1157 				{
  1158 					DeviceNotificationsStop();
  1159 
  1160 					CloseCommunications();
  1161 				}
  1162 				// Look for a device that matches the Vendor ID and Product ID in the text boxes.
  1163 
  1164 				FindTheHid();
  1165 			}
  1166 			catch (Exception ex)
  1167 			{
  1168 				DisplayException(Name, ex);
  1169 				throw;
  1170 			}
  1171 		}
  1172 
  1173 		///  <summary>
  1174 		///  Add handlers to detect device arrival and removal.
  1175 		///  </summary>
  1176 
  1177 		private void DeviceNotificationsStart()
  1178 		{
  1179 			AddDeviceArrivedHandler();
  1180 			AddDeviceRemovedHandler();
  1181 		}
  1182 
  1183 		///  <summary>
  1184 		///  Stop receiving notifications about device arrival and removal
  1185 		///  </summary>
  1186 
  1187 		private void DeviceNotificationsStop()
  1188 		{
  1189 			try
  1190 			{
  1191 				if (_deviceArrivedWatcher != null)
  1192 					_deviceArrivedWatcher.Stop();
  1193 				if (_deviceRemovedWatcher != null)
  1194 					_deviceRemovedWatcher.Stop();
  1195 			}
  1196 			catch (Exception ex)
  1197 			{
  1198 				DisplayException(Name, ex);
  1199 				throw;
  1200 			}
  1201 		}
  1202 
  1203 		///  <summary>
  1204 		///  Called on removal of any device.
  1205 		///  Calls a routine that searches to see if the desired device is still present.
  1206 		///  </summary>
  1207 		/// 
  1208 		private void DeviceRemoved(object sender, EventArgs e)
  1209 		{
  1210 			try
  1211 			{
  1212 				Debug.WriteLine("A USB device has been removed");
  1213 
  1214 				_deviceDetected = FindDeviceUsingWmi();
  1215 
  1216 				if (!_deviceDetected)
  1217 				{
  1218 					_deviceHandleObtained = false;
  1219 					CloseCommunications();
  1220 				}
  1221 			}
  1222 			catch (Exception ex)
  1223 			{
  1224 				DisplayException(Name, ex);
  1225 				throw;
  1226 			}
  1227 		}
  1228 
  1229 		///  <summary>
  1230 		///  Displays received or written report data.
  1231 		///  </summary>
  1232 		///  
  1233 		///  <param name="buffer"> contains the report data. </param>			
  1234 		///  <param name="currentReportType" > "Input", "Output", or "Feature"</param>
  1235 		///  <param name="currentReadOrWritten" > "read" for Input and IN Feature reports, "written" for Output and OUT Feature reports.</param>
  1236 
  1237 		private void DisplayReportData(Byte[] buffer, ReportTypes currentReportType, ReportReadOrWritten currentReadOrWritten)
  1238 		{
  1239 			try
  1240 			{
  1241 				Int32 count;
  1242 
  1243 				LstResults.Items.Add(currentReportType.ToString() + " report has been " + currentReadOrWritten.ToString().ToLower() + ".");
  1244 
  1245 				//  Display the report data received in the form's list box.
  1246 
  1247 				LstResults.Items.Add(" Report ID: " + String.Format("{0:X2} ", buffer[0]));
  1248 				LstResults.Items.Add(" Report Data:");
  1249 
  1250 				TxtBytesReceived.Text = "";
  1251 
  1252 				for (count = 1; count <= buffer.Length - 1; count++)
  1253 				{
  1254 					//  Display bytes as 2-character Hex strings.
  1255 
  1256 					String byteValue = String.Format("{0:X2} ", buffer[count]);
  1257 
  1258 					LstResults.Items.Add(" " + byteValue);
  1259 
  1260 					//  Display the received bytes in the text box.
  1261 
  1262 					TxtBytesReceived.SelectionStart = TxtBytesReceived.Text.Length;
  1263 					TxtBytesReceived.SelectedText = byteValue + Environment.NewLine;
  1264 				}
  1265 				ScrollToBottomOfListBox();
  1266 			}
  1267 			catch (Exception ex)
  1268 			{
  1269 				DisplayException(Name, ex);
  1270 				throw;
  1271 			}
  1272 		}
  1273 
  1274 		///  <summary>
  1275 		///  Display a message if the user clicks a button when a transfer is in progress.
  1276 		///  </summary>
  1277 		/// 
  1278 		private void DisplayTransferInProgressMessage()
  1279 		{
  1280 			AccessForm(FormActions.AddItemToListBox, "Command not executed because a transfer is in progress.");
  1281 			ScrollToBottomOfListBox();
  1282 		}
  1283 
  1284 		///  <summary>
  1285 		///  Do periodic transfers.
  1286 		///  </summary>
  1287 		/// <param name="source"></param>
  1288 		/// <param name="e"></param>
  1289 		///  <remarks>
  1290 		///  The timer is enabled only if continuous (periodic) transfers have been requested.
  1291 		///  </remarks>		  
  1292 
  1293 		private void DoPeriodicTransfers(object source, ElapsedEventArgs e)
  1294 		{
  1295 			try
  1296 			{
  1297 				PeriodicTransfers();
  1298 			}
  1299 			catch (Exception ex)
  1300 			{
  1301 				DisplayException(Name, ex);
  1302 				throw;
  1303 			}
  1304 		}
  1305 
  1306 		/// <summary>
  1307 		/// Enable the command buttons on the form.
  1308 		/// Needed after attempting a transfer and device not found.
  1309 		/// </summary>
  1310 		/// 
  1311 		private void EnableFormControls()
  1312 		{
  1313 			cmdGetInputReportInterrupt.Enabled = true;
  1314 			cmdSendOutputReportControl.Enabled = true;
  1315 			cmdGetInputReportControl.Enabled = true;
  1316 			cmdGetFeatureReport.Enabled = true;
  1317 			cmdSendFeatureReport.Enabled = true;
  1318 			cmdPeriodicTransfers.Enabled = true;
  1319 			cmdSendOutputReportInterrupt.Enabled = true;
  1320 		}
  1321 
  1322 		///  <summary>
  1323 		///  Use the System.Management class to find a device by Vendor ID and Product ID using WMI. If found, display device properties.
  1324 		///  </summary>
  1325 		/// <remarks> 
  1326 		/// During debugging, if you stop the firmware but leave the device attached, the device may still be detected as present
  1327 		/// but will be unable to communicate. The device will show up in Windows Device Manager as well. 
  1328 		/// This situation is unlikely to occur with a final product.
  1329 		/// </remarks>
  1330 
  1331 		private Boolean FindDeviceUsingWmi()
  1332 		{
  1333 			try
  1334 			{
  1335 				// Prepend "@" to string below to treat backslash as a normal character (not escape character):
  1336 
  1337 				String deviceIdString = @"USB\VID_" + _myVendorId.ToString("X4") + "&PID_" + _myProductId.ToString("X4");
  1338 
  1339 				_deviceDetected = false;
  1340 				var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity");
  1341 
  1342 				foreach (ManagementObject queryObj in searcher.Get())
  1343 				{
  1344 					if (queryObj["PNPDeviceID"].ToString().Contains(deviceIdString))
  1345 					{
  1346 						_deviceDetected = true;
  1347 						MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
  1348 						MyMarshalDataToForm(FormActions.AddItemToListBox, "My device found (WMI):");
  1349 
  1350 						// Display device properties.
  1351 
  1352 						foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
  1353 						{
  1354 							MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
  1355 							Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
  1356 						}
  1357 						MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
  1358 						MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1359 					}
  1360 				}
  1361 				if (!_deviceDetected)
  1362 				{
  1363 					MyMarshalDataToForm(FormActions.AddItemToListBox, "My device not found (WMI)");
  1364 					MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1365 				}
  1366 				return _deviceDetected;
  1367 			}
  1368 			catch (Exception ex)
  1369 			{
  1370 				DisplayException(Name, ex);
  1371 				throw;
  1372 			}
  1373 		}
  1374 
  1375 		///  <summary>
  1376 		///  Call HID functions that use Win32 API functions to locate a HID-class device
  1377 		///  by its Vendor ID and Product ID. Open a handle to the device.
  1378 		///  </summary>
  1379 		///          
  1380 		///  <returns>
  1381 		///   True if the device is detected, False if not detected.
  1382 		///  </returns>
  1383 
  1384 		private Boolean FindTheHid()
  1385 		{
  1386 			var devicePathName = new String[128];
  1387 			String myDevicePathName = "";
  1388 
  1389 			try
  1390 			{
  1391 				_deviceHandleObtained = false;
  1392 				CloseCommunications();
  1393 
  1394 				//  Get the device's Vendor ID and Product ID from the form's text boxes.
  1395 
  1396 				GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
  1397 
  1398 				// Get the HID-class GUID.
  1399 
  1400 				Guid hidGuid = _myHid.GetHidGuid();
  1401 
  1402 				String functionName = "GetHidGuid";
  1403 				Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
  1404 				Debug.WriteLine("  GUID for system HIDs: " + hidGuid.ToString());
  1405 
  1406 				//  Fill an array with the device path names of all attached HIDs.
  1407 
  1408 				Boolean availableHids = _myDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
  1409 
  1410 				//  If there is at least one HID, attempt to read the Vendor ID and Product ID
  1411 				//  of each device until there is a match or all devices have been examined.
  1412 
  1413 				if (availableHids)
  1414 				{
  1415 					Int32 memberIndex = 0;
  1416 
  1417 					do
  1418 					{
  1419 						// Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice.
  1420 
  1421 						_hidHandle = _myHid.OpenHandle(devicePathName[memberIndex], false);
  1422 
  1423 						functionName = "CreateFile";
  1424 						Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
  1425 						Debug.WriteLine("  Returned handle: " + _hidHandle);
  1426 
  1427 						if (!_hidHandle.IsInvalid)
  1428 						{
  1429 							// The returned handle is valid, 
  1430 							// so find out if this is the device we're looking for.
  1431 
  1432 							_myHid.DeviceAttributes.Size = Marshal.SizeOf(_myHid.DeviceAttributes);
  1433 
  1434 							Boolean success = _myHid.GetAttributes(_hidHandle, ref _myHid.DeviceAttributes);
  1435 
  1436 							if (success)
  1437 							{
  1438 								Debug.WriteLine("  HIDD_ATTRIBUTES structure filled without error.");
  1439 								Debug.WriteLine("  Structure size: " + _myHid.DeviceAttributes.Size);
  1440 								Debug.WriteLine("  Vendor ID: " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
  1441 								Debug.WriteLine("  Product ID: " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
  1442 								Debug.WriteLine("  Version Number: " + Convert.ToString(_myHid.DeviceAttributes.VersionNumber, 16));
  1443 
  1444 								if ((_myHid.DeviceAttributes.VendorID == _myVendorId) && (_myHid.DeviceAttributes.ProductID == _myProductId))
  1445 								{
  1446 									Debug.WriteLine("  Handle obtained to my device");
  1447 
  1448 									//  Display the information in form's list box.
  1449 
  1450 									MyMarshalDataToForm(FormActions.AddItemToListBox, "Handle obtained to my device:");
  1451 									MyMarshalDataToForm(FormActions.AddItemToListBox, "  Vendor ID= " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
  1452 									MyMarshalDataToForm(FormActions.AddItemToListBox, "  Product ID = " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
  1453 									MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1454 
  1455 									_deviceHandleObtained = true;
  1456 
  1457 									myDevicePathName = devicePathName[memberIndex];
  1458 								}
  1459 								else
  1460 								{
  1461 									//  It's not a match, so close the handle.
  1462 
  1463 									_deviceHandleObtained = false;
  1464 									_hidHandle.Close();
  1465 								}
  1466 							}
  1467 							else
  1468 							{
  1469 								//  There was a problem retrieving the information.
  1470 
  1471 								Debug.WriteLine("  Error in filling HIDD_ATTRIBUTES structure.");
  1472 								_deviceHandleObtained = false;
  1473 								_hidHandle.Close();
  1474 							}
  1475 						}
  1476 
  1477 						//  Keep looking until we find the device or there are no devices left to examine.
  1478 
  1479 						memberIndex = memberIndex + 1;
  1480 					}
  1481 					while (!((_deviceHandleObtained || (memberIndex == devicePathName.Length))));
  1482 				}
  1483 
  1484 				if (_deviceHandleObtained)
  1485 				{
  1486 					//  The device was detected.
  1487 					//  Learn the capabilities of the device.
  1488 
  1489 					_myHid.Capabilities = _myHid.GetDeviceCapabilities(_hidHandle);
  1490 
  1491 					//  Find out if the device is a system mouse or keyboard.
  1492 
  1493 					_hidUsage = _myHid.GetHidUsage(_myHid.Capabilities);
  1494 
  1495 					//  Get the Input report buffer size.
  1496 
  1497 					GetInputReportBufferSize();
  1498 					MyMarshalDataToForm(FormActions.EnableInputReportBufferSize, "");
  1499 
  1500 					//Close the handle and reopen it with read/write access.
  1501 
  1502 					_hidHandle.Close();
  1503 
  1504 					_hidHandle = _myHid.OpenHandle(myDevicePathName, true);
  1505 
  1506 					if (_hidHandle.IsInvalid)
  1507 					{
  1508 						MyMarshalDataToForm(FormActions.AddItemToListBox, "The device is a system " + _hidUsage + ".");
  1509 						MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 2000 and later obtain exclusive access to Input and Output reports for this devices.");
  1510 						MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 8 also obtains exclusive access to Feature reports.");
  1511 						MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1512 					}
  1513 					else
  1514 					{
  1515 						if (_myHid.Capabilities.InputReportByteLength > 0)
  1516 						{
  1517 							//  Set the size of the Input report buffer. 
  1518 
  1519 							var inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
  1520 
  1521 							_deviceData = new FileStream(_hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
  1522 						}
  1523 
  1524 						if (_myHid.Capabilities.OutputReportByteLength > 0)
  1525 						{
  1526 							Byte[] outputReportBuffer = null;
  1527 						}
  1528 						//  Flush any waiting reports in the input buffer. (optional)
  1529 
  1530 						_myHid.FlushQueue(_hidHandle);
  1531 					}
  1532 				}
  1533 				else
  1534 				{
  1535 					MyMarshalDataToForm(FormActions.AddItemToListBox, "Device not found.");
  1536 					MyMarshalDataToForm(FormActions.DisableInputReportBufferSize, "");
  1537 					EnableFormControls();
  1538 					MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1539 				}
  1540 				return _deviceHandleObtained;
  1541 			}
  1542 			catch (Exception ex)
  1543 			{
  1544 				DisplayException(Name, ex);
  1545 				throw;
  1546 			}
  1547 		}
  1548 
  1549 		///  <summary>
  1550 		///  Perform shutdown operations.
  1551 		///  </summary>
  1552 
  1553 		private void frmMain_Closed(Object eventSender, EventArgs eventArgs)
  1554 		{
  1555 			try
  1556 			{
  1557 				Shutdown();
  1558 			}
  1559 			catch (Exception ex)
  1560 			{
  1561 				DisplayException(Name, ex);
  1562 				throw;
  1563 			}
  1564 		}
  1565 
  1566 		///  <summary>
  1567 		///  Perform startup operations.
  1568 		///  </summary>
  1569 
  1570 		private void frmMain_Load(Object eventSender, EventArgs eventArgs)
  1571 		{
  1572 			try
  1573 			{
  1574 				FrmMy = this;
  1575 				Startup();
  1576 			}
  1577 			catch (Exception ex)
  1578 			{
  1579 				DisplayException(Name, ex);
  1580 				throw;
  1581 			}
  1582 		}
  1583 
  1584 		private void GetBytesToSend()
  1585 		{
  1586 			try
  1587 			{
  1588 				//  Get the bytes to send in a report from the combo boxes.
  1589 				//  Increment the values if the autoincrement check box is selected.
  1590 
  1591 				if (ChkAutoincrement.Checked)
  1592 				{
  1593 					if (CboByte0.SelectedIndex < 255)
  1594 					{
  1595 						CboByte0.SelectedIndex = CboByte0.SelectedIndex + 1;
  1596 					}
  1597 					else
  1598 					{
  1599 						CboByte0.SelectedIndex = 0;
  1600 					}
  1601 					if (CboByte1.SelectedIndex < 255)
  1602 					{
  1603 						CboByte1.SelectedIndex = CboByte1.SelectedIndex + 1;
  1604 					}
  1605 					else
  1606 					{
  1607 						CboByte1.SelectedIndex = 0;
  1608 					}
  1609 				}
  1610 			}
  1611 			catch (Exception ex)
  1612 			{
  1613 				DisplayException(Name, ex);
  1614 				throw;
  1615 			}
  1616 		}
  1617 
  1618 		///  <summary>
  1619 		///  Find and display the number of Input buffers
  1620 		///  (the number of Input reports the HID driver will store). 
  1621 		///  </summary>
  1622 
  1623 		private void GetInputReportBufferSize()
  1624 		{
  1625 			Int32 numberOfInputBuffers = 0;
  1626 			Boolean success;
  1627 
  1628 			try
  1629 			{
  1630 				//  Get the number of input buffers.
  1631 
  1632 				_myHid.GetNumberOfInputBuffers(_hidHandle, ref numberOfInputBuffers);
  1633 
  1634 				//  Display the result in the text box.
  1635 
  1636 				MyMarshalDataToForm(FormActions.SetInputReportBufferSize, Convert.ToString(numberOfInputBuffers));
  1637 			}
  1638 			catch (Exception ex)
  1639 			{
  1640 				DisplayException(Name, ex);
  1641 				throw;
  1642 			}
  1643 		}
  1644 
  1645 		///  <summary>
  1646 		///  Retrieve a Vendor ID and Product ID in hexadecimal 
  1647 		///  from the form's text boxes and convert the text to Int32s.
  1648 		///  </summary>
  1649 		///  
  1650 		///  <param name="myVendorId"> the Vendor ID</param>
  1651 		///  <param name="myProductId"> the Product ID</param>
  1652 
  1653 		private void GetVendorAndProductIDsFromTextBoxes(ref Int32 myVendorId, ref Int32 myProductId)
  1654 		{
  1655 			try
  1656 			{
  1657 				myVendorId = Int32.Parse(txtVendorID.Text, NumberStyles.AllowHexSpecifier);
  1658 				myProductId = Int32.Parse(txtProductID.Text, NumberStyles.AllowHexSpecifier);
  1659 			}
  1660 			catch (Exception ex)
  1661 			{
  1662 				DisplayException(Name, ex);
  1663 				throw;
  1664 			}
  1665 		}
  1666 
  1667 		///  <summary>
  1668 		///  Initialize the elements on the form.
  1669 		///  </summary>
  1670 
  1671 		private void InitializeDisplay()
  1672 		{
  1673 			try
  1674 			{
  1675 				//  Create a dropdown list box for each byte to send in a report.
  1676 				//  Display the values as 2-character hex strings.
  1677 
  1678 				Int16 count;
  1679 				for (count = 0; count <= 255; count++)
  1680 				{
  1681 					String byteValue = String.Format("{0:X2} ", count);
  1682 					FrmMy.CboByte0.Items.Insert(count, byteValue);
  1683 					FrmMy.CboByte1.Items.Insert(count, byteValue);
  1684 				}
  1685 
  1686 				//  Select a default value for each box
  1687 
  1688 				FrmMy.CboByte0.SelectedIndex = 0;
  1689 				FrmMy.CboByte1.SelectedIndex = 128;
  1690 				FrmMy.radInputOutputInterrupt.Checked = true;
  1691 
  1692 				//  Check the autoincrement box to increment the values each time a report is sent.
  1693 
  1694 				ChkAutoincrement.CheckState = CheckState.Checked;
  1695 
  1696 				//  Don't allow the user to select an input report buffer size until there is
  1697 				//  a handle to a HID.
  1698 
  1699 				cmdInputReportBufferSize.Focus();
  1700 				cmdInputReportBufferSize.Enabled = false;
  1701 
  1702 				LstResults.Items.Add("For a more detailed event log, view debug statements in Visual Studio's Output window:");
  1703 				LstResults.Items.Add("Click Build > Configuration Manager > Active Solution Configuration > Debug > Close.");
  1704 				LstResults.Items.Add("Then click View > Output.");
  1705 				LstResults.Items.Add("");
  1706 			}
  1707 			catch (Exception ex)
  1708 			{
  1709 				DisplayException(Name, ex);
  1710 				throw;
  1711 			}
  1712 		}
  1713 
  1714 		///  <summary>
  1715 		///  Enables accessing a form's controls from another thread 
  1716 		///  </summary>
  1717 		///  
  1718 		///  <param name="action"> a FormActions member that names the action to perform on the form </param>
  1719 		///  <param name="textToDisplay"> text that the form displays or the code uses for 
  1720 		///  another purpose. Actions that don't use text ignore this parameter.  </param>
  1721 
  1722 		private void MyMarshalDataToForm(FormActions action, String textToDisplay)
  1723 		{
  1724 			try
  1725 			{
  1726 				object[] args = { action, textToDisplay };
  1727 
  1728 				//  The AccessForm routine contains the code that accesses the form.
  1729 
  1730 				MarshalDataToForm marshalDataToFormDelegate = AccessForm;
  1731 
  1732 				//  Execute AccessForm, passing the parameters in args.
  1733 
  1734 				Invoke(marshalDataToFormDelegate, args);
  1735 			}
  1736 			catch (Exception ex)
  1737 			{
  1738 				DisplayException(Name, ex);
  1739 				throw;
  1740 			}
  1741 		}
  1742 
  1743 		/// <summary>
  1744 		/// Timeout if read via interrupt transfer doesn't return.
  1745 		/// </summary>
  1746 
  1747 		private void OnReadTimeout()
  1748 		{
  1749 			try
  1750 			{
  1751 				MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a report timed out.");
  1752 				MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1753 				CloseCommunications();
  1754 				MyMarshalDataToForm(FormActions.EnableGetInputReportInterruptTransfer, "");
  1755 				_transferInProgress = false;
  1756 				_sendOrGet = SendOrGet.Send;
  1757 			}
  1758 			catch (Exception ex)
  1759 			{
  1760 				DisplayException(Name, ex);
  1761 				throw;
  1762 			}
  1763 		}
  1764 
  1765 		/// <summary>
  1766 		/// Timeout if write via interrupt transfer doesn't return.
  1767 		/// </summary>
  1768 
  1769 		private void OnWriteTimeout()
  1770 		{
  1771 			try
  1772 			{
  1773 				MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to write a report timed out.");
  1774 				MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
  1775 				CloseCommunications();
  1776 				MyMarshalDataToForm(FormActions.EnableSendOutputReportInterrupt, "");
  1777 				_transferInProgress = false;
  1778 				_sendOrGet = SendOrGet.Get;
  1779 			}
  1780 			catch (Exception ex)
  1781 			{
  1782 				DisplayException(Name, ex);
  1783 				throw;
  1784 			}
  1785 		}
  1786 
  1787 		/// <summary>
  1788 		/// Alternat sending and getting a report.
  1789 		/// </summary>
  1790 
  1791 		private void PeriodicTransfers()
  1792 		{
  1793 			try
  1794 			{
  1795 				if (!_transferInProgress)
  1796 				{
  1797 					if (_reportType == ReportTypes.Feature)
  1798 					{
  1799 						SendOrGetFeatureReport();
  1800 					}
  1801 					else
  1802 					{
  1803 						// Output and Input reports
  1804 
  1805 						SendOutputReportOrGetInputReport();
  1806 					}
  1807 				}
  1808 			}
  1809 			catch (Exception ex)
  1810 			{
  1811 				DisplayException(Name, ex);
  1812 				throw;
  1813 			}
  1814 		}
  1815 
  1816 		/// <summary>
  1817 		/// Start doing periodic transfers.
  1818 		/// </summary>
  1819 
  1820 		private void PeriodicTransfersStart()
  1821 		{
  1822 			// Don't allow changing the transfer type while transfers are in progress.
  1823 
  1824 			if (radFeature.Checked)
  1825 			{
  1826 				radInputOutputControl.Enabled = false;
  1827 				radInputOutputInterrupt.Enabled = false;
  1828 			}
  1829 			else if (radInputOutputControl.Checked)
  1830 			{
  1831 				radFeature.Enabled = false;
  1832 				radInputOutputInterrupt.Enabled = false;
  1833 			}
  1834 			else if (radInputOutputInterrupt.Checked)
  1835 			{
  1836 				radFeature.Enabled = false;
  1837 				radInputOutputControl.Enabled = false;
  1838 			}
  1839 
  1840 			//  Change the command button's text.
  1841 
  1842 			cmdPeriodicTransfers.Text = "Stop";
  1843 
  1844 			//  Enable the timer event to trigger a set of transfers.
  1845 
  1846 			_periodicTransfers.Start();
  1847 
  1848 			cmdPeriodicTransfers.Enabled = true;
  1849 
  1850 			if (radInputOutputInterrupt.Checked)
  1851 			{
  1852 				_transferType = TransferTypes.Interrupt;
  1853 				_reportType = ReportTypes.Output;
  1854 			}
  1855 			else if (radInputOutputControl.Checked)
  1856 			{
  1857 				_transferType = TransferTypes.Control;
  1858 				_reportType = ReportTypes.Output;
  1859 			}
  1860 			else if (radFeature.Checked)
  1861 			{
  1862 				_transferType = TransferTypes.Control;
  1863 				_reportType = ReportTypes.Feature;
  1864 			}
  1865 			_periodicTransfersRequested = true;
  1866 			PeriodicTransfers();
  1867 		}
  1868 
  1869 		/// <summary>
  1870 		/// Stop doing periodic transfers.
  1871 		/// </summary>
  1872 
  1873 		private void PeriodicTransfersStop()
  1874 		{
  1875 			//  Stop doing continuous transfers.
  1876 
  1877 			_periodicTransfersRequested = false;
  1878 
  1879 			// Disable the timer that triggers the transfers.	
  1880 
  1881 			_periodicTransfers.Stop();
  1882 			cmdPeriodicTransfers.Enabled = true;
  1883 
  1884 			//  Change the command button's text.
  1885 
  1886 			cmdPeriodicTransfers.Text = "Start";
  1887 
  1888 			// Re-allow changing the transfer type.
  1889 
  1890 			radFeature.Enabled = true;
  1891 			radInputOutputControl.Enabled = true;
  1892 			radInputOutputInterrupt.Enabled = true;
  1893 		}
  1894 
  1895 		private void radInputOutputControl_CheckedChanged(object sender, EventArgs e)
  1896 		{
  1897 		}
  1898 
  1899 		private void radInputOutputInterrupt_CheckedChanged(object sender, EventArgs e)
  1900 		{
  1901 		}
  1902 
  1903 		private void radFeature_CheckedChanged(object sender, EventArgs e)
  1904 		{
  1905 		}
  1906 
  1907 		///  <summary>
  1908 		///  Request a Feature report.
  1909 		///  Assumes report ID = 0.
  1910 		///  </summary>
  1911 
  1912 		private void RequestToGetFeatureReport()
  1913 		{
  1914 			String byteValue = null;
  1915 
  1916 			try
  1917 			{
  1918 				//  If the device hasn't been detected, was removed, or timed out on a previous attempt
  1919 				//  to access it, look for the device.
  1920 
  1921 				if (!_deviceHandleObtained)
  1922 				{
  1923 					_deviceHandleObtained = FindTheHid();
  1924 				}
  1925 
  1926 				if (_deviceHandleObtained)
  1927 				{
  1928 					Byte[] inFeatureReportBuffer = null;
  1929 
  1930 					if ((_myHid.Capabilities.FeatureReportByteLength > 0))
  1931 					{
  1932 						//  The HID has a Feature report.	
  1933 						//  Read a report from the device.
  1934 
  1935 						//  Set the size of the Feature report buffer. 
  1936 
  1937 						if ((_myHid.Capabilities.FeatureReportByteLength > 0))
  1938 						{
  1939 							inFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
  1940 						}
  1941 
  1942 						//  Read a report.
  1943 
  1944 						Boolean success = _myHid.GetFeatureReport(_hidHandle, ref inFeatureReportBuffer);
  1945 
  1946 						if (success)
  1947 						{
  1948 							DisplayReportData(inFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Read);
  1949 						}
  1950 						else
  1951 						{
  1952 							CloseCommunications();
  1953 							MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a Feature report failed.");
  1954 							ScrollToBottomOfListBox();
  1955 						}
  1956 					}
  1957 					else
  1958 					{
  1959 						MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
  1960 						ScrollToBottomOfListBox();
  1961 					}
  1962 				}
  1963 				_transferInProgress = false;
  1964 				cmdGetFeatureReport.Enabled = true;
  1965 			}
  1966 			catch (Exception ex)
  1967 			{
  1968 				DisplayException(Name, ex);
  1969 				throw;
  1970 			}
  1971 		}
  1972 
  1973 		///  <summary>
  1974 		///  Request an Input report.
  1975 		///  Assumes report ID = 0.
  1976 		///  </summary>
  1977 
  1978 		private async void RequestToGetInputReport()
  1979 		{
  1980 			const Int32 readTimeout = 5000;
  1981 
  1982 			String byteValue = null;
  1983 			Byte[] inputReportBuffer = null;
  1984 
  1985 			try
  1986 			{
  1987 				Boolean success = false;
  1988 
  1989 				//  If the device hasn't been detected, was removed, or timed out on a previous attempt
  1990 				//  to access it, look for the device.
  1991 
  1992 				if (!_deviceHandleObtained)
  1993 				{
  1994 					_deviceHandleObtained = FindTheHid();
  1995 				}
  1996 
  1997 				if (_deviceHandleObtained)
  1998 				{
  1999 					//  Don't attempt to exchange reports if valid handles aren't available
  2000 					//  (as for a mouse or keyboard under Windows 2000 and later.)
  2001 
  2002 					if (!_hidHandle.IsInvalid)
  2003 					{
  2004 						//  Read an Input report.
  2005 
  2006 						//  Don't attempt to send an Input report if the HID has no Input report.
  2007 						//  (The HID spec requires all HIDs to have an interrupt IN endpoint,
  2008 						//  which suggests that all HIDs must support Input reports.)
  2009 
  2010 						if (_myHid.Capabilities.InputReportByteLength > 0)
  2011 						{
  2012 							//  Set the size of the Input report buffer. 
  2013 
  2014 							inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
  2015 
  2016 							if (_transferType.Equals(TransferTypes.Control))
  2017 							{
  2018 								{
  2019 									_transferInProgress = true;
  2020 
  2021 									//  Read a report using a control transfer.
  2022 
  2023 									success = _myHid.GetInputReportViaControlTransfer(_hidHandle, ref inputReportBuffer);
  2024 									cmdGetInputReportControl.Enabled = true;
  2025 									_transferInProgress = false;
  2026 								}
  2027 							}
  2028 							else
  2029 							{
  2030 								{
  2031 									_transferInProgress = true;
  2032 
  2033 									//  Read a report using interrupt transfers. 
  2034 									//  Timeout if no report available.
  2035 									//  To enable reading a report without blocking the calling thread, uses Filestream's ReadAsync method.                                               
  2036 
  2037 									// Create a delegate to execute on a timeout.
  2038 
  2039 									Action onReadTimeoutAction = OnReadTimeout;
  2040 
  2041 									// The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
  2042 
  2043 									var cts = new CancellationTokenSource();
  2044 
  2045 									// Cancel the read if it hasn't completed after a timeout.
  2046 
  2047 									cts.CancelAfter(readTimeout);
  2048 
  2049 									// Specify the function to call on a timeout.
  2050 
  2051 									cts.Token.Register(onReadTimeoutAction);
  2052 
  2053 									// Stops waiting when data is available or on timeout:
  2054 
  2055 									Int32 bytesRead = await _myHid.GetInputReportViaInterruptTransfer(_deviceData, inputReportBuffer, cts);
  2056 
  2057 									// Arrive here only if the operation completed.
  2058 
  2059 									// Dispose to stop the timeout timer. 
  2060 
  2061 									cts.Dispose();
  2062 
  2063 									_transferInProgress = false;
  2064 									cmdGetInputReportInterrupt.Enabled = true;
  2065 
  2066 									if (bytesRead > 0)
  2067 									{
  2068 										success = true;
  2069 										Debug.Print("bytes read (includes report ID) = " + Convert.ToString(bytesRead));
  2070 									}
  2071 								}
  2072 							}
  2073 						}
  2074 						else
  2075 						{
  2076 							MyMarshalDataToForm(FormActions.AddItemToListBox, "No attempt to read an Input report was made.");
  2077 							MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have an Input report.");
  2078 						}
  2079 					}
  2080 					else
  2081 					{
  2082 						MyMarshalDataToForm(FormActions.AddItemToListBox, "Invalid handle.");
  2083 						MyMarshalDataToForm(FormActions.AddItemToListBox,
  2084 											"No attempt to write an Output report or read an Input report was made.");
  2085 					}
  2086 
  2087 					if (success)
  2088 					{
  2089 						DisplayReportData(inputReportBuffer, ReportTypes.Input, ReportReadOrWritten.Read);
  2090 					}
  2091 					else
  2092 					{
  2093 						CloseCommunications();
  2094 						MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read an Input report has failed.");
  2095 						ScrollToBottomOfListBox();
  2096 					}
  2097 				}
  2098 			}
  2099 
  2100 			catch (Exception ex)
  2101 			{
  2102 				DisplayException(Name, ex);
  2103 				throw;
  2104 			}
  2105 		}
  2106 
  2107 		///  <summary>
  2108 		///  Sends a Feature report.
  2109 		///  Assumes report ID = 0.
  2110 		///  </summary>
  2111 
  2112 		private void RequestToSendFeatureReport()
  2113 		{
  2114 			String byteValue = null;
  2115 
  2116 			try
  2117 			{
  2118 				_transferInProgress = true;
  2119 
  2120 				//  If the device hasn't been detected, was removed, or timed out on a previous attempt
  2121 				//  to access it, look for the device.
  2122 
  2123 				if (!_deviceHandleObtained)
  2124 				{
  2125 					_deviceHandleObtained = FindTheHid();
  2126 				}
  2127 
  2128 				if (_deviceHandleObtained)
  2129 				{
  2130 					GetBytesToSend();
  2131 
  2132 					if ((_myHid.Capabilities.FeatureReportByteLength > 0))
  2133 					{
  2134 						//  The HID has a Feature report.
  2135 						//  Set the size of the Feature report buffer. 
  2136 
  2137 						var outFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
  2138 
  2139 						//  Store the report ID in the buffer.
  2140 
  2141 						outFeatureReportBuffer[0] = 0;
  2142 
  2143 						//  Store the report data following the report ID.
  2144 						//  Use the data in the combo boxes on the form.
  2145 
  2146 						outFeatureReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
  2147 
  2148 						if (outFeatureReportBuffer.GetUpperBound(0) > 1)
  2149 						{
  2150 							outFeatureReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
  2151 						}
  2152 
  2153 						//  Write a report to the device
  2154 
  2155 						Boolean success = _myHid.SendFeatureReport(_hidHandle, outFeatureReportBuffer);
  2156 
  2157 						if (success)
  2158 						{
  2159 							DisplayReportData(outFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Written);
  2160 						}
  2161 						else
  2162 						{
  2163 							CloseCommunications();
  2164 							AccessForm(FormActions.AddItemToListBox, "The attempt to send a Feature report failed.");
  2165 							ScrollToBottomOfListBox();
  2166 						}
  2167 					}
  2168 
  2169 					else
  2170 					{
  2171 						AccessForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
  2172 						ScrollToBottomOfListBox();
  2173 					}
  2174 
  2175 				}
  2176 				_transferInProgress = false;
  2177 				cmdSendFeatureReport.Enabled = true;
  2178 				ScrollToBottomOfListBox();
  2179 
  2180 			}
  2181 			catch (Exception ex)
  2182 			{
  2183 				DisplayException(Name, ex);
  2184 				throw;
  2185 			}
  2186 		}
  2187 
  2188 		///  <summary>
  2189 		///  Sends an Output report.
  2190 		///  Assumes report ID = 0.
  2191 		///  </summary>
  2192 
  2193 		private async void RequestToSendOutputReport()
  2194 		{
  2195 			const Int32 writeTimeout = 5000;
  2196 			String byteValue = null;
  2197 
  2198 			try
  2199 			{
  2200 				//  If the device hasn't been detected, was removed, or timed out on a previous attempt
  2201 				//  to access it, look for the device.
  2202 
  2203 				if (!_deviceHandleObtained)
  2204 				{
  2205 					_deviceHandleObtained = FindTheHid();
  2206 				}
  2207 
  2208 				if (_deviceHandleObtained)
  2209 				{
  2210 					GetBytesToSend();
  2211 				}
  2212 				//  Don't attempt to exchange reports if valid handles aren't available
  2213 				//  (as for a mouse or keyboard.)
  2214 
  2215 				if (!_hidHandle.IsInvalid)
  2216 				{
  2217 					//  Don't attempt to send an Output report if the HID has no Output report.
  2218 
  2219 					if (_myHid.Capabilities.OutputReportByteLength > 0)
  2220 					{
  2221 						//  Set the size of the Output report buffer.   
  2222 
  2223 						var outputReportBuffer = new Byte[_myHid.Capabilities.OutputReportByteLength];
  2224 
  2225 						//  Store the report ID in the first byte of the buffer:
  2226 
  2227 						outputReportBuffer[0] = 0;
  2228 
  2229 						//  Store the report data following the report ID.
  2230 						//  Use the data in the combo boxes on the form.
  2231 
  2232 						outputReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
  2233 
  2234 						if (outputReportBuffer.GetUpperBound(0) > 1)
  2235 						{
  2236 							outputReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
  2237 						}
  2238 
  2239 						//  Write a report.
  2240 
  2241 						Boolean success;
  2242 
  2243 						if (_transferType.Equals(TransferTypes.Control))
  2244 						{
  2245 							{
  2246 								_transferInProgress = true;
  2247 
  2248 								//  Use a control transfer to send the report,
  2249 								//  even if the HID has an interrupt OUT endpoint.
  2250 
  2251 								success = _myHid.SendOutputReportViaControlTransfer(_hidHandle, outputReportBuffer);
  2252 
  2253 								_transferInProgress = false;
  2254 								cmdSendOutputReportControl.Enabled = true;
  2255 							}
  2256 						}
  2257 						else
  2258 						{
  2259 							Debug.Print("interrupt");
  2260 							_transferInProgress = true;
  2261 
  2262 							// The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
  2263 
  2264 							var cts = new CancellationTokenSource();
  2265 
  2266 							// Create a delegate to execute on a timeout.
  2267 
  2268 							Action onWriteTimeoutAction = OnWriteTimeout;
  2269 
  2270 							// Cancel the read if it hasn't completed after a timeout.
  2271 
  2272 							cts.CancelAfter(writeTimeout);
  2273 
  2274 							// Specify the function to call on a timeout.
  2275 
  2276 							cts.Token.Register(onWriteTimeoutAction);
  2277 
  2278 							// Send an Output report and wait for completion or timeout.
  2279 
  2280 							success = await _myHid.SendOutputReportViaInterruptTransfer(_deviceData, _hidHandle, outputReportBuffer, cts);
  2281 
  2282 							// Get here only if the operation completes without a timeout.
  2283 
  2284 							_transferInProgress = false;
  2285 							cmdSendOutputReportInterrupt.Enabled = true;
  2286 
  2287 							// Dispose to stop the timeout timer.
  2288 
  2289 							cts.Dispose();
  2290 						}
  2291 						if (success)
  2292 						{
  2293 							DisplayReportData(outputReportBuffer, ReportTypes.Output, ReportReadOrWritten.Written);
  2294 						}
  2295 						else
  2296 						{
  2297 							CloseCommunications();
  2298 							AccessForm(FormActions.AddItemToListBox, "The attempt to write an Output report failed.");
  2299 							ScrollToBottomOfListBox();
  2300 						}
  2301 					}
  2302 				}
  2303 				else
  2304 				{
  2305 					AccessForm(FormActions.AddItemToListBox, "The HID doesn't have an Output report.");
  2306 				}
  2307 			}
  2308 
  2309 			catch (Exception ex)
  2310 			{
  2311 				DisplayException(Name, ex);
  2312 				throw;
  2313 			}
  2314 		}
  2315 
  2316 		///  <summary>
  2317 		///  Scroll to the bottom of the list box and trim as needed.
  2318 		///  </summary>
  2319 
  2320 		private void ScrollToBottomOfListBox()
  2321 		{
  2322 			try
  2323 			{
  2324 				LstResults.SelectedIndex = LstResults.Items.Count - 1;
  2325 
  2326 				//  If the list box is getting too large, trim its contents by removing the earliest data.
  2327 
  2328 				if (LstResults.Items.Count > 1000)
  2329 				{
  2330 					Int32 count;
  2331 					for (count = 1; count <= 500; count++)
  2332 					{
  2333 						LstResults.Items.RemoveAt(4);
  2334 					}
  2335 				}
  2336 			}
  2337 			catch (Exception ex)
  2338 			{
  2339 				DisplayException(Name, ex);
  2340 				throw;
  2341 			}
  2342 		}
  2343 
  2344 		/// <summary>
  2345 		/// Request to send or get a Feature report.
  2346 		/// </summary>
  2347 
  2348 		private void SendOrGetFeatureReport()
  2349 		{
  2350 			try
  2351 			{
  2352 				//  If the device hasn't been detected, was removed, or timed out on a previous attempt
  2353 				//  to access it, look for the device.
  2354 
  2355 				if (!_deviceHandleObtained)
  2356 				{
  2357 					_deviceHandleObtained = FindTheHid();
  2358 				}
  2359 
  2360 				if (_deviceHandleObtained)
  2361 				{
  2362 					switch (_sendOrGet)
  2363 					{
  2364 						case SendOrGet.Send:
  2365 							RequestToSendFeatureReport();
  2366 							_sendOrGet = SendOrGet.Get;
  2367 							break;
  2368 						case SendOrGet.Get:
  2369 							RequestToGetFeatureReport();
  2370 							_sendOrGet = SendOrGet.Send;
  2371 							break;
  2372 					}
  2373 				}
  2374 			}
  2375 			catch (Exception ex)
  2376 			{
  2377 				DisplayException(Name, ex);
  2378 				throw;
  2379 			}
  2380 		}
  2381 
  2382 		/// <summary>
  2383 		/// Request to send an Output report or get an Input report.
  2384 		/// </summary>
  2385 
  2386 		private void SendOutputReportOrGetInputReport()
  2387 		{
  2388 			try
  2389 			{
  2390 				//  If the device hasn't been detected, was removed, or timed out on a previous attempt
  2391 				//  to access it, look for the device.
  2392 
  2393 				if (!_deviceHandleObtained)
  2394 				{
  2395 					_deviceHandleObtained = FindTheHid();
  2396 				}
  2397 
  2398 				if (_deviceHandleObtained)
  2399 				{
  2400 					if (_sendOrGet == SendOrGet.Send)
  2401 					{
  2402 						RequestToSendOutputReport();
  2403 						_sendOrGet = SendOrGet.Get;
  2404 					}
  2405 					else
  2406 					{
  2407 						RequestToGetInputReport();
  2408 						_sendOrGet = SendOrGet.Send;
  2409 					}
  2410 				}
  2411 			}
  2412 			catch (Exception ex)
  2413 			{
  2414 				DisplayException(Name, ex);
  2415 				throw;
  2416 			}
  2417 		}
  2418 
  2419 		///  <summary>
  2420 		///  Set the number of Input buffers (the number of Input reports 
  2421 		///  the host will store) from the value in the text box.
  2422 		///  </summary>
  2423 
  2424 		private void SetInputReportBufferSize()
  2425 		{
  2426 			try
  2427 			{
  2428 				if (!_transferInProgress)
  2429 				{
  2430 					//  Get the number of buffers from the text box.
  2431 
  2432 					Int32 numberOfInputBuffers = Convert.ToInt32(txtInputReportBufferSize.Text);
  2433 
  2434 					//  Set the number of buffers.
  2435 
  2436 					_myHid.SetNumberOfInputBuffers(_hidHandle, numberOfInputBuffers);
  2437 
  2438 					//  Verify and display the result.
  2439 
  2440 					GetInputReportBufferSize();
  2441 				}
  2442 				else
  2443 				{
  2444 					DisplayTransferInProgressMessage();
  2445 				}
  2446 			}
  2447 			catch (Exception ex)
  2448 			{
  2449 				DisplayException(Name, ex);
  2450 				throw;
  2451 			}
  2452 		}
  2453 
  2454 		///  <summary>
  2455 		///  Perform actions that must execute when the program ends.
  2456 		///  </summary>
  2457 
  2458 		private void Shutdown()
  2459 		{
  2460 			try
  2461 			{
  2462 				CloseCommunications();
  2463 				DeviceNotificationsStop();
  2464 			}
  2465 			catch (Exception ex)
  2466 			{
  2467 				DisplayException(Name, ex);
  2468 				throw;
  2469 			}
  2470 		}
  2471 
  2472 		///  <summary>
  2473 		///  Perform actions that must execute when the program starts.
  2474 		///  </summary>
  2475 
  2476 		private void Startup()
  2477 		{
  2478 			const Int32 periodicTransferInterval = 1000;
  2479 			try
  2480 			{
  2481 				_myHid = new Hid();
  2482 				InitializeDisplay();
  2483 
  2484 				_periodicTransfers = new System.Timers.Timer(periodicTransferInterval);
  2485 				_periodicTransfers.Elapsed += DoPeriodicTransfers;
  2486 				_periodicTransfers.Stop();
  2487 				_periodicTransfers.SynchronizingObject = this;
  2488 
  2489 				//  Default USB Vendor ID and Product ID:
  2490 
  2491 				txtVendorID.Text = "0925";
  2492 				txtProductID.Text = "7001";
  2493 
  2494 				GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
  2495 
  2496 				DeviceNotificationsStart();
  2497 				FindDeviceUsingWmi();
  2498 				FindTheHid();
  2499 			}
  2500 			catch (Exception ex)
  2501 			{
  2502 				DisplayException(Name, ex);
  2503 				throw;
  2504 			}
  2505 		}
  2506 
  2507 		///  <summary>
  2508 		///  The Product ID has changed in the text box. Call a routine to handle it.
  2509 		///  </summary>
  2510 
  2511 		private void txtProductID_TextChanged(Object sender, EventArgs e)
  2512 		{
  2513 			try
  2514 			{
  2515 				DeviceHasChanged();
  2516 			}
  2517 			catch (Exception ex)
  2518 			{
  2519 				DisplayException(Name, ex);
  2520 				throw;
  2521 			}
  2522 		}
  2523 
  2524 		///  <summary>
  2525 		///  The Vendor ID has changed in the text box. Call a routine to handle it.
  2526 		///  </summary>
  2527 
  2528 		private void txtVendorID_TextChanged(Object sender, EventArgs e)
  2529 		{
  2530 			try
  2531 			{
  2532 				DeviceHasChanged();
  2533 			}
  2534 			catch (Exception ex)
  2535 			{
  2536 				DisplayException(Name, ex);
  2537 				throw;
  2538 			}
  2539 		}
  2540 
  2541 		///  <summary>
  2542 		///  Provides a central mechanism for exception handling.
  2543 		///  Displays a message box that describes the exception.
  2544 		///  </summary>
  2545 		///  
  2546 		///  <param name="moduleName"> the module where the exception occurred. </param>
  2547 		///  <param name="e"> the exception </param>
  2548 
  2549 		internal static void DisplayException(String moduleName, Exception e)
  2550 		{
  2551 			//  Create an error message.
  2552 
  2553 			String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
  2554 
  2555 			const String caption = "Unexpected Exception";
  2556 
  2557 			MessageBox.Show(message, caption, MessageBoxButtons.OK);
  2558 			Debug.Write(message);
  2559 
  2560 			// Get the last error and display it. 
  2561 
  2562 			Int32 error = Marshal.GetLastWin32Error();
  2563 
  2564 			Debug.WriteLine("The last Win32 Error was: " + error);
  2565 		}
  2566 
  2567 		[STAThread]
  2568 		internal static void Main() { Application.Run(new FrmMain()); }
  2569 		private static FrmMain _transDefaultFormFrmMain;
  2570 		internal static FrmMain TransDefaultFormFrmMain
  2571 		{
  2572 			get
  2573 			{
  2574 				if (_transDefaultFormFrmMain == null)
  2575 				{
  2576 					_transDefaultFormFrmMain = new FrmMain();
  2577 				}
  2578 				return _transDefaultFormFrmMain;
  2579 			}
  2580 		}
  2581 	}
  2582 }