Adding TreeView to display our 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;
11 using System.Collections.Generic;
17 /// Project: GenericHid
19 /// ***********************************************************************
20 /// Software License Agreement
22 /// Licensor grants any person obtaining a copy of this software ("You")
23 /// a worldwide, royalty-free, non-exclusive license, for the duration of
24 /// the copyright, free of charge, to store and execute the Software in a
25 /// computer system and to incorporate the Software or any portion of it
26 /// in computer programs You write.
28 /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33 /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 /// ***********************************************************************
40 /// This software was written using Visual Studio Express 2012 for Windows
41 /// Desktop building for the .NET Framework v4.5.
44 /// Demonstrates USB communications with a generic HID-class device
47 /// Windows Vista or later and an attached USB generic Human Interface Device (HID).
48 /// (Does not run on Windows XP or earlier because .NET Framework 4.5 will not install on these OSes.)
51 /// Finds an attached device that matches the vendor and product IDs in the form's
54 /// Retrieves the device's capabilities.
55 /// Sends and requests HID reports.
57 /// Uses the System.Management class and Windows Management Instrumentation (WMI) to detect
58 /// when a device is attached or removed.
60 /// A list box displays the data sent and received along with error and status messages.
61 /// You can select data to send and 1-time or periodic transfers.
63 /// You can change the size of the host's Input report buffer and request to use control
64 /// transfers only to exchange Input and Output reports.
66 /// To view additional debugging messages, in the Visual Studio development environment,
67 /// from the main menu, select Build > Configuration Manager > Active Solution Configuration
68 /// and select Configuration > Debug and from the main menu, select View > Output.
70 /// The application uses asynchronous FileStreams to read Input reports and write Output
71 /// reports so the application's main thread doesn't have to wait for the device to retrieve a
72 /// report when the HID driver's buffer is empty or send a report when the device's endpoint is busy.
74 /// For code that finds a device and opens handles to it, see the FindTheHid routine in frmMain.cs.
75 /// For code that reads from the device, see GetInputReportViaInterruptTransfer,
76 /// GetInputReportViaControlTransfer, and GetFeatureReport in Hid.cs.
77 /// For code that writes to the device, see SendInputReportViaInterruptTransfer,
78 /// SendInputReportViaControlTransfer, and SendFeatureReport in Hid.cs.
80 /// This project includes the following modules:
82 /// GenericHid.cs - runs the application.
83 /// FrmMain.cs - routines specific to the form.
84 /// Hid.cs - routines specific to HID communications.
85 /// DeviceManagement.cs - routine for obtaining a handle to a device from its GUID.
86 /// Debugging.cs - contains a routine for displaying API error messages.
87 /// HidDeclarations.cs - Declarations for API functions used by Hid.cs.
88 /// FileIODeclarations.cs - Declarations for file-related API functions.
89 /// DeviceManagementDeclarations.cs - Declarations for API functions used by DeviceManagement.cs.
90 /// DebuggingDeclarations.cs - Declarations for API functions used by Debugging.cs.
92 /// Companion device firmware for several device CPUs is available from www.Lvr.com/hidpage.htm
93 /// You can use any generic HID (not a system mouse or keyboard) that sends and receives reports.
94 /// This application will not detect or communicate with non-HID-class devices.
96 /// For more information about HIDs and USB, and additional example device firmware to use
97 /// with this application, visit Lakeview Research at http://Lvr.com
98 /// Send comments, bug reports, etc. to jan@Lvr.com or post on my PORTS forum: http://www.lvr.com/forum
102 /// Disabled form buttons when a transfer is in progress.
103 /// Other minor edits for clarity and readability.
104 /// Will NOT run on Windows XP or earlier, see below.
108 /// Uses the .NET System.Management class to detect device arrival and removal with WMI instead of Win32 RegisterDeviceNotification.
109 /// Other minor edits.
110 /// Will NOT run on Windows XP or earlier, see below.
114 /// This version will NOT run on Windows XP or earlier because the code uses .NET Framework 4.5 to support asynchronous FileStreams.
115 /// The .NET Framework 4.5 redistributable is compatible with Windows 8, Windows 7 SP1, Windows Server 2008 R2 SP1,
116 /// Windows Server 2008 SP2, Windows Vista SP2, and Windows Vista SP3.
117 /// For compatibility, replaced ToInt32 with ToInt64 here:
118 /// IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
120 /// if ((deviceNotificationHandle.ToInt64() == IntPtr.Zero.ToInt64()))
121 /// For compatibility if the charset isn't English, added System.Globalization.CultureInfo.InvariantCulture here:
122 /// if ((String.Compare(DeviceNameString, mydevicePathName, true, System.Globalization.CultureInfo.InvariantCulture) == 0))
123 /// Replaced all Microsoft.VisualBasic namespace code with other .NET equivalents.
124 /// Revised user interface for more flexibility.
125 /// Moved interrupt-transfer and other HID-specific code to Hid.cs.
126 /// Used JetBrains ReSharper to clean up the code: http://www.jetbrains.com/resharper/
130 /// Replaced ReadFile and WriteFile with FileStreams. Thanks to Joe Dunne and John on my Ports forum for tips on this.
131 /// Simplified Hid.cs.
132 /// Replaced the form timer with a system timer.
136 /// Supports Vendor IDs and Product IDs up to FFFFh.
140 /// Changed HIDD_ATTRIBUTES to use UInt16
144 /// Moved Free_ and similar to Finally blocks to ensure they execute.
148 /// Changes to support 64-bit systems, memory management, and other corrections.
149 /// Big thanks to Peter Nielsen.
153 internal class FrmMain
156 #region '"Windows Form Designer generated code "'
160 // This call is required by the Windows Form Designer.
161 InitializeComponent();
163 // Form overrides dispose to clean up the component list.
164 protected override void Dispose(bool Disposing1)
168 if (components != null)
170 components.Dispose();
173 base.Dispose(Disposing1);
176 // Required by the Windows Form Designer
177 private System.ComponentModel.IContainer components;
178 public System.Windows.Forms.ToolTip ToolTip1;
179 public System.Windows.Forms.TextBox TxtBytesReceived;
180 public System.Windows.Forms.GroupBox FraBytesReceived;
181 public System.Windows.Forms.CheckBox ChkAutoincrement;
182 public System.Windows.Forms.ComboBox CboByte1;
183 public System.Windows.Forms.ComboBox CboByte0;
184 public System.Windows.Forms.GroupBox FraBytesToSend;
185 public System.Windows.Forms.ListBox LstResults;
186 // NOTE: The following procedure is required by the Windows Form Designer
187 // It can be modified using the Windows Form Designer.
188 // Do not modify it using the code editor.
189 internal System.Windows.Forms.GroupBox fraInputReportBufferSize;
190 internal System.Windows.Forms.TextBox txtInputReportBufferSize;
191 internal System.Windows.Forms.Button cmdInputReportBufferSize;
192 internal System.Windows.Forms.GroupBox fraDeviceIdentifiers;
193 internal System.Windows.Forms.Label lblVendorID;
194 internal System.Windows.Forms.TextBox txtVendorID;
195 internal System.Windows.Forms.Label lblProductID;
196 internal System.Windows.Forms.TextBox txtProductID;
197 internal System.Windows.Forms.Button cmdFindDevice;
198 private Button cmdGetInputReportInterrupt;
199 public GroupBox fraInterruptTransfers;
200 private Button cmdSendOutputReportControl;
201 private Button cmdGetInputReportControl;
202 public GroupBox fraControlTransfers;
203 private Button cmdGetFeatureReport;
204 private Button cmdSendFeatureReport;
205 private Button cmdPeriodicTransfers;
206 public GroupBox fraSendAndGetContinuous;
207 private RadioButton radFeature;
208 private RadioButton radInputOutputControl;
209 private RadioButton radInputOutputInterrupt;
210 private TreeView treeViewDevices;
211 private Button cmdSendOutputReportInterrupt;
213 [System.Diagnostics.DebuggerStepThrough()]
214 private void InitializeComponent()
216 this.components = new System.ComponentModel.Container();
217 this.ToolTip1 = new System.Windows.Forms.ToolTip(this.components);
218 this.FraBytesReceived = new System.Windows.Forms.GroupBox();
219 this.TxtBytesReceived = new System.Windows.Forms.TextBox();
220 this.FraBytesToSend = new System.Windows.Forms.GroupBox();
221 this.ChkAutoincrement = new System.Windows.Forms.CheckBox();
222 this.CboByte1 = new System.Windows.Forms.ComboBox();
223 this.CboByte0 = new System.Windows.Forms.ComboBox();
224 this.LstResults = new System.Windows.Forms.ListBox();
225 this.fraInputReportBufferSize = new System.Windows.Forms.GroupBox();
226 this.cmdInputReportBufferSize = new System.Windows.Forms.Button();
227 this.txtInputReportBufferSize = new System.Windows.Forms.TextBox();
228 this.fraDeviceIdentifiers = new System.Windows.Forms.GroupBox();
229 this.txtProductID = new System.Windows.Forms.TextBox();
230 this.lblProductID = new System.Windows.Forms.Label();
231 this.txtVendorID = new System.Windows.Forms.TextBox();
232 this.lblVendorID = new System.Windows.Forms.Label();
233 this.cmdFindDevice = new System.Windows.Forms.Button();
234 this.cmdSendOutputReportInterrupt = new System.Windows.Forms.Button();
235 this.cmdGetInputReportInterrupt = new System.Windows.Forms.Button();
236 this.fraInterruptTransfers = new System.Windows.Forms.GroupBox();
237 this.cmdPeriodicTransfers = new System.Windows.Forms.Button();
238 this.cmdSendOutputReportControl = new System.Windows.Forms.Button();
239 this.cmdGetInputReportControl = new System.Windows.Forms.Button();
240 this.fraControlTransfers = new System.Windows.Forms.GroupBox();
241 this.cmdGetFeatureReport = new System.Windows.Forms.Button();
242 this.cmdSendFeatureReport = new System.Windows.Forms.Button();
243 this.fraSendAndGetContinuous = new System.Windows.Forms.GroupBox();
244 this.radFeature = new System.Windows.Forms.RadioButton();
245 this.radInputOutputControl = new System.Windows.Forms.RadioButton();
246 this.radInputOutputInterrupt = new System.Windows.Forms.RadioButton();
247 this.treeViewDevices = new System.Windows.Forms.TreeView();
248 this.FraBytesReceived.SuspendLayout();
249 this.FraBytesToSend.SuspendLayout();
250 this.fraInputReportBufferSize.SuspendLayout();
251 this.fraDeviceIdentifiers.SuspendLayout();
252 this.fraInterruptTransfers.SuspendLayout();
253 this.fraControlTransfers.SuspendLayout();
254 this.fraSendAndGetContinuous.SuspendLayout();
255 this.SuspendLayout();
259 this.FraBytesReceived.BackColor = System.Drawing.SystemColors.Control;
260 this.FraBytesReceived.Controls.Add(this.TxtBytesReceived);
261 this.FraBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
262 this.FraBytesReceived.ForeColor = System.Drawing.SystemColors.ControlText;
263 this.FraBytesReceived.Location = new System.Drawing.Point(495, 353);
264 this.FraBytesReceived.Name = "FraBytesReceived";
265 this.FraBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
266 this.FraBytesReceived.Size = new System.Drawing.Size(112, 136);
267 this.FraBytesReceived.TabIndex = 4;
268 this.FraBytesReceived.TabStop = false;
269 this.FraBytesReceived.Text = "Bytes Received";
273 this.TxtBytesReceived.AcceptsReturn = true;
274 this.TxtBytesReceived.BackColor = System.Drawing.SystemColors.Window;
275 this.TxtBytesReceived.Cursor = System.Windows.Forms.Cursors.IBeam;
276 this.TxtBytesReceived.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
277 this.TxtBytesReceived.ForeColor = System.Drawing.SystemColors.WindowText;
278 this.TxtBytesReceived.Location = new System.Drawing.Point(18, 24);
279 this.TxtBytesReceived.MaxLength = 0;
280 this.TxtBytesReceived.Multiline = true;
281 this.TxtBytesReceived.Name = "TxtBytesReceived";
282 this.TxtBytesReceived.RightToLeft = System.Windows.Forms.RightToLeft.No;
283 this.TxtBytesReceived.Size = new System.Drawing.Size(72, 96);
284 this.TxtBytesReceived.TabIndex = 5;
288 this.FraBytesToSend.BackColor = System.Drawing.SystemColors.Control;
289 this.FraBytesToSend.Controls.Add(this.ChkAutoincrement);
290 this.FraBytesToSend.Controls.Add(this.CboByte1);
291 this.FraBytesToSend.Controls.Add(this.CboByte0);
292 this.FraBytesToSend.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
293 this.FraBytesToSend.ForeColor = System.Drawing.SystemColors.ControlText;
294 this.FraBytesToSend.Location = new System.Drawing.Point(612, 235);
295 this.FraBytesToSend.Name = "FraBytesToSend";
296 this.FraBytesToSend.RightToLeft = System.Windows.Forms.RightToLeft.No;
297 this.FraBytesToSend.Size = new System.Drawing.Size(160, 136);
298 this.FraBytesToSend.TabIndex = 1;
299 this.FraBytesToSend.TabStop = false;
300 this.FraBytesToSend.Text = "Bytes to Send";
304 this.ChkAutoincrement.BackColor = System.Drawing.SystemColors.Control;
305 this.ChkAutoincrement.Cursor = System.Windows.Forms.Cursors.Default;
306 this.ChkAutoincrement.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
307 this.ChkAutoincrement.ForeColor = System.Drawing.SystemColors.ControlText;
308 this.ChkAutoincrement.Location = new System.Drawing.Point(8, 96);
309 this.ChkAutoincrement.Name = "ChkAutoincrement";
310 this.ChkAutoincrement.RightToLeft = System.Windows.Forms.RightToLeft.No;
311 this.ChkAutoincrement.Size = new System.Drawing.Size(201, 35);
312 this.ChkAutoincrement.TabIndex = 6;
313 this.ChkAutoincrement.Text = "Autoincrement values";
314 this.ChkAutoincrement.UseVisualStyleBackColor = false;
318 this.CboByte1.BackColor = System.Drawing.SystemColors.Window;
319 this.CboByte1.Cursor = System.Windows.Forms.Cursors.Default;
320 this.CboByte1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
321 this.CboByte1.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
322 this.CboByte1.ForeColor = System.Drawing.SystemColors.WindowText;
323 this.CboByte1.Location = new System.Drawing.Point(8, 64);
324 this.CboByte1.Name = "CboByte1";
325 this.CboByte1.RightToLeft = System.Windows.Forms.RightToLeft.No;
326 this.CboByte1.Size = new System.Drawing.Size(101, 22);
327 this.CboByte1.TabIndex = 3;
331 this.CboByte0.BackColor = System.Drawing.SystemColors.Window;
332 this.CboByte0.Cursor = System.Windows.Forms.Cursors.Default;
333 this.CboByte0.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
334 this.CboByte0.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
335 this.CboByte0.ForeColor = System.Drawing.SystemColors.WindowText;
336 this.CboByte0.Location = new System.Drawing.Point(8, 24);
337 this.CboByte0.Name = "CboByte0";
338 this.CboByte0.RightToLeft = System.Windows.Forms.RightToLeft.No;
339 this.CboByte0.Size = new System.Drawing.Size(101, 22);
340 this.CboByte0.TabIndex = 2;
344 this.LstResults.BackColor = System.Drawing.SystemColors.Window;
345 this.LstResults.Cursor = System.Windows.Forms.Cursors.Default;
346 this.LstResults.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
347 this.LstResults.ForeColor = System.Drawing.SystemColors.WindowText;
348 this.LstResults.HorizontalScrollbar = true;
349 this.LstResults.ItemHeight = 14;
350 this.LstResults.Location = new System.Drawing.Point(12, 494);
351 this.LstResults.Name = "LstResults";
352 this.LstResults.RightToLeft = System.Windows.Forms.RightToLeft.No;
353 this.LstResults.Size = new System.Drawing.Size(760, 256);
354 this.LstResults.TabIndex = 0;
356 // fraInputReportBufferSize
358 this.fraInputReportBufferSize.Controls.Add(this.cmdInputReportBufferSize);
359 this.fraInputReportBufferSize.Controls.Add(this.txtInputReportBufferSize);
360 this.fraInputReportBufferSize.Location = new System.Drawing.Point(623, 44);
361 this.fraInputReportBufferSize.Name = "fraInputReportBufferSize";
362 this.fraInputReportBufferSize.Size = new System.Drawing.Size(149, 79);
363 this.fraInputReportBufferSize.TabIndex = 9;
364 this.fraInputReportBufferSize.TabStop = false;
365 this.fraInputReportBufferSize.Text = "Input Report Buffer Size";
367 // cmdInputReportBufferSize
369 this.cmdInputReportBufferSize.Location = new System.Drawing.Point(6, 47);
370 this.cmdInputReportBufferSize.Name = "cmdInputReportBufferSize";
371 this.cmdInputReportBufferSize.Size = new System.Drawing.Size(136, 26);
372 this.cmdInputReportBufferSize.TabIndex = 1;
373 this.cmdInputReportBufferSize.Text = "Change Buffer Size";
374 this.cmdInputReportBufferSize.Click += new System.EventHandler(this.cmdInputReportBufferSize_Click);
376 // txtInputReportBufferSize
378 this.txtInputReportBufferSize.Location = new System.Drawing.Point(6, 21);
379 this.txtInputReportBufferSize.Name = "txtInputReportBufferSize";
380 this.txtInputReportBufferSize.Size = new System.Drawing.Size(56, 20);
381 this.txtInputReportBufferSize.TabIndex = 0;
383 // fraDeviceIdentifiers
385 this.fraDeviceIdentifiers.Controls.Add(this.txtProductID);
386 this.fraDeviceIdentifiers.Controls.Add(this.lblProductID);
387 this.fraDeviceIdentifiers.Controls.Add(this.txtVendorID);
388 this.fraDeviceIdentifiers.Controls.Add(this.lblVendorID);
389 this.fraDeviceIdentifiers.Location = new System.Drawing.Point(409, 12);
390 this.fraDeviceIdentifiers.Name = "fraDeviceIdentifiers";
391 this.fraDeviceIdentifiers.Size = new System.Drawing.Size(208, 96);
392 this.fraDeviceIdentifiers.TabIndex = 10;
393 this.fraDeviceIdentifiers.TabStop = false;
394 this.fraDeviceIdentifiers.Text = "Device Identifiers";
398 this.txtProductID.Location = new System.Drawing.Point(120, 56);
399 this.txtProductID.Name = "txtProductID";
400 this.txtProductID.Size = new System.Drawing.Size(72, 20);
401 this.txtProductID.TabIndex = 3;
402 this.txtProductID.Text = "1299";
403 this.txtProductID.TextChanged += new System.EventHandler(this.txtProductID_TextChanged);
407 this.lblProductID.Location = new System.Drawing.Point(16, 56);
408 this.lblProductID.Name = "lblProductID";
409 this.lblProductID.Size = new System.Drawing.Size(112, 23);
410 this.lblProductID.TabIndex = 2;
411 this.lblProductID.Text = "Product ID (hex):";
415 this.txtVendorID.Location = new System.Drawing.Point(120, 24);
416 this.txtVendorID.Name = "txtVendorID";
417 this.txtVendorID.Size = new System.Drawing.Size(72, 20);
418 this.txtVendorID.TabIndex = 1;
419 this.txtVendorID.Text = "0925";
420 this.txtVendorID.TextChanged += new System.EventHandler(this.txtVendorID_TextChanged);
424 this.lblVendorID.Location = new System.Drawing.Point(16, 24);
425 this.lblVendorID.Name = "lblVendorID";
426 this.lblVendorID.Size = new System.Drawing.Size(112, 23);
427 this.lblVendorID.TabIndex = 0;
428 this.lblVendorID.Text = "Vendor ID (hex):";
432 this.cmdFindDevice.Location = new System.Drawing.Point(636, 12);
433 this.cmdFindDevice.Name = "cmdFindDevice";
434 this.cmdFindDevice.Size = new System.Drawing.Size(136, 26);
435 this.cmdFindDevice.TabIndex = 11;
436 this.cmdFindDevice.Text = "Find My Device";
437 this.cmdFindDevice.Click += new System.EventHandler(this.cmdFindDevice_Click);
439 // cmdSendOutputReportInterrupt
441 this.cmdSendOutputReportInterrupt.Location = new System.Drawing.Point(21, 27);
442 this.cmdSendOutputReportInterrupt.Name = "cmdSendOutputReportInterrupt";
443 this.cmdSendOutputReportInterrupt.Size = new System.Drawing.Size(118, 26);
444 this.cmdSendOutputReportInterrupt.TabIndex = 12;
445 this.cmdSendOutputReportInterrupt.Text = "Send Output Report";
446 this.cmdSendOutputReportInterrupt.UseVisualStyleBackColor = true;
447 this.cmdSendOutputReportInterrupt.Click += new System.EventHandler(this.cmdSendOutputReportInterrupt_Click);
449 // cmdGetInputReportInterrupt
451 this.cmdGetInputReportInterrupt.Location = new System.Drawing.Point(21, 60);
452 this.cmdGetInputReportInterrupt.Name = "cmdGetInputReportInterrupt";
453 this.cmdGetInputReportInterrupt.Size = new System.Drawing.Size(118, 26);
454 this.cmdGetInputReportInterrupt.TabIndex = 13;
455 this.cmdGetInputReportInterrupt.Text = "Get Input Report";
456 this.cmdGetInputReportInterrupt.UseVisualStyleBackColor = true;
457 this.cmdGetInputReportInterrupt.Click += new System.EventHandler(this.cmdGetInputReportInterrupt_Click);
459 // fraInterruptTransfers
461 this.fraInterruptTransfers.BackColor = System.Drawing.SystemColors.Control;
462 this.fraInterruptTransfers.Controls.Add(this.cmdSendOutputReportInterrupt);
463 this.fraInterruptTransfers.Controls.Add(this.cmdGetInputReportInterrupt);
464 this.fraInterruptTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
465 this.fraInterruptTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
466 this.fraInterruptTransfers.Location = new System.Drawing.Point(338, 129);
467 this.fraInterruptTransfers.Name = "fraInterruptTransfers";
468 this.fraInterruptTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
469 this.fraInterruptTransfers.Size = new System.Drawing.Size(151, 100);
470 this.fraInterruptTransfers.TabIndex = 14;
471 this.fraInterruptTransfers.TabStop = false;
472 this.fraInterruptTransfers.Text = "Interrupt Transfers";
474 // cmdPeriodicTransfers
476 this.cmdPeriodicTransfers.Location = new System.Drawing.Point(153, 36);
477 this.cmdPeriodicTransfers.Name = "cmdPeriodicTransfers";
478 this.cmdPeriodicTransfers.Size = new System.Drawing.Size(118, 26);
479 this.cmdPeriodicTransfers.TabIndex = 16;
480 this.cmdPeriodicTransfers.Text = "Start";
481 this.cmdPeriodicTransfers.UseVisualStyleBackColor = true;
482 this.cmdPeriodicTransfers.Click += new System.EventHandler(this.cmdPeriodicTransfers_Click);
484 // cmdSendOutputReportControl
486 this.cmdSendOutputReportControl.Location = new System.Drawing.Point(10, 27);
487 this.cmdSendOutputReportControl.Name = "cmdSendOutputReportControl";
488 this.cmdSendOutputReportControl.Size = new System.Drawing.Size(118, 26);
489 this.cmdSendOutputReportControl.TabIndex = 12;
490 this.cmdSendOutputReportControl.Text = "Send Output Report";
491 this.cmdSendOutputReportControl.UseVisualStyleBackColor = true;
492 this.cmdSendOutputReportControl.Click += new System.EventHandler(this.cmdSendOutputReportControl_Click);
494 // cmdGetInputReportControl
496 this.cmdGetInputReportControl.Location = new System.Drawing.Point(10, 60);
497 this.cmdGetInputReportControl.Name = "cmdGetInputReportControl";
498 this.cmdGetInputReportControl.Size = new System.Drawing.Size(118, 26);
499 this.cmdGetInputReportControl.TabIndex = 13;
500 this.cmdGetInputReportControl.Text = "Get Input Report";
501 this.cmdGetInputReportControl.UseVisualStyleBackColor = true;
502 this.cmdGetInputReportControl.Click += new System.EventHandler(this.cmdGetInputReportControl_Click);
504 // fraControlTransfers
506 this.fraControlTransfers.BackColor = System.Drawing.SystemColors.Control;
507 this.fraControlTransfers.Controls.Add(this.cmdGetFeatureReport);
508 this.fraControlTransfers.Controls.Add(this.cmdSendFeatureReport);
509 this.fraControlTransfers.Controls.Add(this.cmdSendOutputReportControl);
510 this.fraControlTransfers.Controls.Add(this.cmdGetInputReportControl);
511 this.fraControlTransfers.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
512 this.fraControlTransfers.ForeColor = System.Drawing.SystemColors.ControlText;
513 this.fraControlTransfers.Location = new System.Drawing.Point(495, 129);
514 this.fraControlTransfers.Name = "fraControlTransfers";
515 this.fraControlTransfers.RightToLeft = System.Windows.Forms.RightToLeft.No;
516 this.fraControlTransfers.Size = new System.Drawing.Size(277, 100);
517 this.fraControlTransfers.TabIndex = 15;
518 this.fraControlTransfers.TabStop = false;
519 this.fraControlTransfers.Text = "Control Transfers";
521 // cmdGetFeatureReport
523 this.cmdGetFeatureReport.Location = new System.Drawing.Point(141, 60);
524 this.cmdGetFeatureReport.Name = "cmdGetFeatureReport";
525 this.cmdGetFeatureReport.Size = new System.Drawing.Size(118, 26);
526 this.cmdGetFeatureReport.TabIndex = 15;
527 this.cmdGetFeatureReport.Text = "Get Feature Report";
528 this.cmdGetFeatureReport.UseVisualStyleBackColor = true;
529 this.cmdGetFeatureReport.Click += new System.EventHandler(this.cmdGetFeatureReport_Click);
531 // cmdSendFeatureReport
533 this.cmdSendFeatureReport.Location = new System.Drawing.Point(141, 27);
534 this.cmdSendFeatureReport.Name = "cmdSendFeatureReport";
535 this.cmdSendFeatureReport.Size = new System.Drawing.Size(118, 26);
536 this.cmdSendFeatureReport.TabIndex = 14;
537 this.cmdSendFeatureReport.Text = "Send Feature Report";
538 this.cmdSendFeatureReport.UseVisualStyleBackColor = true;
539 this.cmdSendFeatureReport.Click += new System.EventHandler(this.cmdSendFeatureReport_Click);
541 // fraSendAndGetContinuous
543 this.fraSendAndGetContinuous.BackColor = System.Drawing.SystemColors.Control;
544 this.fraSendAndGetContinuous.Controls.Add(this.radFeature);
545 this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputControl);
546 this.fraSendAndGetContinuous.Controls.Add(this.radInputOutputInterrupt);
547 this.fraSendAndGetContinuous.Controls.Add(this.cmdPeriodicTransfers);
548 this.fraSendAndGetContinuous.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
549 this.fraSendAndGetContinuous.ForeColor = System.Drawing.SystemColors.ControlText;
550 this.fraSendAndGetContinuous.Location = new System.Drawing.Point(311, 235);
551 this.fraSendAndGetContinuous.Name = "fraSendAndGetContinuous";
552 this.fraSendAndGetContinuous.RightToLeft = System.Windows.Forms.RightToLeft.No;
553 this.fraSendAndGetContinuous.Size = new System.Drawing.Size(295, 112);
554 this.fraSendAndGetContinuous.TabIndex = 17;
555 this.fraSendAndGetContinuous.TabStop = false;
556 this.fraSendAndGetContinuous.Text = "Send and Get Continuous";
560 this.radFeature.AutoSize = true;
561 this.radFeature.Location = new System.Drawing.Point(17, 76);
562 this.radFeature.Name = "radFeature";
563 this.radFeature.Size = new System.Drawing.Size(62, 18);
564 this.radFeature.TabIndex = 19;
565 this.radFeature.TabStop = true;
566 this.radFeature.Text = "Feature";
567 this.radFeature.UseVisualStyleBackColor = true;
568 this.radFeature.CheckedChanged += new System.EventHandler(this.radFeature_CheckedChanged);
570 // radInputOutputControl
572 this.radInputOutputControl.AutoSize = true;
573 this.radInputOutputControl.Location = new System.Drawing.Point(17, 52);
574 this.radInputOutputControl.Name = "radInputOutputControl";
575 this.radInputOutputControl.Size = new System.Drawing.Size(120, 18);
576 this.radInputOutputControl.TabIndex = 18;
577 this.radInputOutputControl.TabStop = true;
578 this.radInputOutputControl.Text = "Input Output Control";
579 this.radInputOutputControl.UseVisualStyleBackColor = true;
580 this.radInputOutputControl.CheckedChanged += new System.EventHandler(this.radInputOutputControl_CheckedChanged);
582 // radInputOutputInterrupt
584 this.radInputOutputInterrupt.AutoSize = true;
585 this.radInputOutputInterrupt.Location = new System.Drawing.Point(17, 28);
586 this.radInputOutputInterrupt.Name = "radInputOutputInterrupt";
587 this.radInputOutputInterrupt.Size = new System.Drawing.Size(126, 18);
588 this.radInputOutputInterrupt.TabIndex = 17;
589 this.radInputOutputInterrupt.TabStop = true;
590 this.radInputOutputInterrupt.Text = "Input Output Interrupt";
591 this.radInputOutputInterrupt.UseVisualStyleBackColor = true;
592 this.radInputOutputInterrupt.CheckedChanged += new System.EventHandler(this.radInputOutputInterrupt_CheckedChanged);
596 this.treeViewDevices.Location = new System.Drawing.Point(12, 12);
597 this.treeViewDevices.Name = "treeViewDevices";
598 this.treeViewDevices.Size = new System.Drawing.Size(284, 461);
599 this.treeViewDevices.TabIndex = 18;
603 this.ClientSize = new System.Drawing.Size(784, 756);
604 this.Controls.Add(this.treeViewDevices);
605 this.Controls.Add(this.fraSendAndGetContinuous);
606 this.Controls.Add(this.fraControlTransfers);
607 this.Controls.Add(this.fraInterruptTransfers);
608 this.Controls.Add(this.cmdFindDevice);
609 this.Controls.Add(this.fraDeviceIdentifiers);
610 this.Controls.Add(this.fraInputReportBufferSize);
611 this.Controls.Add(this.FraBytesReceived);
612 this.Controls.Add(this.FraBytesToSend);
613 this.Controls.Add(this.LstResults);
614 this.Font = new System.Drawing.Font("Arial", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
615 this.Location = new System.Drawing.Point(21, 28);
616 this.Name = "FrmMain";
617 this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
618 this.Text = "Generic HID Tester";
619 this.Closed += new System.EventHandler(this.frmMain_Closed);
620 this.Load += new System.EventHandler(this.frmMain_Load);
621 this.FraBytesReceived.ResumeLayout(false);
622 this.FraBytesReceived.PerformLayout();
623 this.FraBytesToSend.ResumeLayout(false);
624 this.fraInputReportBufferSize.ResumeLayout(false);
625 this.fraInputReportBufferSize.PerformLayout();
626 this.fraDeviceIdentifiers.ResumeLayout(false);
627 this.fraDeviceIdentifiers.PerformLayout();
628 this.fraInterruptTransfers.ResumeLayout(false);
629 this.fraControlTransfers.ResumeLayout(false);
630 this.fraSendAndGetContinuous.ResumeLayout(false);
631 this.fraSendAndGetContinuous.PerformLayout();
632 this.ResumeLayout(false);
635 #endregion '"Windows Form Designer generated code "'
637 private Boolean _deviceDetected;
638 private IntPtr _deviceNotificationHandle;
639 private FileStream _deviceData;
640 private FormActions _formActions;
641 private SafeFileHandle _hidHandle;
642 private String _hidUsage;
643 private ManagementEventWatcher _deviceArrivedWatcher;
644 private Boolean _deviceHandleObtained;
645 private ManagementEventWatcher _deviceRemovedWatcher;
646 private Int32 _myProductId;
647 private Int32 _myVendorId;
648 private Boolean _periodicTransfersRequested;
649 private ReportReadOrWritten _readOrWritten;
650 private ReportTypes _reportType;
651 private SendOrGet _sendOrGet;
652 private Boolean _transferInProgress;
653 private TransferTypes _transferType;
655 private static System.Timers.Timer _periodicTransfers;
657 private readonly Debugging _myDebugging = new Debugging(); // For viewing results of API calls via Debug.Write.
658 private readonly DeviceManagement _myDeviceManagement = new DeviceManagement();
659 private Hid _myHid = new Hid();
661 private enum FormActions
664 DisableInputReportBufferSize,
665 EnableGetInputReportInterruptTransfer,
666 EnableInputReportBufferSize,
667 EnableSendOutputReportInterrupt,
668 ScrollToBottomOfListBox,
669 SetInputReportBufferSize,
672 SelectDeviceInTreeView
675 private enum ReportReadOrWritten
681 private enum ReportTypes
688 private enum SendOrGet
694 private enum TransferTypes
700 private enum WmiDeviceProperties
711 internal FrmMain FrmMy;
713 // This delegate has the same parameters as AccessForm.
714 // Used in accessing the application's form from a different thread.
716 private delegate void MarshalDataToForm(FormActions action, params string[] strings);
719 /// Performs various application-specific functions that
720 /// involve accessing the application's form.
723 /// <param name="action"> a FormActions member that names the action to perform on the form</param>
724 /// <param name="formText"> text that the form displays or the code uses for
725 /// another purpose. Actions that don't use text ignore this parameter. </param>
727 private void AccessForm(FormActions action, params string[] strings)
731 // Select an action to perform on the form:
735 case FormActions.AddItemToListBox:
737 LstResults.Items.Add(strings[0]);
740 case FormActions.DisableInputReportBufferSize:
742 cmdInputReportBufferSize.Enabled = false;
745 case FormActions.EnableGetInputReportInterruptTransfer:
747 cmdGetInputReportInterrupt.Enabled = true;
750 case FormActions.EnableInputReportBufferSize:
752 cmdInputReportBufferSize.Enabled = true;
755 case FormActions.EnableSendOutputReportInterrupt:
757 cmdSendOutputReportInterrupt.Enabled = true;
760 case FormActions.ScrollToBottomOfListBox:
762 LstResults.SelectedIndex = LstResults.Items.Count - 1;
765 case FormActions.SetInputReportBufferSize:
767 txtInputReportBufferSize.Text = strings[0];
770 case FormActions.AddDeviceToTreeView:
771 //Build our node from our string array
772 TreeNode newNode = new TreeNode(strings[0]);
773 for (int i=1;i<strings.Length;i++)
775 newNode.Nodes.Add(strings[i]);
776 if (strings[i].StartsWith("Name: "))
778 //Found our name property, update our node text
779 newNode.Text = strings[i].Substring(6, strings[i].Length - 6);
783 newNode.Name = strings[0]; //Set ID as name to make sure we can find it
784 treeViewDevices.Nodes.Add(newNode);
787 case FormActions.ResetDeviceTreeView:
788 treeViewDevices.Nodes.Clear();
791 case FormActions.SelectDeviceInTreeView:
792 treeViewDevices.SelectedNode = null;
793 TreeNode[] res=treeViewDevices.Nodes.Find(strings[0], false);
796 treeViewDevices.SelectedNode = res[0];
797 treeViewDevices.SelectedNode.ForeColor = Color.Blue;
806 DisplayException(Name, ex);
812 /// Add a handler to detect arrival of devices using WMI.
815 private void AddDeviceArrivedHandler()
817 const Int32 pollingIntervalSeconds = 3;
818 var scope = new ManagementScope("root\\CIMV2");
819 scope.Options.EnablePrivileges = true;
823 var q = new WqlEventQuery();
824 q.EventClassName = "__InstanceCreationEvent";
825 q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
826 q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
827 _deviceArrivedWatcher = new ManagementEventWatcher(scope, q);
828 _deviceArrivedWatcher.EventArrived += DeviceAdded;
830 _deviceArrivedWatcher.Start();
834 Debug.WriteLine(e.Message);
835 if (_deviceArrivedWatcher != null)
836 _deviceArrivedWatcher.Stop();
841 /// Add a handler to detect removal of devices using WMI.
844 private void AddDeviceRemovedHandler()
846 const Int32 pollingIntervalSeconds = 3;
847 var scope = new ManagementScope("root\\CIMV2");
848 scope.Options.EnablePrivileges = true;
852 var q = new WqlEventQuery();
853 q.EventClassName = "__InstanceDeletionEvent";
854 q.WithinInterval = new TimeSpan(0, 0, pollingIntervalSeconds);
855 q.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
856 _deviceRemovedWatcher = new ManagementEventWatcher(scope, q);
857 _deviceRemovedWatcher.EventArrived += DeviceRemoved;
858 _deviceRemovedWatcher.Start();
862 Debug.WriteLine(e.Message);
863 if (_deviceRemovedWatcher != null)
864 _deviceRemovedWatcher.Stop();
869 /// Close the handle and FileStreams for a device.
872 private void CloseCommunications()
874 if (_deviceData != null)
879 if ((_hidHandle != null) && (!(_hidHandle.IsInvalid)))
884 // The next attempt to communicate will get a new handle and FileStreams.
886 _deviceHandleObtained = false;
890 /// Search for a specific device.
893 private void cmdFindDevice_Click(Object sender, EventArgs e)
897 if (_transferInProgress)
899 DisplayTransferInProgressMessage();
903 _deviceDetected = FindDeviceUsingWmi();
912 DisplayException(Name, ex);
918 /// Request to get a Feature report from the device.
920 /// <param name="sender"></param>
921 /// <param name="e"></param>
923 private void cmdGetFeatureReport_Click(object sender, EventArgs e)
927 if (_transferInProgress)
929 DisplayTransferInProgressMessage();
933 // Don't allow another transfer request until this one completes.
934 // Move the focus away from the button to prevent the focus from
935 // switching to the next control in the tab order on disabling the button.
937 fraControlTransfers.Focus();
938 cmdGetFeatureReport.Enabled = false;
939 _transferType = TransferTypes.Control;
940 RequestToGetFeatureReport();
945 DisplayException(Name, ex);
951 /// Request to get an Input report from the device using a control transfer.
953 /// <param name="sender"></param>
954 /// <param name="e"></param>
956 private void cmdGetInputReportControl_Click(object sender, EventArgs e)
960 // Don't allow another transfer request until this one completes.
961 // Move the focus away from the button to prevent the focus from
962 // switching to the next control in the tab order on disabling the button.
964 if (_transferInProgress)
966 DisplayTransferInProgressMessage();
970 fraControlTransfers.Focus();
971 cmdGetInputReportControl.Enabled = false;
972 _transferType = TransferTypes.Control;
973 RequestToGetInputReport();
978 DisplayException(Name, ex);
984 /// Request to get an Input report retrieved using interrupt transfers.
986 /// <param name="sender"></param>
987 /// <param name="e"></param>
989 private void cmdGetInputReportInterrupt_Click(object sender, EventArgs e)
993 if (_transferInProgress)
995 DisplayTransferInProgressMessage();
999 // Don't allow another transfer request until this one completes.
1000 // Move the focus away from the button to prevent the focus from
1001 // switching to the next control in the tab order on disabling the button.
1003 fraInterruptTransfers.Focus();
1004 cmdGetInputReportInterrupt.Enabled = false;
1005 _transferType = TransferTypes.Interrupt;
1006 RequestToGetInputReport();
1009 catch (Exception ex)
1011 DisplayException(Name, ex);
1017 /// Set the number of Input reports the HID driver will store.
1020 private void cmdInputReportBufferSize_Click(Object sender, EventArgs e)
1024 if (_transferInProgress)
1026 DisplayTransferInProgressMessage();
1030 SetInputReportBufferSize();
1036 DisplayException(Name, ex);
1042 /// Alternate sending and getting a report.
1044 /// <param name="sender"></param>
1045 /// <param name="e"></param>
1047 private void cmdPeriodicTransfers_Click(object sender, EventArgs e)
1051 if (cmdPeriodicTransfers.Text == "Start")
1053 if (_transferInProgress)
1055 DisplayTransferInProgressMessage();
1059 _sendOrGet = SendOrGet.Send;
1060 PeriodicTransfersStart();
1065 PeriodicTransfersStop();
1068 catch (Exception ex)
1070 DisplayException(Name, ex);
1076 /// Request to send a Feature report using a control transfer.
1078 /// <param name="sender"></param>
1079 /// <param name="e"></param>
1081 private void cmdSendFeatureReport_Click(object sender, EventArgs e)
1085 if (_transferInProgress)
1087 DisplayTransferInProgressMessage();
1091 // Don't allow another transfer request until this one completes.
1092 // Move the focus away from the button to prevent the focus from
1093 // switching to the next control in the tab order on disabling the button.
1095 fraControlTransfers.Focus();
1096 cmdSendFeatureReport.Enabled = false;
1097 _transferType = TransferTypes.Control;
1098 RequestToSendFeatureReport();
1101 catch (Exception ex)
1103 DisplayException(Name, ex);
1109 /// Request to send an Output report using a control transfer.
1111 /// <param name="sender"></param>
1112 /// <param name="e"></param>
1114 private void cmdSendOutputReportControl_Click(object sender, EventArgs e)
1118 if (_transferInProgress)
1120 DisplayTransferInProgressMessage();
1124 // Don't allow another transfer request until this one completes.
1125 // Move the focus away from the button to prevent the focus from
1126 // switching to the next control in the tab order on disabling the button.
1128 fraControlTransfers.Focus();
1129 cmdSendOutputReportControl.Enabled = false;
1130 _transferType = TransferTypes.Control;
1131 RequestToSendOutputReport();
1134 catch (Exception ex)
1136 DisplayException(Name, ex);
1142 /// Request to send an Output report using an interrupt transfer.
1144 /// <param name="sender"></param>
1145 /// <param name="e"></param>
1147 private void cmdSendOutputReportInterrupt_Click(object sender, EventArgs e)
1151 if (_transferInProgress)
1153 DisplayTransferInProgressMessage();
1157 // Don't allow another transfer request until this one completes.
1158 // Move the focus away from the button to prevent the focus from
1159 // switching to the next control in the tab order on disabling the button.
1161 fraInterruptTransfers.Focus();
1162 cmdSendOutputReportInterrupt.Enabled = false;
1163 _transferType = TransferTypes.Interrupt;
1164 RequestToSendOutputReport();
1167 catch (Exception ex)
1169 DisplayException(Name, ex);
1175 /// Called on arrival of any device.
1176 /// Calls a routine that searches to see if the desired device is present.
1179 private void DeviceAdded(object sender, EventArrivedEventArgs e)
1183 Debug.WriteLine("A USB device has been inserted");
1185 _deviceDetected = FindDeviceUsingWmi();
1187 catch (Exception ex)
1189 DisplayException(Name, ex);
1195 /// Called if the user changes the Vendor ID or Product ID in the text box.
1198 private void DeviceHasChanged()
1202 // If a device was previously detected, stop receiving notifications about it.
1204 if (_deviceHandleObtained)
1206 DeviceNotificationsStop();
1208 CloseCommunications();
1210 // Look for a device that matches the Vendor ID and Product ID in the text boxes.
1214 catch (Exception ex)
1216 DisplayException(Name, ex);
1222 /// Add handlers to detect device arrival and removal.
1225 private void DeviceNotificationsStart()
1227 AddDeviceArrivedHandler();
1228 AddDeviceRemovedHandler();
1232 /// Stop receiving notifications about device arrival and removal
1235 private void DeviceNotificationsStop()
1239 if (_deviceArrivedWatcher != null)
1240 _deviceArrivedWatcher.Stop();
1241 if (_deviceRemovedWatcher != null)
1242 _deviceRemovedWatcher.Stop();
1244 catch (Exception ex)
1246 DisplayException(Name, ex);
1252 /// Called on removal of any device.
1253 /// Calls a routine that searches to see if the desired device is still present.
1256 private void DeviceRemoved(object sender, EventArgs e)
1260 Debug.WriteLine("A USB device has been removed");
1262 _deviceDetected = FindDeviceUsingWmi();
1264 if (!_deviceDetected)
1266 _deviceHandleObtained = false;
1267 CloseCommunications();
1270 catch (Exception ex)
1272 DisplayException(Name, ex);
1278 /// Displays received or written report data.
1281 /// <param name="buffer"> contains the report data. </param>
1282 /// <param name="currentReportType" > "Input", "Output", or "Feature"</param>
1283 /// <param name="currentReadOrWritten" > "read" for Input and IN Feature reports, "written" for Output and OUT Feature reports.</param>
1285 private void DisplayReportData(Byte[] buffer, ReportTypes currentReportType, ReportReadOrWritten currentReadOrWritten)
1291 LstResults.Items.Add(currentReportType.ToString() + " report has been " + currentReadOrWritten.ToString().ToLower() + ".");
1293 // Display the report data received in the form's list box.
1295 LstResults.Items.Add(" Report ID: " + String.Format("{0:X2} ", buffer[0]));
1296 LstResults.Items.Add(" Report Data:");
1298 TxtBytesReceived.Text = "";
1300 for (count = 1; count <= buffer.Length - 1; count++)
1302 // Display bytes as 2-character Hex strings.
1304 String byteValue = String.Format("{0:X2} ", buffer[count]);
1306 LstResults.Items.Add(" " + byteValue);
1308 // Display the received bytes in the text box.
1310 TxtBytesReceived.SelectionStart = TxtBytesReceived.Text.Length;
1311 TxtBytesReceived.SelectedText = byteValue + Environment.NewLine;
1313 ScrollToBottomOfListBox();
1315 catch (Exception ex)
1317 DisplayException(Name, ex);
1323 /// Display a message if the user clicks a button when a transfer is in progress.
1326 private void DisplayTransferInProgressMessage()
1328 AccessForm(FormActions.AddItemToListBox, "Command not executed because a transfer is in progress.");
1329 ScrollToBottomOfListBox();
1333 /// Do periodic transfers.
1335 /// <param name="source"></param>
1336 /// <param name="e"></param>
1338 /// The timer is enabled only if continuous (periodic) transfers have been requested.
1341 private void DoPeriodicTransfers(object source, ElapsedEventArgs e)
1345 PeriodicTransfers();
1347 catch (Exception ex)
1349 DisplayException(Name, ex);
1355 /// Enable the command buttons on the form.
1356 /// Needed after attempting a transfer and device not found.
1359 private void EnableFormControls()
1361 cmdGetInputReportInterrupt.Enabled = true;
1362 cmdSendOutputReportControl.Enabled = true;
1363 cmdGetInputReportControl.Enabled = true;
1364 cmdGetFeatureReport.Enabled = true;
1365 cmdSendFeatureReport.Enabled = true;
1366 cmdPeriodicTransfers.Enabled = true;
1367 cmdSendOutputReportInterrupt.Enabled = true;
1371 /// Use the System.Management class to find a device by Vendor ID and Product ID using WMI. If found, display device properties.
1374 /// During debugging, if you stop the firmware but leave the device attached, the device may still be detected as present
1375 /// but will be unable to communicate. The device will show up in Windows Device Manager as well.
1376 /// This situation is unlikely to occur with a final product.
1379 private Boolean FindDeviceUsingWmi()
1383 MyMarshalDataToForm(FormActions.ResetDeviceTreeView);
1384 // Prepend "@" to string below to treat backslash as a normal character (not escape character):
1386 String deviceIdString = @"USB\VID_" + _myVendorId.ToString("X4") + "&PID_" + _myProductId.ToString("X4");
1388 _deviceDetected = false;
1389 var searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity");
1390 int usbDeviceCounter = 0;
1392 foreach (ManagementObject queryObj in searcher.Get())
1394 string deviceId = queryObj["PNPDeviceID"].ToString();
1395 if (deviceId.Contains(deviceIdString))
1397 _deviceDetected = true;
1398 MyMarshalDataToForm(FormActions.AddItemToListBox, "My device found (WMI):");
1400 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1401 List<string> device = new List<string>();
1402 device.Add(deviceId);
1404 // Display device properties.
1405 foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
1407 MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
1408 device.Add((wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
1409 Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
1411 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1412 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1414 MyMarshalDataToForm(FormActions.AddDeviceToTreeView, device.ToArray());
1415 MyMarshalDataToForm(FormActions.SelectDeviceInTreeView, deviceId);
1418 else if (deviceId.StartsWith("USB\\VID"))
1420 List<string> device = new List<string>();
1421 device.Add(deviceId);
1423 // Add device properties.
1424 foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
1426 device.Add((wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
1427 Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
1430 MyMarshalDataToForm(FormActions.AddDeviceToTreeView, device.ToArray());
1434 MyMarshalDataToForm(FormActions.AddItemToListBox, "Found " + usbDeviceCounter /*searcher.Get().Count*/ + " USB HID devices");
1436 if (!_deviceDetected)
1438 MyMarshalDataToForm(FormActions.AddItemToListBox, "My device not found (WMI)");
1439 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1441 return _deviceDetected;
1443 catch (Exception ex)
1445 DisplayException(Name, ex);
1451 /// Call HID functions that use Win32 API functions to locate a HID-class device
1452 /// by its Vendor ID and Product ID. Open a handle to the device.
1456 /// True if the device is detected, False if not detected.
1459 private Boolean FindTheHid()
1461 var devicePathName = new String[128];
1462 String myDevicePathName = "";
1466 _deviceHandleObtained = false;
1467 CloseCommunications();
1469 // Get the device's Vendor ID and Product ID from the form's text boxes.
1471 GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
1473 // Get the HID-class GUID.
1475 Guid hidGuid = _myHid.GetHidGuid();
1477 String functionName = "GetHidGuid";
1478 Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
1479 Debug.WriteLine(" GUID for system HIDs: " + hidGuid.ToString());
1481 // Fill an array with the device path names of all attached HIDs.
1483 Boolean availableHids = _myDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
1485 // If there is at least one HID, attempt to read the Vendor ID and Product ID
1486 // of each device until there is a match or all devices have been examined.
1490 Int32 memberIndex = 0;
1494 // Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice.
1496 _hidHandle = _myHid.OpenHandle(devicePathName[memberIndex], false);
1498 functionName = "CreateFile";
1499 Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
1500 Debug.WriteLine(" Returned handle: " + _hidHandle);
1502 if (!_hidHandle.IsInvalid)
1504 // The returned handle is valid,
1505 // so find out if this is the device we're looking for.
1507 _myHid.DeviceAttributes.Size = Marshal.SizeOf(_myHid.DeviceAttributes);
1509 Boolean success = _myHid.GetAttributes(_hidHandle, ref _myHid.DeviceAttributes);
1513 Debug.WriteLine(" HIDD_ATTRIBUTES structure filled without error.");
1514 Debug.WriteLine(" Structure size: " + _myHid.DeviceAttributes.Size);
1515 Debug.WriteLine(" Vendor ID: " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
1516 Debug.WriteLine(" Product ID: " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
1517 Debug.WriteLine(" Version Number: " + Convert.ToString(_myHid.DeviceAttributes.VersionNumber, 16));
1519 if ((_myHid.DeviceAttributes.VendorID == _myVendorId) && (_myHid.DeviceAttributes.ProductID == _myProductId))
1521 Debug.WriteLine(" Handle obtained to my device");
1523 // Display the information in form's list box.
1525 MyMarshalDataToForm(FormActions.AddItemToListBox, "Handle obtained to my device:");
1526 MyMarshalDataToForm(FormActions.AddItemToListBox, " Vendor ID= " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
1527 MyMarshalDataToForm(FormActions.AddItemToListBox, " Product ID = " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
1528 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1530 _deviceHandleObtained = true;
1532 myDevicePathName = devicePathName[memberIndex];
1536 // It's not a match, so close the handle.
1538 _deviceHandleObtained = false;
1544 // There was a problem retrieving the information.
1546 Debug.WriteLine(" Error in filling HIDD_ATTRIBUTES structure.");
1547 _deviceHandleObtained = false;
1552 // Keep looking until we find the device or there are no devices left to examine.
1554 memberIndex = memberIndex + 1;
1556 while (!((_deviceHandleObtained || (memberIndex == devicePathName.Length))));
1559 if (_deviceHandleObtained)
1561 // The device was detected.
1562 // Learn the capabilities of the device.
1564 _myHid.Capabilities = _myHid.GetDeviceCapabilities(_hidHandle);
1566 // Find out if the device is a system mouse or keyboard.
1568 _hidUsage = _myHid.GetHidUsage(_myHid.Capabilities);
1570 // Get the Input report buffer size.
1572 GetInputReportBufferSize();
1573 MyMarshalDataToForm(FormActions.EnableInputReportBufferSize, "");
1575 //Close the handle and reopen it with read/write access.
1579 _hidHandle = _myHid.OpenHandle(myDevicePathName, true);
1581 if (_hidHandle.IsInvalid)
1583 MyMarshalDataToForm(FormActions.AddItemToListBox, "The device is a system " + _hidUsage + ".");
1584 MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 2000 and later obtain exclusive access to Input and Output reports for this devices.");
1585 MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 8 also obtains exclusive access to Feature reports.");
1586 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1590 if (_myHid.Capabilities.InputReportByteLength > 0)
1592 // Set the size of the Input report buffer.
1594 var inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
1596 _deviceData = new FileStream(_hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
1599 if (_myHid.Capabilities.OutputReportByteLength > 0)
1601 Byte[] outputReportBuffer = null;
1603 // Flush any waiting reports in the input buffer. (optional)
1605 _myHid.FlushQueue(_hidHandle);
1610 MyMarshalDataToForm(FormActions.AddItemToListBox, "Device not found.");
1611 MyMarshalDataToForm(FormActions.DisableInputReportBufferSize, "");
1612 EnableFormControls();
1613 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1615 return _deviceHandleObtained;
1617 catch (Exception ex)
1619 DisplayException(Name, ex);
1625 /// Perform shutdown operations.
1628 private void frmMain_Closed(Object eventSender, EventArgs eventArgs)
1634 catch (Exception ex)
1636 DisplayException(Name, ex);
1642 /// Perform startup operations.
1645 private void frmMain_Load(Object eventSender, EventArgs eventArgs)
1652 catch (Exception ex)
1654 DisplayException(Name, ex);
1659 private void GetBytesToSend()
1663 // Get the bytes to send in a report from the combo boxes.
1664 // Increment the values if the autoincrement check box is selected.
1666 if (ChkAutoincrement.Checked)
1668 if (CboByte0.SelectedIndex < 255)
1670 CboByte0.SelectedIndex = CboByte0.SelectedIndex + 1;
1674 CboByte0.SelectedIndex = 0;
1676 if (CboByte1.SelectedIndex < 255)
1678 CboByte1.SelectedIndex = CboByte1.SelectedIndex + 1;
1682 CboByte1.SelectedIndex = 0;
1686 catch (Exception ex)
1688 DisplayException(Name, ex);
1694 /// Find and display the number of Input buffers
1695 /// (the number of Input reports the HID driver will store).
1698 private void GetInputReportBufferSize()
1700 Int32 numberOfInputBuffers = 0;
1705 // Get the number of input buffers.
1707 _myHid.GetNumberOfInputBuffers(_hidHandle, ref numberOfInputBuffers);
1709 // Display the result in the text box.
1711 MyMarshalDataToForm(FormActions.SetInputReportBufferSize, Convert.ToString(numberOfInputBuffers));
1713 catch (Exception ex)
1715 DisplayException(Name, ex);
1721 /// Retrieve a Vendor ID and Product ID in hexadecimal
1722 /// from the form's text boxes and convert the text to Int32s.
1725 /// <param name="myVendorId"> the Vendor ID</param>
1726 /// <param name="myProductId"> the Product ID</param>
1728 private void GetVendorAndProductIDsFromTextBoxes(ref Int32 myVendorId, ref Int32 myProductId)
1732 myVendorId = Int32.Parse(txtVendorID.Text, NumberStyles.AllowHexSpecifier);
1733 myProductId = Int32.Parse(txtProductID.Text, NumberStyles.AllowHexSpecifier);
1735 catch (Exception ex)
1737 DisplayException(Name, ex);
1743 /// Initialize the elements on the form.
1746 private void InitializeDisplay()
1750 // Create a dropdown list box for each byte to send in a report.
1751 // Display the values as 2-character hex strings.
1754 for (count = 0; count <= 255; count++)
1756 String byteValue = String.Format("{0:X2} ", count);
1757 FrmMy.CboByte0.Items.Insert(count, byteValue);
1758 FrmMy.CboByte1.Items.Insert(count, byteValue);
1761 // Select a default value for each box
1763 FrmMy.CboByte0.SelectedIndex = 0;
1764 FrmMy.CboByte1.SelectedIndex = 128;
1765 FrmMy.radInputOutputInterrupt.Checked = true;
1767 // Check the autoincrement box to increment the values each time a report is sent.
1769 ChkAutoincrement.CheckState = CheckState.Checked;
1771 // Don't allow the user to select an input report buffer size until there is
1772 // a handle to a HID.
1774 cmdInputReportBufferSize.Focus();
1775 cmdInputReportBufferSize.Enabled = false;
1777 LstResults.Items.Add("For a more detailed event log, view debug statements in Visual Studio's Output window:");
1778 LstResults.Items.Add("Click Build > Configuration Manager > Active Solution Configuration > Debug > Close.");
1779 LstResults.Items.Add("Then click View > Output.");
1780 LstResults.Items.Add("");
1782 catch (Exception ex)
1784 DisplayException(Name, ex);
1790 /// Enables accessing a form's controls from another thread
1793 /// <param name="action"> a FormActions member that names the action to perform on the form </param>
1794 /// <param name="textToDisplay"> text that the form displays or the code uses for
1795 /// another purpose. Actions that don't use text ignore this parameter. </param>
1797 private void MyMarshalDataToForm(FormActions action, params string[] strings)
1801 object[] args = { action, strings };
1803 // The AccessForm routine contains the code that accesses the form.
1805 MarshalDataToForm marshalDataToFormDelegate = AccessForm;
1807 // Execute AccessForm, passing the parameters in args.
1809 Invoke(marshalDataToFormDelegate, args);
1811 catch (Exception ex)
1813 DisplayException(Name, ex);
1819 /// Timeout if read via interrupt transfer doesn't return.
1822 private void OnReadTimeout()
1826 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a report timed out.");
1827 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1828 CloseCommunications();
1829 MyMarshalDataToForm(FormActions.EnableGetInputReportInterruptTransfer, "");
1830 _transferInProgress = false;
1831 _sendOrGet = SendOrGet.Send;
1833 catch (Exception ex)
1835 DisplayException(Name, ex);
1841 /// Timeout if write via interrupt transfer doesn't return.
1844 private void OnWriteTimeout()
1848 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to write a report timed out.");
1849 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1850 CloseCommunications();
1851 MyMarshalDataToForm(FormActions.EnableSendOutputReportInterrupt, "");
1852 _transferInProgress = false;
1853 _sendOrGet = SendOrGet.Get;
1855 catch (Exception ex)
1857 DisplayException(Name, ex);
1863 /// Alternat sending and getting a report.
1866 private void PeriodicTransfers()
1870 if (!_transferInProgress)
1872 if (_reportType == ReportTypes.Feature)
1874 SendOrGetFeatureReport();
1878 // Output and Input reports
1880 SendOutputReportOrGetInputReport();
1884 catch (Exception ex)
1886 DisplayException(Name, ex);
1892 /// Start doing periodic transfers.
1895 private void PeriodicTransfersStart()
1897 // Don't allow changing the transfer type while transfers are in progress.
1899 if (radFeature.Checked)
1901 radInputOutputControl.Enabled = false;
1902 radInputOutputInterrupt.Enabled = false;
1904 else if (radInputOutputControl.Checked)
1906 radFeature.Enabled = false;
1907 radInputOutputInterrupt.Enabled = false;
1909 else if (radInputOutputInterrupt.Checked)
1911 radFeature.Enabled = false;
1912 radInputOutputControl.Enabled = false;
1915 // Change the command button's text.
1917 cmdPeriodicTransfers.Text = "Stop";
1919 // Enable the timer event to trigger a set of transfers.
1921 _periodicTransfers.Start();
1923 cmdPeriodicTransfers.Enabled = true;
1925 if (radInputOutputInterrupt.Checked)
1927 _transferType = TransferTypes.Interrupt;
1928 _reportType = ReportTypes.Output;
1930 else if (radInputOutputControl.Checked)
1932 _transferType = TransferTypes.Control;
1933 _reportType = ReportTypes.Output;
1935 else if (radFeature.Checked)
1937 _transferType = TransferTypes.Control;
1938 _reportType = ReportTypes.Feature;
1940 _periodicTransfersRequested = true;
1941 PeriodicTransfers();
1945 /// Stop doing periodic transfers.
1948 private void PeriodicTransfersStop()
1950 // Stop doing continuous transfers.
1952 _periodicTransfersRequested = false;
1954 // Disable the timer that triggers the transfers.
1956 _periodicTransfers.Stop();
1957 cmdPeriodicTransfers.Enabled = true;
1959 // Change the command button's text.
1961 cmdPeriodicTransfers.Text = "Start";
1963 // Re-allow changing the transfer type.
1965 radFeature.Enabled = true;
1966 radInputOutputControl.Enabled = true;
1967 radInputOutputInterrupt.Enabled = true;
1970 private void radInputOutputControl_CheckedChanged(object sender, EventArgs e)
1974 private void radInputOutputInterrupt_CheckedChanged(object sender, EventArgs e)
1978 private void radFeature_CheckedChanged(object sender, EventArgs e)
1983 /// Request a Feature report.
1984 /// Assumes report ID = 0.
1987 private void RequestToGetFeatureReport()
1989 String byteValue = null;
1993 // If the device hasn't been detected, was removed, or timed out on a previous attempt
1994 // to access it, look for the device.
1996 if (!_deviceHandleObtained)
1998 _deviceHandleObtained = FindTheHid();
2001 if (_deviceHandleObtained)
2003 Byte[] inFeatureReportBuffer = null;
2005 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
2007 // The HID has a Feature report.
2008 // Read a report from the device.
2010 // Set the size of the Feature report buffer.
2012 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
2014 inFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
2019 Boolean success = _myHid.GetFeatureReport(_hidHandle, ref inFeatureReportBuffer);
2023 DisplayReportData(inFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Read);
2027 CloseCommunications();
2028 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a Feature report failed.");
2029 ScrollToBottomOfListBox();
2034 MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
2035 ScrollToBottomOfListBox();
2038 _transferInProgress = false;
2039 cmdGetFeatureReport.Enabled = true;
2041 catch (Exception ex)
2043 DisplayException(Name, ex);
2049 /// Request an Input report.
2050 /// Assumes report ID = 0.
2053 private async void RequestToGetInputReport()
2055 const Int32 readTimeout = 5000;
2057 String byteValue = null;
2058 Byte[] inputReportBuffer = null;
2062 Boolean success = false;
2064 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2065 // to access it, look for the device.
2067 if (!_deviceHandleObtained)
2069 _deviceHandleObtained = FindTheHid();
2072 if (_deviceHandleObtained)
2074 // Don't attempt to exchange reports if valid handles aren't available
2075 // (as for a mouse or keyboard under Windows 2000 and later.)
2077 if (!_hidHandle.IsInvalid)
2079 // Read an Input report.
2081 // Don't attempt to send an Input report if the HID has no Input report.
2082 // (The HID spec requires all HIDs to have an interrupt IN endpoint,
2083 // which suggests that all HIDs must support Input reports.)
2085 if (_myHid.Capabilities.InputReportByteLength > 0)
2087 // Set the size of the Input report buffer.
2089 inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
2091 if (_transferType.Equals(TransferTypes.Control))
2094 _transferInProgress = true;
2096 // Read a report using a control transfer.
2098 success = _myHid.GetInputReportViaControlTransfer(_hidHandle, ref inputReportBuffer);
2099 cmdGetInputReportControl.Enabled = true;
2100 _transferInProgress = false;
2106 _transferInProgress = true;
2108 // Read a report using interrupt transfers.
2109 // Timeout if no report available.
2110 // To enable reading a report without blocking the calling thread, uses Filestream's ReadAsync method.
2112 // Create a delegate to execute on a timeout.
2114 Action onReadTimeoutAction = OnReadTimeout;
2116 // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
2118 var cts = new CancellationTokenSource();
2120 // Cancel the read if it hasn't completed after a timeout.
2122 cts.CancelAfter(readTimeout);
2124 // Specify the function to call on a timeout.
2126 cts.Token.Register(onReadTimeoutAction);
2128 // Stops waiting when data is available or on timeout:
2130 Int32 bytesRead = await _myHid.GetInputReportViaInterruptTransfer(_deviceData, inputReportBuffer, cts);
2132 // Arrive here only if the operation completed.
2134 // Dispose to stop the timeout timer.
2138 _transferInProgress = false;
2139 cmdGetInputReportInterrupt.Enabled = true;
2144 Debug.Print("bytes read (includes report ID) = " + Convert.ToString(bytesRead));
2151 MyMarshalDataToForm(FormActions.AddItemToListBox, "No attempt to read an Input report was made.");
2152 MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have an Input report.");
2157 MyMarshalDataToForm(FormActions.AddItemToListBox, "Invalid handle.");
2158 MyMarshalDataToForm(FormActions.AddItemToListBox,
2159 "No attempt to write an Output report or read an Input report was made.");
2164 DisplayReportData(inputReportBuffer, ReportTypes.Input, ReportReadOrWritten.Read);
2168 CloseCommunications();
2169 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read an Input report has failed.");
2170 ScrollToBottomOfListBox();
2174 catch (Exception ex)
2176 DisplayException(Name, ex);
2182 /// Sends a Feature report.
2183 /// Assumes report ID = 0.
2186 private void RequestToSendFeatureReport()
2188 String byteValue = null;
2192 _transferInProgress = true;
2194 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2195 // to access it, look for the device.
2197 if (!_deviceHandleObtained)
2199 _deviceHandleObtained = FindTheHid();
2202 if (_deviceHandleObtained)
2206 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
2208 // The HID has a Feature report.
2209 // Set the size of the Feature report buffer.
2211 var outFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
2213 // Store the report ID in the buffer.
2215 outFeatureReportBuffer[0] = 0;
2217 // Store the report data following the report ID.
2218 // Use the data in the combo boxes on the form.
2220 outFeatureReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
2222 if (outFeatureReportBuffer.GetUpperBound(0) > 1)
2224 outFeatureReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
2227 // Write a report to the device
2229 Boolean success = _myHid.SendFeatureReport(_hidHandle, outFeatureReportBuffer);
2233 DisplayReportData(outFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Written);
2237 CloseCommunications();
2238 AccessForm(FormActions.AddItemToListBox, "The attempt to send a Feature report failed.");
2239 ScrollToBottomOfListBox();
2244 AccessForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
2245 ScrollToBottomOfListBox();
2249 _transferInProgress = false;
2250 cmdSendFeatureReport.Enabled = true;
2251 ScrollToBottomOfListBox();
2254 catch (Exception ex)
2256 DisplayException(Name, ex);
2262 /// Sends an Output report.
2263 /// Assumes report ID = 0.
2266 private async void RequestToSendOutputReport()
2268 const Int32 writeTimeout = 5000;
2269 String byteValue = null;
2273 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2274 // to access it, look for the device.
2276 if (!_deviceHandleObtained)
2278 _deviceHandleObtained = FindTheHid();
2281 if (_deviceHandleObtained)
2285 // Don't attempt to exchange reports if valid handles aren't available
2286 // (as for a mouse or keyboard.)
2288 if (!_hidHandle.IsInvalid)
2290 // Don't attempt to send an Output report if the HID has no Output report.
2292 if (_myHid.Capabilities.OutputReportByteLength > 0)
2294 // Set the size of the Output report buffer.
2296 var outputReportBuffer = new Byte[_myHid.Capabilities.OutputReportByteLength];
2298 // Store the report ID in the first byte of the buffer:
2300 outputReportBuffer[0] = 0;
2302 // Store the report data following the report ID.
2303 // Use the data in the combo boxes on the form.
2305 outputReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
2307 if (outputReportBuffer.GetUpperBound(0) > 1)
2309 outputReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
2316 if (_transferType.Equals(TransferTypes.Control))
2319 _transferInProgress = true;
2321 // Use a control transfer to send the report,
2322 // even if the HID has an interrupt OUT endpoint.
2324 success = _myHid.SendOutputReportViaControlTransfer(_hidHandle, outputReportBuffer);
2326 _transferInProgress = false;
2327 cmdSendOutputReportControl.Enabled = true;
2332 Debug.Print("interrupt");
2333 _transferInProgress = true;
2335 // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
2337 var cts = new CancellationTokenSource();
2339 // Create a delegate to execute on a timeout.
2341 Action onWriteTimeoutAction = OnWriteTimeout;
2343 // Cancel the read if it hasn't completed after a timeout.
2345 cts.CancelAfter(writeTimeout);
2347 // Specify the function to call on a timeout.
2349 cts.Token.Register(onWriteTimeoutAction);
2351 // Send an Output report and wait for completion or timeout.
2353 success = await _myHid.SendOutputReportViaInterruptTransfer(_deviceData, _hidHandle, outputReportBuffer, cts);
2355 // Get here only if the operation completes without a timeout.
2357 _transferInProgress = false;
2358 cmdSendOutputReportInterrupt.Enabled = true;
2360 // Dispose to stop the timeout timer.
2366 DisplayReportData(outputReportBuffer, ReportTypes.Output, ReportReadOrWritten.Written);
2370 CloseCommunications();
2371 AccessForm(FormActions.AddItemToListBox, "The attempt to write an Output report failed.");
2372 ScrollToBottomOfListBox();
2378 AccessForm(FormActions.AddItemToListBox, "The HID doesn't have an Output report.");
2381 catch (Exception ex)
2383 DisplayException(Name, ex);
2389 /// Scroll to the bottom of the list box and trim as needed.
2392 private void ScrollToBottomOfListBox()
2396 LstResults.SelectedIndex = LstResults.Items.Count - 1;
2398 // If the list box is getting too large, trim its contents by removing the earliest data.
2400 if (LstResults.Items.Count > 1000)
2403 for (count = 1; count <= 500; count++)
2405 LstResults.Items.RemoveAt(4);
2409 catch (Exception ex)
2411 DisplayException(Name, ex);
2417 /// Request to send or get a Feature report.
2420 private void SendOrGetFeatureReport()
2424 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2425 // to access it, look for the device.
2427 if (!_deviceHandleObtained)
2429 _deviceHandleObtained = FindTheHid();
2432 if (_deviceHandleObtained)
2436 case SendOrGet.Send:
2437 RequestToSendFeatureReport();
2438 _sendOrGet = SendOrGet.Get;
2441 RequestToGetFeatureReport();
2442 _sendOrGet = SendOrGet.Send;
2447 catch (Exception ex)
2449 DisplayException(Name, ex);
2455 /// Request to send an Output report or get an Input report.
2458 private void SendOutputReportOrGetInputReport()
2462 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2463 // to access it, look for the device.
2465 if (!_deviceHandleObtained)
2467 _deviceHandleObtained = FindTheHid();
2470 if (_deviceHandleObtained)
2472 if (_sendOrGet == SendOrGet.Send)
2474 RequestToSendOutputReport();
2475 _sendOrGet = SendOrGet.Get;
2479 RequestToGetInputReport();
2480 _sendOrGet = SendOrGet.Send;
2484 catch (Exception ex)
2486 DisplayException(Name, ex);
2492 /// Set the number of Input buffers (the number of Input reports
2493 /// the host will store) from the value in the text box.
2496 private void SetInputReportBufferSize()
2500 if (!_transferInProgress)
2502 // Get the number of buffers from the text box.
2504 Int32 numberOfInputBuffers = Convert.ToInt32(txtInputReportBufferSize.Text);
2506 // Set the number of buffers.
2508 _myHid.SetNumberOfInputBuffers(_hidHandle, numberOfInputBuffers);
2510 // Verify and display the result.
2512 GetInputReportBufferSize();
2516 DisplayTransferInProgressMessage();
2519 catch (Exception ex)
2521 DisplayException(Name, ex);
2527 /// Perform actions that must execute when the program ends.
2530 private void Shutdown()
2534 CloseCommunications();
2535 DeviceNotificationsStop();
2537 catch (Exception ex)
2539 DisplayException(Name, ex);
2545 /// Perform actions that must execute when the program starts.
2548 private void Startup()
2550 const Int32 periodicTransferInterval = 1000;
2554 InitializeDisplay();
2556 _periodicTransfers = new System.Timers.Timer(periodicTransferInterval);
2557 _periodicTransfers.Elapsed += DoPeriodicTransfers;
2558 _periodicTransfers.Stop();
2559 _periodicTransfers.SynchronizingObject = this;
2561 // Default USB Vendor ID and Product ID:
2563 txtVendorID.Text = "0925";
2564 txtProductID.Text = "7001";
2566 GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
2568 DeviceNotificationsStart();
2569 FindDeviceUsingWmi();
2572 catch (Exception ex)
2574 DisplayException(Name, ex);
2580 /// The Product ID has changed in the text box. Call a routine to handle it.
2583 private void txtProductID_TextChanged(Object sender, EventArgs e)
2589 catch (Exception ex)
2591 DisplayException(Name, ex);
2597 /// The Vendor ID has changed in the text box. Call a routine to handle it.
2600 private void txtVendorID_TextChanged(Object sender, EventArgs e)
2606 catch (Exception ex)
2608 DisplayException(Name, ex);
2614 /// Provides a central mechanism for exception handling.
2615 /// Displays a message box that describes the exception.
2618 /// <param name="moduleName"> the module where the exception occurred. </param>
2619 /// <param name="e"> the exception </param>
2621 internal static void DisplayException(String moduleName, Exception e)
2623 // Create an error message.
2625 String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
2627 const String caption = "Unexpected Exception";
2629 MessageBox.Show(message, caption, MessageBoxButtons.OK);
2630 Debug.Write(message);
2632 // Get the last error and display it.
2634 Int32 error = Marshal.GetLastWin32Error();
2636 Debug.WriteLine("The last Win32 Error was: " + error);
2640 internal static void Main() { Application.Run(new FrmMain()); }
2641 private static FrmMain _transDefaultFormFrmMain;
2642 internal static FrmMain TransDefaultFormFrmMain
2646 if (_transDefaultFormFrmMain == null)
2648 _transDefaultFormFrmMain = new FrmMain();
2650 return _transDefaultFormFrmMain;