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