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);
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");
1342 foreach (ManagementObject queryObj in searcher.Get())
1344 if (queryObj["PNPDeviceID"].ToString().Contains(deviceIdString))
1346 _deviceDetected = true;
1347 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1348 MyMarshalDataToForm(FormActions.AddItemToListBox, "My device found (WMI):");
1350 // Display device properties.
1352 foreach (WmiDeviceProperties wmiDeviceProperty in Enum.GetValues(typeof(WmiDeviceProperties)))
1354 MyMarshalDataToForm(FormActions.AddItemToListBox, (wmiDeviceProperty.ToString() + ": " + queryObj[wmiDeviceProperty.ToString()]));
1355 Debug.WriteLine(wmiDeviceProperty.ToString() + ": {0}", queryObj[wmiDeviceProperty.ToString()]);
1357 MyMarshalDataToForm(FormActions.AddItemToListBox, "--------");
1358 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1361 if (!_deviceDetected)
1363 MyMarshalDataToForm(FormActions.AddItemToListBox, "My device not found (WMI)");
1364 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1366 return _deviceDetected;
1368 catch (Exception ex)
1370 DisplayException(Name, ex);
1376 /// Call HID functions that use Win32 API functions to locate a HID-class device
1377 /// by its Vendor ID and Product ID. Open a handle to the device.
1381 /// True if the device is detected, False if not detected.
1384 private Boolean FindTheHid()
1386 var devicePathName = new String[128];
1387 String myDevicePathName = "";
1391 _deviceHandleObtained = false;
1392 CloseCommunications();
1394 // Get the device's Vendor ID and Product ID from the form's text boxes.
1396 GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
1398 // Get the HID-class GUID.
1400 Guid hidGuid = _myHid.GetHidGuid();
1402 String functionName = "GetHidGuid";
1403 Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
1404 Debug.WriteLine(" GUID for system HIDs: " + hidGuid.ToString());
1406 // Fill an array with the device path names of all attached HIDs.
1408 Boolean availableHids = _myDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName);
1410 // If there is at least one HID, attempt to read the Vendor ID and Product ID
1411 // of each device until there is a match or all devices have been examined.
1415 Int32 memberIndex = 0;
1419 // Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice.
1421 _hidHandle = _myHid.OpenHandle(devicePathName[memberIndex], false);
1423 functionName = "CreateFile";
1424 Debug.WriteLine(_myDebugging.ResultOfApiCall(functionName));
1425 Debug.WriteLine(" Returned handle: " + _hidHandle);
1427 if (!_hidHandle.IsInvalid)
1429 // The returned handle is valid,
1430 // so find out if this is the device we're looking for.
1432 _myHid.DeviceAttributes.Size = Marshal.SizeOf(_myHid.DeviceAttributes);
1434 Boolean success = _myHid.GetAttributes(_hidHandle, ref _myHid.DeviceAttributes);
1438 Debug.WriteLine(" HIDD_ATTRIBUTES structure filled without error.");
1439 Debug.WriteLine(" Structure size: " + _myHid.DeviceAttributes.Size);
1440 Debug.WriteLine(" Vendor ID: " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
1441 Debug.WriteLine(" Product ID: " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
1442 Debug.WriteLine(" Version Number: " + Convert.ToString(_myHid.DeviceAttributes.VersionNumber, 16));
1444 if ((_myHid.DeviceAttributes.VendorID == _myVendorId) && (_myHid.DeviceAttributes.ProductID == _myProductId))
1446 Debug.WriteLine(" Handle obtained to my device");
1448 // Display the information in form's list box.
1450 MyMarshalDataToForm(FormActions.AddItemToListBox, "Handle obtained to my device:");
1451 MyMarshalDataToForm(FormActions.AddItemToListBox, " Vendor ID= " + Convert.ToString(_myHid.DeviceAttributes.VendorID, 16));
1452 MyMarshalDataToForm(FormActions.AddItemToListBox, " Product ID = " + Convert.ToString(_myHid.DeviceAttributes.ProductID, 16));
1453 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1455 _deviceHandleObtained = true;
1457 myDevicePathName = devicePathName[memberIndex];
1461 // It's not a match, so close the handle.
1463 _deviceHandleObtained = false;
1469 // There was a problem retrieving the information.
1471 Debug.WriteLine(" Error in filling HIDD_ATTRIBUTES structure.");
1472 _deviceHandleObtained = false;
1477 // Keep looking until we find the device or there are no devices left to examine.
1479 memberIndex = memberIndex + 1;
1481 while (!((_deviceHandleObtained || (memberIndex == devicePathName.Length))));
1484 if (_deviceHandleObtained)
1486 // The device was detected.
1487 // Learn the capabilities of the device.
1489 _myHid.Capabilities = _myHid.GetDeviceCapabilities(_hidHandle);
1491 // Find out if the device is a system mouse or keyboard.
1493 _hidUsage = _myHid.GetHidUsage(_myHid.Capabilities);
1495 // Get the Input report buffer size.
1497 GetInputReportBufferSize();
1498 MyMarshalDataToForm(FormActions.EnableInputReportBufferSize, "");
1500 //Close the handle and reopen it with read/write access.
1504 _hidHandle = _myHid.OpenHandle(myDevicePathName, true);
1506 if (_hidHandle.IsInvalid)
1508 MyMarshalDataToForm(FormActions.AddItemToListBox, "The device is a system " + _hidUsage + ".");
1509 MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 2000 and later obtain exclusive access to Input and Output reports for this devices.");
1510 MyMarshalDataToForm(FormActions.AddItemToListBox, "Windows 8 also obtains exclusive access to Feature reports.");
1511 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1515 if (_myHid.Capabilities.InputReportByteLength > 0)
1517 // Set the size of the Input report buffer.
1519 var inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
1521 _deviceData = new FileStream(_hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false);
1524 if (_myHid.Capabilities.OutputReportByteLength > 0)
1526 Byte[] outputReportBuffer = null;
1528 // Flush any waiting reports in the input buffer. (optional)
1530 _myHid.FlushQueue(_hidHandle);
1535 MyMarshalDataToForm(FormActions.AddItemToListBox, "Device not found.");
1536 MyMarshalDataToForm(FormActions.DisableInputReportBufferSize, "");
1537 EnableFormControls();
1538 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1540 return _deviceHandleObtained;
1542 catch (Exception ex)
1544 DisplayException(Name, ex);
1550 /// Perform shutdown operations.
1553 private void frmMain_Closed(Object eventSender, EventArgs eventArgs)
1559 catch (Exception ex)
1561 DisplayException(Name, ex);
1567 /// Perform startup operations.
1570 private void frmMain_Load(Object eventSender, EventArgs eventArgs)
1577 catch (Exception ex)
1579 DisplayException(Name, ex);
1584 private void GetBytesToSend()
1588 // Get the bytes to send in a report from the combo boxes.
1589 // Increment the values if the autoincrement check box is selected.
1591 if (ChkAutoincrement.Checked)
1593 if (CboByte0.SelectedIndex < 255)
1595 CboByte0.SelectedIndex = CboByte0.SelectedIndex + 1;
1599 CboByte0.SelectedIndex = 0;
1601 if (CboByte1.SelectedIndex < 255)
1603 CboByte1.SelectedIndex = CboByte1.SelectedIndex + 1;
1607 CboByte1.SelectedIndex = 0;
1611 catch (Exception ex)
1613 DisplayException(Name, ex);
1619 /// Find and display the number of Input buffers
1620 /// (the number of Input reports the HID driver will store).
1623 private void GetInputReportBufferSize()
1625 Int32 numberOfInputBuffers = 0;
1630 // Get the number of input buffers.
1632 _myHid.GetNumberOfInputBuffers(_hidHandle, ref numberOfInputBuffers);
1634 // Display the result in the text box.
1636 MyMarshalDataToForm(FormActions.SetInputReportBufferSize, Convert.ToString(numberOfInputBuffers));
1638 catch (Exception ex)
1640 DisplayException(Name, ex);
1646 /// Retrieve a Vendor ID and Product ID in hexadecimal
1647 /// from the form's text boxes and convert the text to Int32s.
1650 /// <param name="myVendorId"> the Vendor ID</param>
1651 /// <param name="myProductId"> the Product ID</param>
1653 private void GetVendorAndProductIDsFromTextBoxes(ref Int32 myVendorId, ref Int32 myProductId)
1657 myVendorId = Int32.Parse(txtVendorID.Text, NumberStyles.AllowHexSpecifier);
1658 myProductId = Int32.Parse(txtProductID.Text, NumberStyles.AllowHexSpecifier);
1660 catch (Exception ex)
1662 DisplayException(Name, ex);
1668 /// Initialize the elements on the form.
1671 private void InitializeDisplay()
1675 // Create a dropdown list box for each byte to send in a report.
1676 // Display the values as 2-character hex strings.
1679 for (count = 0; count <= 255; count++)
1681 String byteValue = String.Format("{0:X2} ", count);
1682 FrmMy.CboByte0.Items.Insert(count, byteValue);
1683 FrmMy.CboByte1.Items.Insert(count, byteValue);
1686 // Select a default value for each box
1688 FrmMy.CboByte0.SelectedIndex = 0;
1689 FrmMy.CboByte1.SelectedIndex = 128;
1690 FrmMy.radInputOutputInterrupt.Checked = true;
1692 // Check the autoincrement box to increment the values each time a report is sent.
1694 ChkAutoincrement.CheckState = CheckState.Checked;
1696 // Don't allow the user to select an input report buffer size until there is
1697 // a handle to a HID.
1699 cmdInputReportBufferSize.Focus();
1700 cmdInputReportBufferSize.Enabled = false;
1702 LstResults.Items.Add("For a more detailed event log, view debug statements in Visual Studio's Output window:");
1703 LstResults.Items.Add("Click Build > Configuration Manager > Active Solution Configuration > Debug > Close.");
1704 LstResults.Items.Add("Then click View > Output.");
1705 LstResults.Items.Add("");
1707 catch (Exception ex)
1709 DisplayException(Name, ex);
1715 /// Enables accessing a form's controls from another thread
1718 /// <param name="action"> a FormActions member that names the action to perform on the form </param>
1719 /// <param name="textToDisplay"> text that the form displays or the code uses for
1720 /// another purpose. Actions that don't use text ignore this parameter. </param>
1722 private void MyMarshalDataToForm(FormActions action, String textToDisplay)
1726 object[] args = { action, textToDisplay };
1728 // The AccessForm routine contains the code that accesses the form.
1730 MarshalDataToForm marshalDataToFormDelegate = AccessForm;
1732 // Execute AccessForm, passing the parameters in args.
1734 Invoke(marshalDataToFormDelegate, args);
1736 catch (Exception ex)
1738 DisplayException(Name, ex);
1744 /// Timeout if read via interrupt transfer doesn't return.
1747 private void OnReadTimeout()
1751 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a report timed out.");
1752 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1753 CloseCommunications();
1754 MyMarshalDataToForm(FormActions.EnableGetInputReportInterruptTransfer, "");
1755 _transferInProgress = false;
1756 _sendOrGet = SendOrGet.Send;
1758 catch (Exception ex)
1760 DisplayException(Name, ex);
1766 /// Timeout if write via interrupt transfer doesn't return.
1769 private void OnWriteTimeout()
1773 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to write a report timed out.");
1774 MyMarshalDataToForm(FormActions.ScrollToBottomOfListBox, "");
1775 CloseCommunications();
1776 MyMarshalDataToForm(FormActions.EnableSendOutputReportInterrupt, "");
1777 _transferInProgress = false;
1778 _sendOrGet = SendOrGet.Get;
1780 catch (Exception ex)
1782 DisplayException(Name, ex);
1788 /// Alternat sending and getting a report.
1791 private void PeriodicTransfers()
1795 if (!_transferInProgress)
1797 if (_reportType == ReportTypes.Feature)
1799 SendOrGetFeatureReport();
1803 // Output and Input reports
1805 SendOutputReportOrGetInputReport();
1809 catch (Exception ex)
1811 DisplayException(Name, ex);
1817 /// Start doing periodic transfers.
1820 private void PeriodicTransfersStart()
1822 // Don't allow changing the transfer type while transfers are in progress.
1824 if (radFeature.Checked)
1826 radInputOutputControl.Enabled = false;
1827 radInputOutputInterrupt.Enabled = false;
1829 else if (radInputOutputControl.Checked)
1831 radFeature.Enabled = false;
1832 radInputOutputInterrupt.Enabled = false;
1834 else if (radInputOutputInterrupt.Checked)
1836 radFeature.Enabled = false;
1837 radInputOutputControl.Enabled = false;
1840 // Change the command button's text.
1842 cmdPeriodicTransfers.Text = "Stop";
1844 // Enable the timer event to trigger a set of transfers.
1846 _periodicTransfers.Start();
1848 cmdPeriodicTransfers.Enabled = true;
1850 if (radInputOutputInterrupt.Checked)
1852 _transferType = TransferTypes.Interrupt;
1853 _reportType = ReportTypes.Output;
1855 else if (radInputOutputControl.Checked)
1857 _transferType = TransferTypes.Control;
1858 _reportType = ReportTypes.Output;
1860 else if (radFeature.Checked)
1862 _transferType = TransferTypes.Control;
1863 _reportType = ReportTypes.Feature;
1865 _periodicTransfersRequested = true;
1866 PeriodicTransfers();
1870 /// Stop doing periodic transfers.
1873 private void PeriodicTransfersStop()
1875 // Stop doing continuous transfers.
1877 _periodicTransfersRequested = false;
1879 // Disable the timer that triggers the transfers.
1881 _periodicTransfers.Stop();
1882 cmdPeriodicTransfers.Enabled = true;
1884 // Change the command button's text.
1886 cmdPeriodicTransfers.Text = "Start";
1888 // Re-allow changing the transfer type.
1890 radFeature.Enabled = true;
1891 radInputOutputControl.Enabled = true;
1892 radInputOutputInterrupt.Enabled = true;
1895 private void radInputOutputControl_CheckedChanged(object sender, EventArgs e)
1899 private void radInputOutputInterrupt_CheckedChanged(object sender, EventArgs e)
1903 private void radFeature_CheckedChanged(object sender, EventArgs e)
1908 /// Request a Feature report.
1909 /// Assumes report ID = 0.
1912 private void RequestToGetFeatureReport()
1914 String byteValue = null;
1918 // If the device hasn't been detected, was removed, or timed out on a previous attempt
1919 // to access it, look for the device.
1921 if (!_deviceHandleObtained)
1923 _deviceHandleObtained = FindTheHid();
1926 if (_deviceHandleObtained)
1928 Byte[] inFeatureReportBuffer = null;
1930 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
1932 // The HID has a Feature report.
1933 // Read a report from the device.
1935 // Set the size of the Feature report buffer.
1937 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
1939 inFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
1944 Boolean success = _myHid.GetFeatureReport(_hidHandle, ref inFeatureReportBuffer);
1948 DisplayReportData(inFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Read);
1952 CloseCommunications();
1953 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read a Feature report failed.");
1954 ScrollToBottomOfListBox();
1959 MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
1960 ScrollToBottomOfListBox();
1963 _transferInProgress = false;
1964 cmdGetFeatureReport.Enabled = true;
1966 catch (Exception ex)
1968 DisplayException(Name, ex);
1974 /// Request an Input report.
1975 /// Assumes report ID = 0.
1978 private async void RequestToGetInputReport()
1980 const Int32 readTimeout = 5000;
1982 String byteValue = null;
1983 Byte[] inputReportBuffer = null;
1987 Boolean success = false;
1989 // If the device hasn't been detected, was removed, or timed out on a previous attempt
1990 // to access it, look for the device.
1992 if (!_deviceHandleObtained)
1994 _deviceHandleObtained = FindTheHid();
1997 if (_deviceHandleObtained)
1999 // Don't attempt to exchange reports if valid handles aren't available
2000 // (as for a mouse or keyboard under Windows 2000 and later.)
2002 if (!_hidHandle.IsInvalid)
2004 // Read an Input report.
2006 // Don't attempt to send an Input report if the HID has no Input report.
2007 // (The HID spec requires all HIDs to have an interrupt IN endpoint,
2008 // which suggests that all HIDs must support Input reports.)
2010 if (_myHid.Capabilities.InputReportByteLength > 0)
2012 // Set the size of the Input report buffer.
2014 inputReportBuffer = new Byte[_myHid.Capabilities.InputReportByteLength];
2016 if (_transferType.Equals(TransferTypes.Control))
2019 _transferInProgress = true;
2021 // Read a report using a control transfer.
2023 success = _myHid.GetInputReportViaControlTransfer(_hidHandle, ref inputReportBuffer);
2024 cmdGetInputReportControl.Enabled = true;
2025 _transferInProgress = false;
2031 _transferInProgress = true;
2033 // Read a report using interrupt transfers.
2034 // Timeout if no report available.
2035 // To enable reading a report without blocking the calling thread, uses Filestream's ReadAsync method.
2037 // Create a delegate to execute on a timeout.
2039 Action onReadTimeoutAction = OnReadTimeout;
2041 // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
2043 var cts = new CancellationTokenSource();
2045 // Cancel the read if it hasn't completed after a timeout.
2047 cts.CancelAfter(readTimeout);
2049 // Specify the function to call on a timeout.
2051 cts.Token.Register(onReadTimeoutAction);
2053 // Stops waiting when data is available or on timeout:
2055 Int32 bytesRead = await _myHid.GetInputReportViaInterruptTransfer(_deviceData, inputReportBuffer, cts);
2057 // Arrive here only if the operation completed.
2059 // Dispose to stop the timeout timer.
2063 _transferInProgress = false;
2064 cmdGetInputReportInterrupt.Enabled = true;
2069 Debug.Print("bytes read (includes report ID) = " + Convert.ToString(bytesRead));
2076 MyMarshalDataToForm(FormActions.AddItemToListBox, "No attempt to read an Input report was made.");
2077 MyMarshalDataToForm(FormActions.AddItemToListBox, "The HID doesn't have an Input report.");
2082 MyMarshalDataToForm(FormActions.AddItemToListBox, "Invalid handle.");
2083 MyMarshalDataToForm(FormActions.AddItemToListBox,
2084 "No attempt to write an Output report or read an Input report was made.");
2089 DisplayReportData(inputReportBuffer, ReportTypes.Input, ReportReadOrWritten.Read);
2093 CloseCommunications();
2094 MyMarshalDataToForm(FormActions.AddItemToListBox, "The attempt to read an Input report has failed.");
2095 ScrollToBottomOfListBox();
2100 catch (Exception ex)
2102 DisplayException(Name, ex);
2108 /// Sends a Feature report.
2109 /// Assumes report ID = 0.
2112 private void RequestToSendFeatureReport()
2114 String byteValue = null;
2118 _transferInProgress = true;
2120 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2121 // to access it, look for the device.
2123 if (!_deviceHandleObtained)
2125 _deviceHandleObtained = FindTheHid();
2128 if (_deviceHandleObtained)
2132 if ((_myHid.Capabilities.FeatureReportByteLength > 0))
2134 // The HID has a Feature report.
2135 // Set the size of the Feature report buffer.
2137 var outFeatureReportBuffer = new Byte[_myHid.Capabilities.FeatureReportByteLength];
2139 // Store the report ID in the buffer.
2141 outFeatureReportBuffer[0] = 0;
2143 // Store the report data following the report ID.
2144 // Use the data in the combo boxes on the form.
2146 outFeatureReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
2148 if (outFeatureReportBuffer.GetUpperBound(0) > 1)
2150 outFeatureReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
2153 // Write a report to the device
2155 Boolean success = _myHid.SendFeatureReport(_hidHandle, outFeatureReportBuffer);
2159 DisplayReportData(outFeatureReportBuffer, ReportTypes.Feature, ReportReadOrWritten.Written);
2163 CloseCommunications();
2164 AccessForm(FormActions.AddItemToListBox, "The attempt to send a Feature report failed.");
2165 ScrollToBottomOfListBox();
2171 AccessForm(FormActions.AddItemToListBox, "The HID doesn't have a Feature report.");
2172 ScrollToBottomOfListBox();
2176 _transferInProgress = false;
2177 cmdSendFeatureReport.Enabled = true;
2178 ScrollToBottomOfListBox();
2181 catch (Exception ex)
2183 DisplayException(Name, ex);
2189 /// Sends an Output report.
2190 /// Assumes report ID = 0.
2193 private async void RequestToSendOutputReport()
2195 const Int32 writeTimeout = 5000;
2196 String byteValue = null;
2200 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2201 // to access it, look for the device.
2203 if (!_deviceHandleObtained)
2205 _deviceHandleObtained = FindTheHid();
2208 if (_deviceHandleObtained)
2212 // Don't attempt to exchange reports if valid handles aren't available
2213 // (as for a mouse or keyboard.)
2215 if (!_hidHandle.IsInvalid)
2217 // Don't attempt to send an Output report if the HID has no Output report.
2219 if (_myHid.Capabilities.OutputReportByteLength > 0)
2221 // Set the size of the Output report buffer.
2223 var outputReportBuffer = new Byte[_myHid.Capabilities.OutputReportByteLength];
2225 // Store the report ID in the first byte of the buffer:
2227 outputReportBuffer[0] = 0;
2229 // Store the report data following the report ID.
2230 // Use the data in the combo boxes on the form.
2232 outputReportBuffer[1] = Convert.ToByte(CboByte0.SelectedIndex);
2234 if (outputReportBuffer.GetUpperBound(0) > 1)
2236 outputReportBuffer[2] = Convert.ToByte(CboByte1.SelectedIndex);
2243 if (_transferType.Equals(TransferTypes.Control))
2246 _transferInProgress = true;
2248 // Use a control transfer to send the report,
2249 // even if the HID has an interrupt OUT endpoint.
2251 success = _myHid.SendOutputReportViaControlTransfer(_hidHandle, outputReportBuffer);
2253 _transferInProgress = false;
2254 cmdSendOutputReportControl.Enabled = true;
2259 Debug.Print("interrupt");
2260 _transferInProgress = true;
2262 // The CancellationTokenSource specifies the timeout value and the action to take on a timeout.
2264 var cts = new CancellationTokenSource();
2266 // Create a delegate to execute on a timeout.
2268 Action onWriteTimeoutAction = OnWriteTimeout;
2270 // Cancel the read if it hasn't completed after a timeout.
2272 cts.CancelAfter(writeTimeout);
2274 // Specify the function to call on a timeout.
2276 cts.Token.Register(onWriteTimeoutAction);
2278 // Send an Output report and wait for completion or timeout.
2280 success = await _myHid.SendOutputReportViaInterruptTransfer(_deviceData, _hidHandle, outputReportBuffer, cts);
2282 // Get here only if the operation completes without a timeout.
2284 _transferInProgress = false;
2285 cmdSendOutputReportInterrupt.Enabled = true;
2287 // Dispose to stop the timeout timer.
2293 DisplayReportData(outputReportBuffer, ReportTypes.Output, ReportReadOrWritten.Written);
2297 CloseCommunications();
2298 AccessForm(FormActions.AddItemToListBox, "The attempt to write an Output report failed.");
2299 ScrollToBottomOfListBox();
2305 AccessForm(FormActions.AddItemToListBox, "The HID doesn't have an Output report.");
2309 catch (Exception ex)
2311 DisplayException(Name, ex);
2317 /// Scroll to the bottom of the list box and trim as needed.
2320 private void ScrollToBottomOfListBox()
2324 LstResults.SelectedIndex = LstResults.Items.Count - 1;
2326 // If the list box is getting too large, trim its contents by removing the earliest data.
2328 if (LstResults.Items.Count > 1000)
2331 for (count = 1; count <= 500; count++)
2333 LstResults.Items.RemoveAt(4);
2337 catch (Exception ex)
2339 DisplayException(Name, ex);
2345 /// Request to send or get a Feature report.
2348 private void SendOrGetFeatureReport()
2352 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2353 // to access it, look for the device.
2355 if (!_deviceHandleObtained)
2357 _deviceHandleObtained = FindTheHid();
2360 if (_deviceHandleObtained)
2364 case SendOrGet.Send:
2365 RequestToSendFeatureReport();
2366 _sendOrGet = SendOrGet.Get;
2369 RequestToGetFeatureReport();
2370 _sendOrGet = SendOrGet.Send;
2375 catch (Exception ex)
2377 DisplayException(Name, ex);
2383 /// Request to send an Output report or get an Input report.
2386 private void SendOutputReportOrGetInputReport()
2390 // If the device hasn't been detected, was removed, or timed out on a previous attempt
2391 // to access it, look for the device.
2393 if (!_deviceHandleObtained)
2395 _deviceHandleObtained = FindTheHid();
2398 if (_deviceHandleObtained)
2400 if (_sendOrGet == SendOrGet.Send)
2402 RequestToSendOutputReport();
2403 _sendOrGet = SendOrGet.Get;
2407 RequestToGetInputReport();
2408 _sendOrGet = SendOrGet.Send;
2412 catch (Exception ex)
2414 DisplayException(Name, ex);
2420 /// Set the number of Input buffers (the number of Input reports
2421 /// the host will store) from the value in the text box.
2424 private void SetInputReportBufferSize()
2428 if (!_transferInProgress)
2430 // Get the number of buffers from the text box.
2432 Int32 numberOfInputBuffers = Convert.ToInt32(txtInputReportBufferSize.Text);
2434 // Set the number of buffers.
2436 _myHid.SetNumberOfInputBuffers(_hidHandle, numberOfInputBuffers);
2438 // Verify and display the result.
2440 GetInputReportBufferSize();
2444 DisplayTransferInProgressMessage();
2447 catch (Exception ex)
2449 DisplayException(Name, ex);
2455 /// Perform actions that must execute when the program ends.
2458 private void Shutdown()
2462 CloseCommunications();
2463 DeviceNotificationsStop();
2465 catch (Exception ex)
2467 DisplayException(Name, ex);
2473 /// Perform actions that must execute when the program starts.
2476 private void Startup()
2478 const Int32 periodicTransferInterval = 1000;
2482 InitializeDisplay();
2484 _periodicTransfers = new System.Timers.Timer(periodicTransferInterval);
2485 _periodicTransfers.Elapsed += DoPeriodicTransfers;
2486 _periodicTransfers.Stop();
2487 _periodicTransfers.SynchronizingObject = this;
2489 // Default USB Vendor ID and Product ID:
2491 txtVendorID.Text = "0925";
2492 txtProductID.Text = "7001";
2494 GetVendorAndProductIDsFromTextBoxes(ref _myVendorId, ref _myProductId);
2496 DeviceNotificationsStart();
2497 FindDeviceUsingWmi();
2500 catch (Exception ex)
2502 DisplayException(Name, ex);
2508 /// The Product ID has changed in the text box. Call a routine to handle it.
2511 private void txtProductID_TextChanged(Object sender, EventArgs e)
2517 catch (Exception ex)
2519 DisplayException(Name, ex);
2525 /// The Vendor ID has changed in the text box. Call a routine to handle it.
2528 private void txtVendorID_TextChanged(Object sender, EventArgs e)
2534 catch (Exception ex)
2536 DisplayException(Name, ex);
2542 /// Provides a central mechanism for exception handling.
2543 /// Displays a message box that describes the exception.
2546 /// <param name="moduleName"> the module where the exception occurred. </param>
2547 /// <param name="e"> the exception </param>
2549 internal static void DisplayException(String moduleName, Exception e)
2551 // Create an error message.
2553 String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
2555 const String caption = "Unexpected Exception";
2557 MessageBox.Show(message, caption, MessageBoxButtons.OK);
2558 Debug.Write(message);
2560 // Get the last error and display it.
2562 Int32 error = Marshal.GetLastWin32Error();
2564 Debug.WriteLine("The last Win32 Error was: " + error);
2568 internal static void Main() { Application.Run(new FrmMain()); }
2569 private static FrmMain _transDefaultFormFrmMain;
2570 internal static FrmMain TransDefaultFormFrmMain
2574 if (_transDefaultFormFrmMain == null)
2576 _transDefaultFormFrmMain = new FrmMain();
2578 return _transDefaultFormFrmMain;