Adding log s to display all our HID devices.
1 using Microsoft.Win32.SafeHandles;
3 using System.Diagnostics;
4 using System.Globalization;
6 using System.Management;
7 using System.Runtime.InteropServices;
8 using System.Threading;
10 using System.Windows.Forms;
15 /// Project: GenericHid
17 /// ***********************************************************************
18 /// Software License Agreement
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.
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
33 /// ***********************************************************************
38 /// This software was written using Visual Studio Express 2012 for Windows
39 /// Desktop building for the .NET Framework v4.5.
42 /// Demonstrates USB communications with a generic HID-class device
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.)
49 /// Finds an attached device that matches the vendor and product IDs in the form's
52 /// Retrieves the device's capabilities.
53 /// Sends and requests HID reports.
55 /// Uses the System.Management class and Windows Management Instrumentation (WMI) to detect
56 /// when a device is attached or removed.
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.
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.
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.
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.
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.
78 /// This project includes the following modules:
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.
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.
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
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.
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.
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);
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/
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.
134 /// Supports Vendor IDs and Product IDs up to FFFFh.
138 /// Changed HIDD_ATTRIBUTES to use UInt16
142 /// Moved Free_ and similar to Finally blocks to ensure they execute.
146 /// Changes to support 64-bit systems, memory management, and other corrections.
147 /// Big thanks to Peter Nielsen.
151 internal class FrmMain
154 #region '"Windows Form Designer generated code "'
158 // This call is required by the Windows Form Designer.
159 InitializeComponent();
161 // Form overrides dispose to clean up the component list.
162 protected override void Dispose(bool Disposing1)
166 if (components != null)
168 components.Dispose();
171 base.Dispose(Disposing1);
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;
210 [System.Diagnostics.DebuggerStepThrough()]
211 private void InitializeComponent()
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();
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";
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;
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";
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;
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;
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;
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;
352 // fraInputReportBufferSize
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";
363 // cmdInputReportBufferSize
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);
372 // txtInputReportBufferSize
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;
379 // fraDeviceIdentifiers
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";
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);
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):";
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);
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):";
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);
435 // cmdSendOutputReportInterrupt
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);
445 // cmdGetInputReportInterrupt
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);
455 // fraInterruptTransfers
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";
470 // cmdPeriodicTransfers
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);
480 // cmdSendOutputReportControl
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);
490 // cmdGetInputReportControl
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);
500 // fraControlTransfers
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";
517 // cmdGetFeatureReport
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);
527 // cmdSendFeatureReport
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);
537 // fraSendAndGetContinuous
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";
554 // radInputOutputInterrupt
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);
566 // radInputOutputControl
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);
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);
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);
623 #endregion '"Windows Form Designer generated code "'
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;
643 private static System.Timers.Timer _periodicTransfers;
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();
649 private enum FormActions
652 DisableInputReportBufferSize,
653 EnableGetInputReportInterruptTransfer,
654 EnableInputReportBufferSize,
655 EnableSendOutputReportInterrupt,
656 ScrollToBottomOfListBox,
657 SetInputReportBufferSize
660 private enum ReportReadOrWritten
666 private enum ReportTypes
673 private enum SendOrGet
679 private enum TransferTypes
685 private enum WmiDeviceProperties
696 internal FrmMain FrmMy;
698 // This delegate has the same parameters as AccessForm.
699 // Used in accessing the application's form from a different thread.
701 private delegate void MarshalDataToForm(FormActions action, String textToAdd);
704 /// Performs various application-specific functions that
705 /// involve accessing the application's form.
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>
712 private void AccessForm(FormActions action, String formText)
716 // Select an action to perform on the form:
720 case FormActions.AddItemToListBox:
722 LstResults.Items.Add(formText);
725 case FormActions.DisableInputReportBufferSize:
727 cmdInputReportBufferSize.Enabled = false;
730 case FormActions.EnableGetInputReportInterruptTransfer:
732 cmdGetInputReportInterrupt.Enabled = true;
735 case FormActions.EnableInputReportBufferSize:
737 cmdInputReportBufferSize.Enabled = true;
740 case FormActions.EnableSendOutputReportInterrupt:
742 cmdSendOutputReportInterrupt.Enabled = true;
745 case FormActions.ScrollToBottomOfListBox:
747 LstResults.SelectedIndex = LstResults.Items.Count - 1;
750 case FormActions.SetInputReportBufferSize:
752 txtInputReportBufferSize.Text = formText;
758 DisplayException(Name, ex);
764 /// Add a handler to detect arrival of devices using WMI.
767 private void AddDeviceArrivedHandler()
769 const Int32 pollingIntervalSeconds = 3;
770 var scope = new ManagementScope("root\\CIMV2");
771 scope.Options.EnablePrivileges = true;
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;
782 _deviceArrivedWatcher.Start();
786 Debug.WriteLine(e.Message);
787 if (_deviceArrivedWatcher != null)
788 _deviceArrivedWatcher.Stop();
793 /// Add a handler to detect removal of devices using WMI.
796 private void AddDeviceRemovedHandler()
798 const Int32 pollingIntervalSeconds = 3;
799 var scope = new ManagementScope("root\\CIMV2");
800 scope.Options.EnablePrivileges = true;
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();
814 Debug.WriteLine(e.Message);
815 if (_deviceRemovedWatcher != null)
816 _deviceRemovedWatcher.Stop();
821 /// Close the handle and FileStreams for a device.
824 private void CloseCommunications()
826 if (_deviceData != null)
831 if ((_hidHandle != null) && (!(_hidHandle.IsInvalid)))
836 // The next attempt to communicate will get a new handle and FileStreams.
838 _deviceHandleObtained = false;
842 /// Search for a specific device.
845 private void cmdFindDevice_Click(Object sender, EventArgs e)
849 if (_transferInProgress)
851 DisplayTransferInProgressMessage();
855 _deviceDetected = FindDeviceUsingWmi();
864 DisplayException(Name, ex);
870 /// Request to get a Feature report from the device.
872 /// <param name="sender"></param>
873 /// <param name="e"></param>
875 private void cmdGetFeatureReport_Click(object sender, EventArgs e)
879 if (_transferInProgress)
881 DisplayTransferInProgressMessage();
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.
889 fraControlTransfers.Focus();
890 cmdGetFeatureReport.Enabled = false;
891 _transferType = TransferTypes.Control;
892 RequestToGetFeatureReport();
897 DisplayException(Name, ex);
903 /// Request to get an Input report from the device using a control transfer.
905 /// <param name="sender"></param>
906 /// <param name="e"></param>
908 private void cmdGetInputReportControl_Click(object sender, EventArgs e)
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.
916 if (_transferInProgress)
918 DisplayTransferInProgressMessage();
922 fraControlTransfers.Focus();
923 cmdGetInputReportControl.Enabled = false;
924 _transferType = TransferTypes.Control;
925 RequestToGetInputReport();
930 DisplayException(Name, ex);
936 /// Request to get an Input report retrieved using interrupt transfers.
938 /// <param name="sender"></param>
939 /// <param name="e"></param>
941 private void cmdGetInputReportInterrupt_Click(object sender, EventArgs e)
945 if (_transferInProgress)
947 DisplayTransferInProgressMessage();
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.
955 fraInterruptTransfers.Focus();
956 cmdGetInputReportInterrupt.Enabled = false;
957 _transferType = TransferTypes.Interrupt;
958 RequestToGetInputReport();
963 DisplayException(Name, ex);
969 /// Set the number of Input reports the HID driver will store.
972 private void cmdInputReportBufferSize_Click(Object sender, EventArgs e)
976 if (_transferInProgress)
978 DisplayTransferInProgressMessage();
982 SetInputReportBufferSize();
988 DisplayException(Name, ex);
994 /// Alternate sending and getting a report.
996 /// <param name="sender"></param>
997 /// <param name="e"></param>
999 private void cmdPeriodicTransfers_Click(object sender, EventArgs e)
1003 if (cmdPeriodicTransfers.Text == "Start")
1005 if (_transferInProgress)
1007 DisplayTransferInProgressMessage();
1011 _sendOrGet = SendOrGet.Send;
1012 PeriodicTransfersStart();
1017 PeriodicTransfersStop();
1020 catch (Exception ex)
1022 DisplayException(Name, ex);
1028 /// Request to send a Feature report using a control transfer.
1030 /// <param name="sender"></param>
1031 /// <param name="e"></param>
1033 private void cmdSendFeatureReport_Click(object sender, EventArgs e)
1037 if (_transferInProgress)
1039 DisplayTransferInProgressMessage();
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.
1047 fraControlTransfers.Focus();
1048 cmdSendFeatureReport.Enabled = false;
1049 _transferType = TransferTypes.Control;
1050 RequestToSendFeatureReport();
1053 catch (Exception ex)
1055 DisplayException(Name, ex);
1061 /// Request to send an Output report using a control transfer.
1063 /// <param name="sender"></param>
1064 /// <param name="e"></param>
1066 private void cmdSendOutputReportControl_Click(object sender, EventArgs e)
1070 if (_transferInProgress)
1072 DisplayTransferInProgressMessage();
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.
1080 fraControlTransfers.Focus();
1081 cmdSendOutputReportControl.Enabled = false;
1082 _transferType = TransferTypes.Control;
1083 RequestToSendOutputReport();
1086 catch (Exception ex)
1088 DisplayException(Name, ex);
1094 /// Request to send an Output report using an interrupt transfer.
1096 /// <param name="sender"></param>
1097 /// <param name="e"></param>
1099 private void cmdSendOutputReportInterrupt_Click(object sender, EventArgs e)
1103 if (_transferInProgress)
1105 DisplayTransferInProgressMessage();
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.
1113 fraInterruptTransfers.Focus();
1114 cmdSendOutputReportInterrupt.Enabled = false;
1115 _transferType = TransferTypes.Interrupt;
1116 RequestToSendOutputReport();
1119 catch (Exception ex)
1121 DisplayException(Name, ex);
1127 /// Called on arrival of any device.
1128 /// Calls a routine that searches to see if the desired device is present.
1131 private void DeviceAdded(object sender, EventArrivedEventArgs e)
1135 Debug.WriteLine("A USB device has been inserted");
1137 _deviceDetected = FindDeviceUsingWmi();
1139 catch (Exception ex)
1141 DisplayException(Name, ex);
1147 /// Called if the user changes the Vendor ID or Product ID in the text box.
1150 private void DeviceHasChanged()
1154 // If a device was previously detected, stop receiving notifications about it.
1156 if (_deviceHandleObtained)
1158 DeviceNotificationsStop();
1160 CloseCommunications();
1162 // Look for a device that matches the Vendor ID and Product ID in the text boxes.
1166 catch (Exception ex)
1168 DisplayException(Name, ex);
1174 /// Add handlers to detect device arrival and removal.
1177 private void DeviceNotificationsStart()
1179 AddDeviceArrivedHandler();
1180 AddDeviceRemovedHandler();
1184 /// Stop receiving notifications about device arrival and removal
1187 private void DeviceNotificationsStop()
1191 if (_deviceArrivedWatcher != null)
1192 _deviceArrivedWatcher.Stop();
1193 if (_deviceRemovedWatcher != null)
1194 _deviceRemovedWatcher.Stop();
1196 catch (Exception ex)
1198 DisplayException(Name, ex);
1204 /// Called on removal of any device.
1205 /// Calls a routine that searches to see if the desired device is still present.
1208 private void DeviceRemoved(object sender, EventArgs e)
1212 Debug.WriteLine("A USB device has been removed");
1214 _deviceDetected = FindDeviceUsingWmi();
1216 if (!_deviceDetected)
1218 _deviceHandleObtained = false;
1219 CloseCommunications();
1222 catch (Exception ex)
1224 DisplayException(Name, ex);
1230 /// Displays received or written report data.
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>
1237 private void DisplayReportData(Byte[] buffer, ReportTypes currentReportType, ReportReadOrWritten currentReadOrWritten)
1243 LstResults.Items.Add(currentReportType.ToString() + " report has been " + currentReadOrWritten.ToString().ToLower() + ".");
1245 // Display the report data received in the form's list box.
1247 LstResults.Items.Add(" Report ID: " + String.Format("{0:X2} ", buffer[0]));
1248 LstResults.Items.Add(" Report Data:");
1250 TxtBytesReceived.Text = "";
1252 for (count = 1; count <= buffer.Length - 1; count++)
1254 // Display bytes as 2-character Hex strings.
1256 String byteValue = String.Format("{0:X2} ", buffer[count]);
1258 LstResults.Items.Add(" " + byteValue);
1260 // Display the received bytes in the text box.
1262 TxtBytesReceived.SelectionStart = TxtBytesReceived.Text.Length;
1263 TxtBytesReceived.SelectedText = byteValue + Environment.NewLine;
1265 ScrollToBottomOfListBox();
1267 catch (Exception ex)
1269 DisplayException(Name, ex);
1275 /// Display a message if the user clicks a button when a transfer is in progress.
1278 private void DisplayTransferInProgressMessage()
1280 AccessForm(FormActions.AddItemToListBox, "Command not executed because a transfer is in progress.");
1281 ScrollToBottomOfListBox();
1285 /// Do periodic transfers.
1287 /// <param name="source"></param>
1288 /// <param name="e"></param>
1290 /// The timer is enabled only if continuous (periodic) transfers have been requested.
1293 private void DoPeriodicTransfers(object source, ElapsedEventArgs e)
1297 PeriodicTransfers();
1299 catch (Exception ex)
1301 DisplayException(Name, ex);
1307 /// Enable the command buttons on the form.
1308 /// Needed after attempting a transfer and device not found.
1311 private void EnableFormControls()
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;
1323 /// Use the System.Management class to find a device by Vendor ID and Product ID using WMI. If found, display device properties.
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.
1331 private Boolean FindDeviceUsingWmi()
1335 // Prepend "@" to string below to treat backslash as a normal character (not escape character):
1337 String deviceIdString = @"USB\VID_" + _myVendorId.ToString("X4") + "&PID_" + _myProductId.ToString("X4");
1339 _deviceDetected = false;
1340 var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity");
1341 int usbDeviceCounter = 0;
1343 foreach (ManagementObject queryObj in searcher.Get())
1345 string deviceId = queryObj["PNPDeviceID"].ToString();
1346 if (deviceId.Contains(deviceIdString))
1349 _deviceDetected = true;
1350 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1351 MyMarshalDataToForm(FormActions.AddItemToListBox, "My device found (WMI):");
1353 // Display device properties.
1355 foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
1357 MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
1358 Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
1360 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1361 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1363 else if (deviceId.StartsWith("USB\\"))
1366 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1367 MyMarshalDataToForm(FormActions.AddItemToListBox, "Skipping device:" + deviceId);
1368 foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
1370 MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
1371 Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
1373 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1374 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1378 MyMarshalDataToForm(FormActions.AddItemToListBox, "Found " + usbDeviceCounter /*searcher.Get().Count*/ + " USB HID devices");
1380 if (!_deviceDetected)
1382 MyMarshalDataToForm(FormActions.AddItemToListBox, "My device not found (WMI)");
1383 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1385 return _deviceDetected;
1387 catch (Exception ex)
1389 DisplayException(Name, ex);
1395 /// Call HID functions that use Win32 API functions to locate a HID-class device
1396 /// by its Vendor ID and Product ID. Open a handle to the device.
1400 /// True if the device is detected, False if not detected.
1403 private Boolean FindTheHid()
1405 var devicePathName = new String[128];
1406 String myDevicePathName = "";
1410 _deviceHandleObtained = false;
1411 CloseCommunications();
1413 // Get the device's Vendor ID and Product ID from the form's text boxes.
1415 GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
1417 // Get the HID-class GUID.
1419 Guid hidGuid = _myHid.GetHidGuid();
1421 String functionName = "GetHidGuid";
1422 Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
1423 Debug.WriteLine(" GUID for system HIDs: " + hidGuid.ToString());
1425 // Fill an array with the device path names of all attached HIDs.
1427 Boolean availableHids = _myDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
1429 // If there is at least one HID, attempt to read the Vendor ID and Product ID
1430 // of each device until there is a match or all devices have been examined.
1434 Int32 memberIndex = 0;
1438 // Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice.
1440 _hidHandle = _myHid.OpenHandle(devicePathName[memberIndex], false);
1442 functionName = "CreateFile";
1443 Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
1444 Debug.WriteLine(" Returned handle: " + _hidHandle);
1446 if (!_hidHandle.IsInvalid)
1448 // The returned handle is valid,
1449 // so find out if this is the device we're looking for.
1451 _myHid.DeviceAttributes.Size = Marshal.SizeOf(_myHid.DeviceAttributes);
1453 Boolean success = _myHid.GetAttributes(_hidHandle, ref _myHid.DeviceAttributes);
1457 Debug.WriteLine(" HIDD_ATTRIBUTES structure filled without error.");
1458 Debug.WriteLine(" Structure size: " + _myHid.DeviceAttributes.Size);
1459 Debug.WriteLine(" Vendor ID: " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
1460 Debug.WriteLine(" Product ID: " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
1461 Debug.WriteLine(" Version Number: " + Convert.ToString(_myHid.DeviceAttributes.VersionNumber, 16));
1463 if ((_myHid.DeviceAttributes.VendorID == _myVendorId) && (_myHid.DeviceAttributes.ProductID == _myProductId))
1465 Debug.WriteLine(" Handle obtained to my device");
1467 // Display the information in form's list box.
1469 MyMarshalDataToForm(FormActions.AddItemToListBox, "Handle obtained to my device:");
1470 MyMarshalDataToForm(FormActions.AddItemToListBox, " Vendor ID= " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
1471 MyMarshalDataToForm(FormActions.AddItemToListBox, " Product ID = " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
1472 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1474 _deviceHandleObtained = true;
1476 myDevicePathName = devicePathName[memberIndex];
1480 // It's not a match, so close the handle.
1482 _deviceHandleObtained = false;
1488 // There was a problem retrieving the information.
1490 Debug.WriteLine(" Error in filling HIDD_ATTRIBUTES structure.");
1491 _deviceHandleObtained = false;
1496 // Keep looking until we find the device or there are no devices left to examine.
1498 memberIndex = memberIndex + 1;
1500 while (!((_deviceHandleObtained || (memberIndex == devicePathName.Length))));
1503 if (_deviceHandleObtained)
1505 // The device was detected.
1506 // Learn the capabilities of the device.
1508 _myHid.Capabilities = _myHid.GetDeviceCapabilities(_hidHandle);
1510 // Find out if the device is a system mouse or keyboard.
1512 _hidUsage = _myHid.GetHidUsage(_myHid.Capabilities);
1514 // Get the Input report buffer size.
1516 GetInputReportBufferSize();
1517 MyMarshalDataToForm(FormActions.EnableInputReportBufferSize, "");
1519 //Close the handle and reopen it with read/write access.
1523 _hidHandle = _myHid.OpenHandle(myDevicePathName, true);
1525 if (_hidHandle.IsInvalid)
1527 MyMarshalDataToForm(FormActions.AddItemToListBox, "The device is a system " + _hidUsage + ".");
1528 MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 2000 and later obtain exclusive access to Input and Output reports for this devices.");
1529 MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 8 also obtains exclusive access to Feature reports.");
1530 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1534 if (_myHid.Capabilities.InputReportByteLength > 0)
1536 // Set the size of the Input report buffer.
1538 var inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
1540 _deviceData = new FileStream(_hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
1543 if (_myHid.Capabilities.OutputReportByteLength > 0)
1545 Byte[] outputReportBuffer = null;
1547 // Flush any waiting reports in the input buffer. (optional)
1549 _myHid.FlushQueue(_hidHandle);
1554 MyMarshalDataToForm(FormActions.AddItemToListBox, "Device not found.");
1555 MyMarshalDataToForm(FormActions.DisableInputReportBufferSize, "");
1556 EnableFormControls();
1557 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1559 return _deviceHandleObtained;
1561 catch (Exception ex)
1563 DisplayException(Name, ex);
1569 /// Perform shutdown operations.
1572 private void frmMain_Closed(Object eventSender, EventArgs eventArgs)
1578 catch (Exception ex)
1580 DisplayException(Name, ex);
1586 /// Perform startup operations.
1589 private void frmMain_Load(Object eventSender, EventArgs eventArgs)
1596 catch (Exception ex)
1598 DisplayException(Name, ex);
1603 private void GetBytesToSend()
1607 // Get the bytes to send in a report from the combo boxes.
1608 // Increment the values if the autoincrement check box is selected.
1610 if (ChkAutoincrement.Checked)
1612 if (CboByte0.SelectedIndex < 255)
1614 CboByte0.SelectedIndex = CboByte0.SelectedIndex + 1;
1618 CboByte0.SelectedIndex = 0;
1620 if (CboByte1.SelectedIndex < 255)
1622 CboByte1.SelectedIndex = CboByte1.SelectedIndex + 1;
1626 CboByte1.SelectedIndex = 0;
1630 catch (Exception ex)
1632 DisplayException(Name, ex);
1638 /// Find and display the number of Input buffers
1639 /// (the number of Input reports the HID driver will store).
1642 private void GetInputReportBufferSize()
1644 Int32 numberOfInputBuffers = 0;
1649 // Get the number of input buffers.
1651 _myHid.GetNumberOfInputBuffers(_hidHandle, ref numberOfInputBuffers);
1653 // Display the result in the text box.
1655 MyMarshalDataToForm(FormActions.SetInputReportBufferSize, Convert.ToString(numberOfInputBuffers));
1657 catch (Exception ex)
1659 DisplayException(Name, ex);
1665 /// Retrieve a Vendor ID and Product ID in hexadecimal
1666 /// from the form's text boxes and convert the text to Int32s.
1669 /// <param name="myVendorId"> the Vendor ID</param>
1670 /// <param name="myProductId"> the Product ID</param>
1672 private void GetVendorAndProductIDsFromTextBoxes(ref Int32 myVendorId, ref Int32 myProductId)
1676 myVendorId = Int32.Parse(txtVendorID.Text, NumberStyles.AllowHexSpecifier);
1677 myProductId = Int32.Parse(txtProductID.Text, NumberStyles.AllowHexSpecifier);
1679 catch (Exception ex)
1681 DisplayException(Name, ex);
1687 /// Initialize the elements on the form.
1690 private void InitializeDisplay()
1694 // Create a dropdown list box for each byte to send in a report.
1695 // Display the values as 2-character hex strings.
1698 for (count = 0; count <= 255; count++)
1700 String byteValue = String.Format("{0:X2} ", count);
1701 FrmMy.CboByte0.Items.Insert(count, byteValue);
1702 FrmMy.CboByte1.Items.Insert(count, byteValue);
1705 // Select a default value for each box
1707 FrmMy.CboByte0.SelectedIndex = 0;
1708 FrmMy.CboByte1.SelectedIndex = 128;
1709 FrmMy.radInputOutputInterrupt.Checked = true;
1711 // Check the autoincrement box to increment the values each time a report is sent.
1713 ChkAutoincrement.CheckState = CheckState.Checked;
1715 // Don't allow the user to select an input report buffer size until there is
1716 // a handle to a HID.
1718 cmdInputReportBufferSize.Focus();
1719 cmdInputReportBufferSize.Enabled = false;
1721 LstResults.Items.Add("For a more detailed event log, view debug statements in Visual Studio's Output window:");
1722 LstResults.Items.Add("Click Build > Configuration Manager > Active Solution Configuration > Debug > Close.");
1723 LstResults.Items.Add("Then click View > Output.");
1724 LstResults.Items.Add("");
1726 catch (Exception ex)
1728 DisplayException(Name, ex);
1734 /// Enables accessing a form's controls from another thread
1737 /// <param name="action"> a FormActions member that names the action to perform on the form </param>
1738 /// <param name="textToDisplay"> text that the form displays or the code uses for
1739 /// another purpose. Actions that don't use text ignore this parameter. </param>
1741 private void MyMarshalDataToForm(FormActions action, String textToDisplay)
1745 object[] args = { action, textToDisplay };
1747 // The AccessForm routine contains the code that accesses the form.
1749 MarshalDataToForm marshalDataToFormDelegate = AccessForm;
1751 // Execute AccessForm, passing the parameters in args.
1753 Invoke(marshalDataToFormDelegate, args);
1755 catch (Exception ex)
1757 DisplayException(Name, ex);
1763 /// Timeout if read via interrupt transfer doesn't return.
1766 private void OnReadTimeout()
1770 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a report timed out.");
1771 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1772 CloseCommunications();
1773 MyMarshalDataToForm(FormActions.EnableGetInputReportInterruptTransfer, "");
1774 _transferInProgress = false;
1775 _sendOrGet = SendOrGet.Send;
1777 catch (Exception ex)
1779 DisplayException(Name, ex);
1785 /// Timeout if write via interrupt transfer doesn't return.
1788 private void OnWriteTimeout()
1792 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to write a report timed out.");
1793 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1794 CloseCommunications();
1795 MyMarshalDataToForm(FormActions.EnableSendOutputReportInterrupt, "");
1796 _transferInProgress = false;
1797 _sendOrGet = SendOrGet.Get;
1799 catch (Exception ex)
1801 DisplayException(Name, ex);
1807 /// Alternat sending and getting a report.
1810 private void PeriodicTransfers()
1814 if (!_transferInProgress)
1816 if (_reportType == ReportTypes.Feature)
1818 SendOrGetFeatureReport();
1822 // Output and Input reports
1824 SendOutputReportOrGetInputReport();
1828 catch (Exception ex)
1830 DisplayException(Name, ex);
1836 /// Start doing periodic transfers.
1839 private void PeriodicTransfersStart()
1841 // Don't allow changing the transfer type while transfers are in progress.
1843 if (radFeature.Checked)
1845 radInputOutputControl.Enabled = false;
1846 radInputOutputInterrupt.Enabled = false;
1848 else if (radInputOutputControl.Checked)
1850 radFeature.Enabled = false;
1851 radInputOutputInterrupt.Enabled = false;
1853 else if (radInputOutputInterrupt.Checked)
1855 radFeature.Enabled = false;
1856 radInputOutputControl.Enabled = false;
1859 // Change the command button's text.
1861 cmdPeriodicTransfers.Text = "Stop";
1863 // Enable the timer event to trigger a set of transfers.
1865 _periodicTransfers.Start();
1867 cmdPeriodicTransfers.Enabled = true;
1869 if (radInputOutputInterrupt.Checked)
1871 _transferType = TransferTypes.Interrupt;
1872 _reportType = ReportTypes.Output;
1874 else if (radInputOutputControl.Checked)
1876 _transferType = TransferTypes.Control;
1877 _reportType = ReportTypes.Output;
1879 else if (radFeature.Checked)
1881 _transferType = TransferTypes.Control;
1882 _reportType = ReportTypes.Feature;
1884 _periodicTransfersRequested = true;
1885 PeriodicTransfers();
1889 /// Stop doing periodic transfers.
1892 private void PeriodicTransfersStop()
1894 // Stop doing continuous transfers.
1896 _periodicTransfersRequested = false;
1898 // Disable the timer that triggers the transfers.
1900 _periodicTransfers.Stop();
1901 cmdPeriodicTransfers.Enabled = true;
1903 // Change the command button's text.
1905 cmdPeriodicTransfers.Text = "Start";
1907 // Re-allow changing the transfer type.
1909 radFeature.Enabled = true;
1910 radInputOutputControl.Enabled = true;
1911 radInputOutputInterrupt.Enabled = true;
1914 private void radInputOutputControl_CheckedChanged(object sender, EventArgs e)
1918 private void radInputOutputInterrupt_CheckedChanged(object sender, EventArgs e)
1922 private void radFeature_CheckedChanged(object sender, EventArgs e)
1927 /// Request a Feature report.
1928 /// Assumes report ID = 0.
1931 private void RequestToGetFeatureReport()
1933 String byteValue = null;
1937 // If the device hasn't been detected, was removed, or timed out on a previous attempt
1938 // to access it, look for the device.
1940 if (!_deviceHandleObtained)
1942 _deviceHandleObtained = FindTheHid();
1945 if (_deviceHandleObtained)
1947 Byte[] inFeatureReportBuffer = null;
1949 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
1951 // The HID has a Feature report.
1952 // Read a report from the device.
1954 // Set the size of the Feature report buffer.
1956 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
1958 inFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
1963 Boolean success = _myHid.GetFeatureReport(_hidHandle, ref inFeatureReportBuffer);
1967 DisplayReportData(inFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Read);
1971 CloseCommunications();
1972 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a Feature report failed.");
1973 ScrollToBottomOfListBox();
1978 MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
1979 ScrollToBottomOfListBox();
1982 _transferInProgress = false;
1983 cmdGetFeatureReport.Enabled = true;
1985 catch (Exception ex)
1987 DisplayException(Name, ex);
1993 /// Request an Input report.
1994 /// Assumes report ID = 0.
1997 private async void RequestToGetInputReport()
1999 const Int32 readTimeout = 5000;
2001 String byteValue = null;
2002 Byte[] inputReportBuffer = null;
2006 Boolean success = false;
2008 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2009 // to access it, look for the device.
2011 if (!_deviceHandleObtained)
2013 _deviceHandleObtained = FindTheHid();
2016 if (_deviceHandleObtained)
2018 // Don't attempt to exchange reports if valid handles aren't available
2019 // (as for a mouse or keyboard under Windows 2000 and later.)
2021 if (!_hidHandle.IsInvalid)
2023 // Read an Input report.
2025 // Don't attempt to send an Input report if the HID has no Input report.
2026 // (The HID spec requires all HIDs to have an interrupt IN endpoint,
2027 // which suggests that all HIDs must support Input reports.)
2029 if (_myHid.Capabilities.InputReportByteLength > 0)
2031 // Set the size of the Input report buffer.
2033 inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
2035 if (_transferType.Equals(TransferTypes.Control))
2038 _transferInProgress = true;
2040 // Read a report using a control transfer.
2042 success = _myHid.GetInputReportViaControlTransfer(_hidHandle, ref inputReportBuffer);
2043 cmdGetInputReportControl.Enabled = true;
2044 _transferInProgress = false;
2050 _transferInProgress = true;
2052 // Read a report using interrupt transfers.
2053 // Timeout if no report available.
2054 // To enable reading a report without blocking the calling thread, uses Filestream's ReadAsync method.
2056 // Create a delegate to execute on a timeout.
2058 Action onReadTimeoutAction = OnReadTimeout;
2060 // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
2062 var cts = new CancellationTokenSource();
2064 // Cancel the read if it hasn't completed after a timeout.
2066 cts.CancelAfter(readTimeout);
2068 // Specify the function to call on a timeout.
2070 cts.Token.Register(onReadTimeoutAction);
2072 // Stops waiting when data is available or on timeout:
2074 Int32 bytesRead = await _myHid.GetInputReportViaInterruptTransfer(_deviceData, inputReportBuffer, cts);
2076 // Arrive here only if the operation completed.
2078 // Dispose to stop the timeout timer.
2082 _transferInProgress = false;
2083 cmdGetInputReportInterrupt.Enabled = true;
2088 Debug.Print("bytes read (includes report ID) = " + Convert.ToString(bytesRead));
2095 MyMarshalDataToForm(FormActions.AddItemToListBox, "No attempt to read an Input report was made.");
2096 MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have an Input report.");
2101 MyMarshalDataToForm(FormActions.AddItemToListBox, "Invalid handle.");
2102 MyMarshalDataToForm(FormActions.AddItemToListBox,
2103 "No attempt to write an Output report or read an Input report was made.");
2108 DisplayReportData(inputReportBuffer, ReportTypes.Input, ReportReadOrWritten.Read);
2112 CloseCommunications();
2113 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read an Input report has failed.");
2114 ScrollToBottomOfListBox();
2118 catch (Exception ex)
2120 DisplayException(Name, ex);
2126 /// Sends a Feature report.
2127 /// Assumes report ID = 0.
2130 private void RequestToSendFeatureReport()
2132 String byteValue = null;
2136 _transferInProgress = true;
2138 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2139 // to access it, look for the device.
2141 if (!_deviceHandleObtained)
2143 _deviceHandleObtained = FindTheHid();
2146 if (_deviceHandleObtained)
2150 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
2152 // The HID has a Feature report.
2153 // Set the size of the Feature report buffer.
2155 var outFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
2157 // Store the report ID in the buffer.
2159 outFeatureReportBuffer[0] = 0;
2161 // Store the report data following the report ID.
2162 // Use the data in the combo boxes on the form.
2164 outFeatureReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
2166 if (outFeatureReportBuffer.GetUpperBound(0) > 1)
2168 outFeatureReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
2171 // Write a report to the device
2173 Boolean success = _myHid.SendFeatureReport(_hidHandle, outFeatureReportBuffer);
2177 DisplayReportData(outFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Written);
2181 CloseCommunications();
2182 AccessForm(FormActions.AddItemToListBox, "The attempt to send a Feature report failed.");
2183 ScrollToBottomOfListBox();
2188 AccessForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
2189 ScrollToBottomOfListBox();
2193 _transferInProgress = false;
2194 cmdSendFeatureReport.Enabled = true;
2195 ScrollToBottomOfListBox();
2198 catch (Exception ex)
2200 DisplayException(Name, ex);
2206 /// Sends an Output report.
2207 /// Assumes report ID = 0.
2210 private async void RequestToSendOutputReport()
2212 const Int32 writeTimeout = 5000;
2213 String byteValue = null;
2217 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2218 // to access it, look for the device.
2220 if (!_deviceHandleObtained)
2222 _deviceHandleObtained = FindTheHid();
2225 if (_deviceHandleObtained)
2229 // Don't attempt to exchange reports if valid handles aren't available
2230 // (as for a mouse or keyboard.)
2232 if (!_hidHandle.IsInvalid)
2234 // Don't attempt to send an Output report if the HID has no Output report.
2236 if (_myHid.Capabilities.OutputReportByteLength > 0)
2238 // Set the size of the Output report buffer.
2240 var outputReportBuffer = new Byte[_myHid.Capabilities.OutputReportByteLength];
2242 // Store the report ID in the first byte of the buffer:
2244 outputReportBuffer[0] = 0;
2246 // Store the report data following the report ID.
2247 // Use the data in the combo boxes on the form.
2249 outputReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
2251 if (outputReportBuffer.GetUpperBound(0) > 1)
2253 outputReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
2260 if (_transferType.Equals(TransferTypes.Control))
2263 _transferInProgress = true;
2265 // Use a control transfer to send the report,
2266 // even if the HID has an interrupt OUT endpoint.
2268 success = _myHid.SendOutputReportViaControlTransfer(_hidHandle, outputReportBuffer);
2270 _transferInProgress = false;
2271 cmdSendOutputReportControl.Enabled = true;
2276 Debug.Print("interrupt");
2277 _transferInProgress = true;
2279 // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
2281 var cts = new CancellationTokenSource();
2283 // Create a delegate to execute on a timeout.
2285 Action onWriteTimeoutAction = OnWriteTimeout;
2287 // Cancel the read if it hasn't completed after a timeout.
2289 cts.CancelAfter(writeTimeout);
2291 // Specify the function to call on a timeout.
2293 cts.Token.Register(onWriteTimeoutAction);
2295 // Send an Output report and wait for completion or timeout.
2297 success = await _myHid.SendOutputReportViaInterruptTransfer(_deviceData, _hidHandle, outputReportBuffer, cts);
2299 // Get here only if the operation completes without a timeout.
2301 _transferInProgress = false;
2302 cmdSendOutputReportInterrupt.Enabled = true;
2304 // Dispose to stop the timeout timer.
2310 DisplayReportData(outputReportBuffer, ReportTypes.Output, ReportReadOrWritten.Written);
2314 CloseCommunications();
2315 AccessForm(FormActions.AddItemToListBox, "The attempt to write an Output report failed.");
2316 ScrollToBottomOfListBox();
2322 AccessForm(FormActions.AddItemToListBox, "The HID doesn't have an Output report.");
2325 catch (Exception ex)
2327 DisplayException(Name, ex);
2333 /// Scroll to the bottom of the list box and trim as needed.
2336 private void ScrollToBottomOfListBox()
2340 LstResults.SelectedIndex = LstResults.Items.Count - 1;
2342 // If the list box is getting too large, trim its contents by removing the earliest data.
2344 if (LstResults.Items.Count > 1000)
2347 for (count = 1; count <= 500; count++)
2349 LstResults.Items.RemoveAt(4);
2353 catch (Exception ex)
2355 DisplayException(Name, ex);
2361 /// Request to send or get a Feature report.
2364 private void SendOrGetFeatureReport()
2368 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2369 // to access it, look for the device.
2371 if (!_deviceHandleObtained)
2373 _deviceHandleObtained = FindTheHid();
2376 if (_deviceHandleObtained)
2380 case SendOrGet.Send:
2381 RequestToSendFeatureReport();
2382 _sendOrGet = SendOrGet.Get;
2385 RequestToGetFeatureReport();
2386 _sendOrGet = SendOrGet.Send;
2391 catch (Exception ex)
2393 DisplayException(Name, ex);
2399 /// Request to send an Output report or get an Input report.
2402 private void SendOutputReportOrGetInputReport()
2406 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2407 // to access it, look for the device.
2409 if (!_deviceHandleObtained)
2411 _deviceHandleObtained = FindTheHid();
2414 if (_deviceHandleObtained)
2416 if (_sendOrGet == SendOrGet.Send)
2418 RequestToSendOutputReport();
2419 _sendOrGet = SendOrGet.Get;
2423 RequestToGetInputReport();
2424 _sendOrGet = SendOrGet.Send;
2428 catch (Exception ex)
2430 DisplayException(Name, ex);
2436 /// Set the number of Input buffers (the number of Input reports
2437 /// the host will store) from the value in the text box.
2440 private void SetInputReportBufferSize()
2444 if (!_transferInProgress)
2446 // Get the number of buffers from the text box.
2448 Int32 numberOfInputBuffers = Convert.ToInt32(txtInputReportBufferSize.Text);
2450 // Set the number of buffers.
2452 _myHid.SetNumberOfInputBuffers(_hidHandle, numberOfInputBuffers);
2454 // Verify and display the result.
2456 GetInputReportBufferSize();
2460 DisplayTransferInProgressMessage();
2463 catch (Exception ex)
2465 DisplayException(Name, ex);
2471 /// Perform actions that must execute when the program ends.
2474 private void Shutdown()
2478 CloseCommunications();
2479 DeviceNotificationsStop();
2481 catch (Exception ex)
2483 DisplayException(Name, ex);
2489 /// Perform actions that must execute when the program starts.
2492 private void Startup()
2494 const Int32 periodicTransferInterval = 1000;
2498 InitializeDisplay();
2500 _periodicTransfers = new System.Timers.Timer(periodicTransferInterval);
2501 _periodicTransfers.Elapsed += DoPeriodicTransfers;
2502 _periodicTransfers.Stop();
2503 _periodicTransfers.SynchronizingObject = this;
2505 // Default USB Vendor ID and Product ID:
2507 txtVendorID.Text = "0925";
2508 txtProductID.Text = "7001";
2510 GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
2512 DeviceNotificationsStart();
2513 FindDeviceUsingWmi();
2516 catch (Exception ex)
2518 DisplayException(Name, ex);
2524 /// The Product ID has changed in the text box. Call a routine to handle it.
2527 private void txtProductID_TextChanged(Object sender, EventArgs e)
2533 catch (Exception ex)
2535 DisplayException(Name, ex);
2541 /// The Vendor ID has changed in the text box. Call a routine to handle it.
2544 private void txtVendorID_TextChanged(Object sender, EventArgs e)
2550 catch (Exception ex)
2552 DisplayException(Name, ex);
2558 /// Provides a central mechanism for exception handling.
2559 /// Displays a message box that describes the exception.
2562 /// <param name="moduleName"> the module where the exception occurred. </param>
2563 /// <param name="e"> the exception </param>
2565 internal static void DisplayException(String moduleName, Exception e)
2567 // Create an error message.
2569 String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
2571 const String caption = "Unexpected Exception";
2573 MessageBox.Show(message, caption, MessageBoxButtons.OK);
2574 Debug.Write(message);
2576 // Get the last error and display it.
2578 Int32 error = Marshal.GetLastWin32Error();
2580 Debug.WriteLine("The last Win32 Error was: " + error);
2584 internal static void Main() { Application.Run(new FrmMain()); }
2585 private static FrmMain _transDefaultFormFrmMain;
2586 internal static FrmMain TransDefaultFormFrmMain
2590 if (_transDefaultFormFrmMain == null)
2592 _transDefaultFormFrmMain = new FrmMain();
2594 return _transDefaultFormFrmMain;