Hid.cs
author sl
Wed, 14 May 2014 16:37:44 +0200
changeset 4 0220435cf48a
child 7 5680e56e9b0b
permissions -rw-r--r--
Newly added device are now showing green. Removed devices are showing red.
Other devices are showing black. Devices in unknown state are showing purple.
sl@0
     1
using Microsoft.Win32.SafeHandles;
sl@0
     2
using System;
sl@0
     3
using System.Diagnostics;
sl@0
     4
using System.IO;
sl@0
     5
using System.Runtime.InteropServices;
sl@0
     6
using System.Threading;
sl@0
     7
using System.Threading.Tasks;
sl@0
     8
using System.Windows.Forms;
sl@0
     9
sl@0
    10
namespace GenericHid
sl@0
    11
{
sl@0
    12
	///  <summary>
sl@0
    13
	///  Supports Windows API functions for accessing HID-class USB devices.
sl@0
    14
	///  Includes routines for retrieving information about the configuring a HID and 
sl@0
    15
	///  sending and receiving reports via control and interrupt transfers. 
sl@0
    16
	///  </summary>
sl@0
    17
sl@0
    18
	internal sealed partial class Hid
sl@0
    19
	{
sl@0
    20
		//  Used in error messages.
sl@0
    21
sl@0
    22
		private const String ModuleName = "Hid";
sl@0
    23
sl@0
    24
		internal NativeMethods.HIDP_CAPS Capabilities;
sl@0
    25
		internal NativeMethods.HIDD_ATTRIBUTES DeviceAttributes;
sl@0
    26
sl@0
    27
		//  For viewing results of API calls in debug.write statements:
sl@0
    28
sl@0
    29
		internal static Debugging MyDebugging = new Debugging();
sl@0
    30
sl@0
    31
		///  <summary>
sl@0
    32
		///  Provides a central mechanism for exception handling.
sl@0
    33
		///  Displays a message box that describes the exception.
sl@0
    34
		///  </summary>
sl@0
    35
		///  
sl@0
    36
		///  <param name="moduleName">  the module where the exception occurred. </param>
sl@0
    37
		///  <param name="e"> the exception </param>
sl@0
    38
sl@0
    39
		internal static void DisplayException(String moduleName, Exception e)
sl@0
    40
		{
sl@0
    41
			//  Create an error message.
sl@0
    42
sl@0
    43
			String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + moduleName + Environment.NewLine + "Method: " + e.TargetSite.Name;
sl@0
    44
sl@0
    45
			const String caption = "Unexpected Exception";
sl@0
    46
sl@0
    47
			MessageBox.Show(message, caption, MessageBoxButtons.OK);
sl@0
    48
			Debug.Write(message);
sl@0
    49
sl@0
    50
			// Get the last error and display it. 
sl@0
    51
			Int32 error = Marshal.GetLastWin32Error();
sl@0
    52
sl@0
    53
			Debug.WriteLine("The last Win32 Error was: " + error);
sl@0
    54
		}
sl@0
    55
sl@0
    56
		///  <summary>
sl@0
    57
		///  Remove any Input reports waiting in the buffer.
sl@0
    58
		///  </summary>
sl@0
    59
		///  <param name="hidHandle"> a handle to a device.   </param>
sl@0
    60
		///  <returns>
sl@0
    61
		///  True on success, False on failure.
sl@0
    62
		///  </returns>
sl@0
    63
sl@0
    64
		internal Boolean FlushQueue(SafeFileHandle hidHandle)
sl@0
    65
		{
sl@0
    66
			try
sl@0
    67
			{
sl@0
    68
				//  ***
sl@0
    69
				//  API function: HidD_FlushQueue
sl@0
    70
sl@0
    71
				//  Purpose: Removes any Input reports waiting in the buffer.
sl@0
    72
sl@0
    73
				//  Accepts: a handle to the device.
sl@0
    74
sl@0
    75
				//  Returns: True on success, False on failure.
sl@0
    76
				//  ***
sl@0
    77
sl@0
    78
				Boolean success = NativeMethods.HidD_FlushQueue(hidHandle);
sl@0
    79
sl@0
    80
				return success;
sl@0
    81
			}
sl@0
    82
sl@0
    83
			catch (Exception ex)
sl@0
    84
			{
sl@0
    85
				DisplayException(ModuleName, ex);
sl@0
    86
				throw;
sl@0
    87
			}
sl@0
    88
		}
sl@0
    89
sl@0
    90
		/// <summary>
sl@0
    91
		/// Get HID attributes.
sl@0
    92
		/// </summary>
sl@0
    93
		/// <param name="hidHandle"> HID handle retrieved with CreateFile </param>
sl@0
    94
		/// <param name="deviceAttributes"> HID attributes structure </param>
sl@0
    95
		/// <returns> true on success </returns>
sl@0
    96
sl@0
    97
		internal Boolean GetAttributes(SafeFileHandle hidHandle, ref NativeMethods.HIDD_ATTRIBUTES deviceAttributes)
sl@0
    98
		{
sl@0
    99
			Boolean success;
sl@0
   100
			try
sl@0
   101
			{
sl@0
   102
				//  ***
sl@0
   103
				//  API function:
sl@0
   104
				//  HidD_GetAttributes
sl@0
   105
sl@0
   106
				//  Purpose:
sl@0
   107
				//  Retrieves a HIDD_ATTRIBUTES structure containing the Vendor ID, 
sl@0
   108
				//  Product ID, and Product Version Number for a device.
sl@0
   109
sl@0
   110
				//  Accepts:
sl@0
   111
				//  A handle returned by CreateFile.
sl@0
   112
				//  A pointer to receive a HIDD_ATTRIBUTES structure.
sl@0
   113
sl@0
   114
				//  Returns:
sl@0
   115
				//  True on success, False on failure.
sl@0
   116
				//  ***                            
sl@0
   117
sl@0
   118
				success = NativeMethods.HidD_GetAttributes(hidHandle, ref deviceAttributes);
sl@0
   119
			}
sl@0
   120
sl@0
   121
			catch (Exception ex)
sl@0
   122
			{
sl@0
   123
				DisplayException(ModuleName, ex);
sl@0
   124
				throw;
sl@0
   125
			}
sl@0
   126
			return success;
sl@0
   127
		}
sl@0
   128
sl@0
   129
		///  <summary>
sl@0
   130
		///  Retrieves a structure with information about a device's capabilities. 
sl@0
   131
		///  </summary>
sl@0
   132
		///  
sl@0
   133
		///  <param name="hidHandle"> a handle to a device. </param>
sl@0
   134
		///  
sl@0
   135
		///  <returns>
sl@0
   136
		///  An HIDP_CAPS structure.
sl@0
   137
		///  </returns>
sl@0
   138
sl@0
   139
		internal NativeMethods.HIDP_CAPS GetDeviceCapabilities(SafeFileHandle hidHandle)
sl@0
   140
		{
sl@0
   141
			var preparsedData = new IntPtr();
sl@0
   142
sl@0
   143
			try
sl@0
   144
			{
sl@0
   145
				//  ***
sl@0
   146
				//  API function: HidD_GetPreparsedData
sl@0
   147
sl@0
   148
				//  Purpose: retrieves a pointer to a buffer containing information about the device's capabilities.
sl@0
   149
				//  HidP_GetCaps and other API functions require a pointer to the buffer.
sl@0
   150
sl@0
   151
				//  Requires: 
sl@0
   152
				//  A handle returned by CreateFile.
sl@0
   153
				//  A pointer to a buffer.
sl@0
   154
sl@0
   155
				//  Returns:
sl@0
   156
				//  True on success, False on failure.
sl@0
   157
				//  ***
sl@0
   158
sl@0
   159
				NativeMethods.HidD_GetPreparsedData(hidHandle, ref preparsedData);
sl@0
   160
sl@0
   161
				//  ***
sl@0
   162
				//  API function: HidP_GetCaps
sl@0
   163
sl@0
   164
				//  Purpose: find out a device's capabilities.
sl@0
   165
				//  For standard devices such as joysticks, you can find out the specific
sl@0
   166
				//  capabilities of the device.
sl@0
   167
				//  For a custom device where the software knows what the device is capable of,
sl@0
   168
				//  this call may be unneeded.
sl@0
   169
sl@0
   170
				//  Accepts:
sl@0
   171
				//  A pointer returned by HidD_GetPreparsedData
sl@0
   172
				//  A pointer to a HIDP_CAPS structure.
sl@0
   173
sl@0
   174
				//  Returns: True on success, False on failure.
sl@0
   175
				//  ***
sl@0
   176
sl@0
   177
				Int32 result = NativeMethods.HidP_GetCaps(preparsedData, ref Capabilities);
sl@0
   178
				if ((result != 0))
sl@0
   179
				{
sl@0
   180
					Debug.WriteLine("");
sl@0
   181
					Debug.WriteLine("  Usage: " + Convert.ToString(Capabilities.Usage, 16));
sl@0
   182
					Debug.WriteLine("  Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
sl@0
   183
					Debug.WriteLine("  Input Report Byte Length: " + Capabilities.InputReportByteLength);
sl@0
   184
					Debug.WriteLine("  Output Report Byte Length: " + Capabilities.OutputReportByteLength);
sl@0
   185
					Debug.WriteLine("  Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
sl@0
   186
					Debug.WriteLine("  Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
sl@0
   187
					Debug.WriteLine("  Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
sl@0
   188
					Debug.WriteLine("  Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
sl@0
   189
					Debug.WriteLine("  Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
sl@0
   190
					Debug.WriteLine("  Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
sl@0
   191
					Debug.WriteLine("  Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
sl@0
   192
					Debug.WriteLine("  Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
sl@0
   193
					Debug.WriteLine("  Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
sl@0
   194
					Debug.WriteLine("  Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
sl@0
   195
					Debug.WriteLine("  Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);
sl@0
   196
sl@0
   197
					//  ***
sl@0
   198
					//  API function: HidP_GetValueCaps
sl@0
   199
sl@0
   200
					//  Purpose: retrieves a buffer containing an array of HidP_ValueCaps structures.
sl@0
   201
					//  Each structure defines the capabilities of one value.
sl@0
   202
					//  This application doesn't use this data.
sl@0
   203
sl@0
   204
					//  Accepts:
sl@0
   205
					//  A report type enumerator from hidpi.h,
sl@0
   206
					//  A pointer to a buffer for the returned array,
sl@0
   207
					//  The NumberInputValueCaps member of the device's HidP_Caps structure,
sl@0
   208
					//  A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.
sl@0
   209
sl@0
   210
					//  Returns: True on success, False on failure.
sl@0
   211
					//  ***                    
sl@0
   212
sl@0
   213
					Int32 vcSize = Capabilities.NumberInputValueCaps;
sl@0
   214
					var valueCaps = new Byte[vcSize];
sl@0
   215
sl@0
   216
					NativeMethods.HidP_GetValueCaps(NativeMethods.HidP_Input, valueCaps, ref vcSize, preparsedData);
sl@0
   217
sl@0
   218
					// (To use this data, copy the ValueCaps byte array into an array of structures.)              
sl@0
   219
				}
sl@0
   220
			}
sl@0
   221
sl@0
   222
			catch (Exception ex)
sl@0
   223
			{
sl@0
   224
				DisplayException(ModuleName, ex);
sl@0
   225
				throw;
sl@0
   226
			}
sl@0
   227
			finally
sl@0
   228
			{
sl@0
   229
				//  ***
sl@0
   230
				//  API function: HidD_FreePreparsedData
sl@0
   231
sl@0
   232
				//  Purpose: frees the buffer reserved by HidD_GetPreparsedData.
sl@0
   233
sl@0
   234
				//  Accepts: A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.
sl@0
   235
sl@0
   236
				//  Returns: True on success, False on failure.
sl@0
   237
				//  ***
sl@0
   238
sl@0
   239
				if (preparsedData != IntPtr.Zero)
sl@0
   240
				{
sl@0
   241
					NativeMethods.HidD_FreePreparsedData(preparsedData);
sl@0
   242
				}
sl@0
   243
			}
sl@0
   244
			return Capabilities;
sl@0
   245
		}
sl@0
   246
sl@0
   247
		///  <summary>
sl@0
   248
		///  reads a Feature report from the device.
sl@0
   249
		///  </summary>
sl@0
   250
		///  
sl@0
   251
		///  <param name="hidHandle"> the handle for learning about the device and exchanging Feature reports. </param>	
sl@0
   252
		///  <param name="inFeatureReportBuffer"> contains the requested report.</param>
sl@0
   253
sl@0
   254
		internal Boolean GetFeatureReport(SafeFileHandle hidHandle, ref Byte[] inFeatureReportBuffer)
sl@0
   255
		{
sl@0
   256
			try
sl@0
   257
			{
sl@0
   258
				Boolean success = false;
sl@0
   259
sl@0
   260
				//  ***
sl@0
   261
				//  API function: HidD_GetFeature
sl@0
   262
				//  Attempts to read a Feature report from the device.
sl@0
   263
sl@0
   264
				//  Requires:
sl@0
   265
				//  A handle to a HID
sl@0
   266
				//  A pointer to a buffer containing the report ID and report
sl@0
   267
				//  The size of the buffer. 
sl@0
   268
sl@0
   269
				//  Returns: true on success, false on failure.
sl@0
   270
				//  ***                    
sl@0
   271
sl@0
   272
				if (!hidHandle.IsInvalid && !hidHandle.IsClosed)
sl@0
   273
				{
sl@0
   274
					success = NativeMethods.HidD_GetFeature(hidHandle, inFeatureReportBuffer, inFeatureReportBuffer.Length);
sl@0
   275
sl@0
   276
					Debug.Print("HidD_GetFeature success = " + success);
sl@0
   277
				}
sl@0
   278
				return success;
sl@0
   279
			}
sl@0
   280
sl@0
   281
			catch (Exception ex)
sl@0
   282
			{
sl@0
   283
				DisplayException(ModuleName, ex);
sl@0
   284
				throw;
sl@0
   285
			}
sl@0
   286
		}
sl@0
   287
sl@0
   288
		/// <summary>
sl@0
   289
		/// Get the HID-class GUID
sl@0
   290
		/// </summary>
sl@0
   291
		/// <returns> the GUID </returns>
sl@0
   292
sl@0
   293
		internal Guid GetHidGuid()
sl@0
   294
		{
sl@0
   295
			Guid hidGuid = Guid.Empty;
sl@0
   296
			try
sl@0
   297
			{
sl@0
   298
				//  ***
sl@0
   299
				//  API function: 'HidD_GetHidGuid
sl@0
   300
sl@0
   301
				//  Purpose: Retrieves the interface class GUID for the HID class.
sl@0
   302
sl@0
   303
				//  Accepts: A System.Guid object for storing the GUID.
sl@0
   304
				//  ***
sl@0
   305
sl@0
   306
				NativeMethods.HidD_GetHidGuid(ref hidGuid);
sl@0
   307
			}
sl@0
   308
sl@0
   309
			catch (Exception ex)
sl@0
   310
			{
sl@0
   311
				DisplayException(ModuleName, ex);
sl@0
   312
				throw;
sl@0
   313
			}
sl@0
   314
			return hidGuid;
sl@0
   315
		}
sl@0
   316
sl@0
   317
		///  <summary>
sl@0
   318
		///  Creates a 32-bit Usage from the Usage Page and Usage ID. 
sl@0
   319
		///  Determines whether the Usage is a system mouse or keyboard.
sl@0
   320
		///  Can be modified to detect other Usages.
sl@0
   321
		///  </summary>
sl@0
   322
		///  
sl@0
   323
		///  <param name="myCapabilities"> a HIDP_CAPS structure retrieved with HidP_GetCaps. </param>
sl@0
   324
		///  
sl@0
   325
		///  <returns>
sl@0
   326
		///  A String describing the Usage.
sl@0
   327
		///  </returns>
sl@0
   328
sl@0
   329
		internal String GetHidUsage(NativeMethods.HIDP_CAPS myCapabilities)
sl@0
   330
		{
sl@0
   331
			String usageDescription = "";
sl@0
   332
sl@0
   333
			try
sl@0
   334
			{
sl@0
   335
				//  Create32-bit Usage from Usage Page and Usage ID.
sl@0
   336
sl@0
   337
				Int32 usage = myCapabilities.UsagePage * 256 + myCapabilities.Usage;
sl@0
   338
sl@0
   339
				if (usage == Convert.ToInt32(0X102))
sl@0
   340
				{
sl@0
   341
					usageDescription = "mouse";
sl@0
   342
				}
sl@0
   343
				if (usage == Convert.ToInt32(0X106))
sl@0
   344
				{
sl@0
   345
					usageDescription = "keyboard";
sl@0
   346
				}
sl@0
   347
			}
sl@0
   348
sl@0
   349
			catch (Exception ex)
sl@0
   350
			{
sl@0
   351
				DisplayException(ModuleName, ex);
sl@0
   352
				throw;
sl@0
   353
			}
sl@0
   354
sl@0
   355
			return usageDescription;
sl@0
   356
		}
sl@0
   357
sl@0
   358
		///  <summary>
sl@0
   359
		///  reads an Input report from the device using a control transfer.
sl@0
   360
		///  </summary>  
sl@0
   361
		///  <param name="hidHandle"> the handle for learning about the device and exchanging Feature reports. </param>
sl@0
   362
		/// <param name="inputReportBuffer"> contains the requested report. </param>
sl@0
   363
sl@0
   364
		internal Boolean GetInputReportViaControlTransfer(SafeFileHandle hidHandle, ref Byte[] inputReportBuffer)
sl@0
   365
		{
sl@0
   366
			var success = false;
sl@0
   367
sl@0
   368
			try
sl@0
   369
			{
sl@0
   370
				//  ***
sl@0
   371
				//  API function: HidD_GetInputReport
sl@0
   372
sl@0
   373
				//  Purpose: Attempts to read an Input report from the device using a control transfer.
sl@0
   374
sl@0
   375
				//  Requires:
sl@0
   376
				//  A handle to a HID
sl@0
   377
				//  A pointer to a buffer containing the report ID and report
sl@0
   378
				//  The size of the buffer. 
sl@0
   379
sl@0
   380
				//  Returns: true on success, false on failure.
sl@0
   381
				//  ***
sl@0
   382
sl@0
   383
				if (!hidHandle.IsInvalid && !hidHandle.IsClosed)
sl@0
   384
				{
sl@0
   385
					success = NativeMethods.HidD_GetInputReport(hidHandle, inputReportBuffer, inputReportBuffer.Length + 1);
sl@0
   386
					Debug.Print("HidD_GetInputReport success = " + success);
sl@0
   387
				}
sl@0
   388
				return success;
sl@0
   389
			}
sl@0
   390
sl@0
   391
			catch (Exception ex)
sl@0
   392
			{
sl@0
   393
				DisplayException(ModuleName, ex);
sl@0
   394
				throw;
sl@0
   395
			}
sl@0
   396
		}
sl@0
   397
sl@0
   398
		///  <summary>
sl@0
   399
		///  Reads an Input report from the device using an interrupt transfer.
sl@0
   400
		///  </summary>
sl@0
   401
		///  
sl@0
   402
		///  <param name="deviceData"> the Filestream for writing data. </param> 
sl@0
   403
		///  <param name="inputReportBuffer"> contains the report ID and report data. </param>
sl@0
   404
		/// <returns>
sl@0
   405
		///   True on success. False on failure.
sl@0
   406
		///  </returns>  
sl@0
   407
sl@0
   408
		internal async Task<Int32> GetInputReportViaInterruptTransfer(FileStream deviceData, Byte[] inputReportBuffer, CancellationTokenSource cts)
sl@0
   409
		{
sl@0
   410
			try
sl@0
   411
			{
sl@0
   412
				Int32 bytesRead = 0;
sl@0
   413
				
sl@0
   414
					// Begin reading an Input report. 
sl@0
   415
sl@0
   416
					Task<Int32> t = deviceData.ReadAsync(inputReportBuffer, 0, inputReportBuffer.Length, cts.Token);
sl@0
   417
sl@0
   418
					bytesRead = await t;
sl@0
   419
sl@0
   420
					// Gets to here only if the read operation completed before a timeout.
sl@0
   421
sl@0
   422
					Debug.Print("Asynchronous read completed. Bytes read = " + Convert.ToString(bytesRead));
sl@0
   423
sl@0
   424
					// The operation has one of these completion states:
sl@0
   425
sl@0
   426
					switch (t.Status)
sl@0
   427
					{
sl@0
   428
						case TaskStatus.RanToCompletion:
sl@0
   429
							Debug.Print("Input report received from device");
sl@0
   430
							break;
sl@0
   431
						case TaskStatus.Canceled:
sl@0
   432
							Debug.Print("Task canceled");
sl@0
   433
							break;
sl@0
   434
						case TaskStatus.Faulted:
sl@0
   435
							Debug.Print("Unhandled exception");
sl@0
   436
							break;
sl@0
   437
					}
sl@0
   438
				return bytesRead;
sl@0
   439
			}
sl@0
   440
			catch (Exception ex)
sl@0
   441
			{
sl@0
   442
				DisplayException(ModuleName, ex);
sl@0
   443
				throw;
sl@0
   444
			}
sl@0
   445
		}
sl@0
   446
sl@0
   447
		///  <summary>
sl@0
   448
		///  Retrieves the number of Input reports the HID driver will store.
sl@0
   449
		///  </summary>
sl@0
   450
		///  
sl@0
   451
		///  <param name="hidDeviceObject"> a handle to a device  </param>
sl@0
   452
		///  <param name="numberOfInputBuffers"> an integer to hold the returned value. </param>
sl@0
   453
		///  
sl@0
   454
		///  <returns>
sl@0
   455
		///  True on success, False on failure.
sl@0
   456
		///  </returns>
sl@0
   457
sl@0
   458
		internal Boolean GetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, ref Int32 numberOfInputBuffers)
sl@0
   459
		{
sl@0
   460
			try
sl@0
   461
			{
sl@0
   462
				//  ***
sl@0
   463
				//  API function: HidD_GetNumInputBuffers
sl@0
   464
sl@0
   465
				//  Purpose: retrieves the number of Input reports the host can store.
sl@0
   466
				//  Not supported by Windows 98 Gold.
sl@0
   467
				//  If the buffer is full and another report arrives, the host drops the 
sl@0
   468
				//  ldest report.
sl@0
   469
sl@0
   470
				//  Accepts: a handle to a device and an integer to hold the number of buffers. 
sl@0
   471
sl@0
   472
				//  Returns: True on success, False on failure.
sl@0
   473
				//  ***
sl@0
   474
sl@0
   475
				Boolean success = NativeMethods.HidD_GetNumInputBuffers(hidDeviceObject, ref numberOfInputBuffers);
sl@0
   476
sl@0
   477
				return success;
sl@0
   478
			}
sl@0
   479
sl@0
   480
			catch (Exception ex)
sl@0
   481
			{
sl@0
   482
				DisplayException(ModuleName, ex);
sl@0
   483
				throw;
sl@0
   484
			}
sl@0
   485
		}
sl@0
   486
sl@0
   487
		/// <summary>
sl@0
   488
		/// Timeout if read or write via interrupt transfer doesn't return.
sl@0
   489
		/// </summary>
sl@0
   490
sl@0
   491
		internal void OnTimeout()
sl@0
   492
		{
sl@0
   493
			try
sl@0
   494
			{
sl@0
   495
				// No action required.
sl@0
   496
sl@0
   497
				Debug.Print("timeout");
sl@0
   498
			}
sl@0
   499
			catch (Exception ex)
sl@0
   500
			{
sl@0
   501
				DisplayException(ModuleName, ex);
sl@0
   502
				throw;
sl@0
   503
			}
sl@0
   504
		}
sl@0
   505
sl@0
   506
		/// <summary>
sl@0
   507
		/// Attempts to open a handle to a HID.
sl@0
   508
		/// </summary>
sl@0
   509
		/// <param name="devicePathName"> device path name returned by SetupDiGetDeviceInterfaceDetail </param>
sl@0
   510
		/// <param name="readAndWrite"> true if requesting read/write access for Input and Output reports </param>
sl@0
   511
		/// <returns> hidHandle - a handle to the HID </returns>
sl@0
   512
sl@0
   513
		internal SafeFileHandle OpenHandle(String devicePathName, Boolean readAndWrite)
sl@0
   514
		{
sl@0
   515
			SafeFileHandle hidHandle;
sl@0
   516
sl@0
   517
			try
sl@0
   518
			{
sl@0
   519
				if (readAndWrite)
sl@0
   520
				{
sl@0
   521
					//  ***
sl@0
   522
					//  API function:
sl@0
   523
					//  CreateFile
sl@0
   524
sl@0
   525
					//  Purpose:
sl@0
   526
					//  Retrieves a handle to a device.
sl@0
   527
sl@0
   528
					//  Accepts:
sl@0
   529
					//  A device path name returned by SetupDiGetDeviceInterfaceDetail
sl@0
   530
					//  The type of access requested (read/write).
sl@0
   531
					//  FILE_SHARE attributes to allow other processes to access the device while this handle is open.
sl@0
   532
					//  A Security structure or IntPtr.Zero. 
sl@0
   533
					//  A creation disposition value. Use OPEN_EXISTING for devices.
sl@0
   534
					//  Flags and attributes for files. Not used for devices.
sl@0
   535
					//  Handle to a template file. Not used.
sl@0
   536
sl@0
   537
					//  Returns: a handle without read or write access.
sl@0
   538
					//  This enables obtaining information about all HIDs, even system
sl@0
   539
					//  keyboards and mice. 
sl@0
   540
					//  Separate handles are used for reading and writing.
sl@0
   541
					//  ***
sl@0
   542
sl@0
   543
					hidHandle = FileIo.CreateFile(devicePathName, FileIo.GenericRead | FileIo.GenericWrite, FileIo.FileShareRead | FileIo.FileShareWrite, IntPtr.Zero, FileIo.OpenExisting, 0, IntPtr.Zero);
sl@0
   544
				}
sl@0
   545
				else
sl@0
   546
				{
sl@0
   547
					hidHandle = FileIo.CreateFile(devicePathName, 0, FileIo.FileShareRead | FileIo.FileShareWrite, IntPtr.Zero, FileIo.OpenExisting, 0, IntPtr.Zero);
sl@0
   548
				}
sl@0
   549
			}
sl@0
   550
sl@0
   551
			catch (Exception ex)
sl@0
   552
			{
sl@0
   553
				DisplayException(ModuleName, ex);
sl@0
   554
				throw;
sl@0
   555
			}
sl@0
   556
			return hidHandle;
sl@0
   557
		}
sl@0
   558
sl@0
   559
		///  <summary>
sl@0
   560
		///  Writes a Feature report to the device.
sl@0
   561
		///  </summary>
sl@0
   562
		///  
sl@0
   563
		///  <param name="outFeatureReportBuffer"> contains the report ID and report data. </param>
sl@0
   564
		///  <param name="hidHandle"> handle to the device.  </param>
sl@0
   565
		///  
sl@0
   566
		///  <returns>
sl@0
   567
		///   True on success. False on failure.
sl@0
   568
		///  </returns>            
sl@0
   569
sl@0
   570
		internal Boolean SendFeatureReport(SafeFileHandle hidHandle, Byte[] outFeatureReportBuffer)
sl@0
   571
		{
sl@0
   572
			try
sl@0
   573
			{
sl@0
   574
				//  ***
sl@0
   575
				//  API function: HidD_SetFeature
sl@0
   576
sl@0
   577
				//  Purpose: Attempts to send a Feature report to the device.
sl@0
   578
sl@0
   579
				//  Accepts:
sl@0
   580
				//  A handle to a HID
sl@0
   581
				//  A pointer to a buffer containing the report ID and report
sl@0
   582
				//  The size of the buffer. 
sl@0
   583
sl@0
   584
				//  Returns: true on success, false on failure.
sl@0
   585
				//  ***
sl@0
   586
sl@0
   587
				Boolean success = NativeMethods.HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);
sl@0
   588
sl@0
   589
				Debug.Print("HidD_SetFeature success = " + success);
sl@0
   590
sl@0
   591
				return success;
sl@0
   592
			}
sl@0
   593
sl@0
   594
			catch (Exception ex)
sl@0
   595
			{
sl@0
   596
				DisplayException(ModuleName, ex);
sl@0
   597
				throw;
sl@0
   598
			}
sl@0
   599
		}
sl@0
   600
sl@0
   601
		///  <summary>
sl@0
   602
		///  Writes an Output report to the device using a control transfer.
sl@0
   603
		///  </summary>
sl@0
   604
		///  
sl@0
   605
		///  <param name="outputReportBuffer"> contains the report ID and report data. </param>
sl@0
   606
		///  <param name="hidHandle"> handle to the device.  </param>
sl@0
   607
		///  
sl@0
   608
		///  <returns>
sl@0
   609
		///   True on success. False on failure.
sl@0
   610
		///  </returns>            
sl@0
   611
sl@0
   612
		internal Boolean SendOutputReportViaControlTransfer(SafeFileHandle hidHandle, Byte[] outputReportBuffer)
sl@0
   613
		{
sl@0
   614
			try
sl@0
   615
			{
sl@0
   616
				//  ***
sl@0
   617
				//  API function: HidD_SetOutputReport
sl@0
   618
sl@0
   619
				//  Purpose: 
sl@0
   620
				//  Attempts to send an Output report to the device using a control transfer.
sl@0
   621
sl@0
   622
				//  Accepts:
sl@0
   623
				//  A handle to a HID
sl@0
   624
				//  A pointer to a buffer containing the report ID and report
sl@0
   625
				//  The size of the buffer. 
sl@0
   626
sl@0
   627
				//  Returns: true on success, false on failure.
sl@0
   628
				//  ***                    
sl@0
   629
sl@0
   630
				Boolean success = NativeMethods.HidD_SetOutputReport(hidHandle, outputReportBuffer, outputReportBuffer.Length + 1);
sl@0
   631
sl@0
   632
				Debug.Print("HidD_SetOutputReport success = " + success);
sl@0
   633
sl@0
   634
				return success;
sl@0
   635
			}
sl@0
   636
sl@0
   637
			catch (Exception ex)
sl@0
   638
			{
sl@0
   639
				DisplayException(ModuleName, ex);
sl@0
   640
				throw;
sl@0
   641
			}
sl@0
   642
		}
sl@0
   643
sl@0
   644
		///  <summary>
sl@0
   645
		///  Writes an Output report to the device using an interrupt transfer.
sl@0
   646
		///  </summary>
sl@0
   647
		///  
sl@0
   648
		///  <param name="fileStreamDeviceData"> the Filestream for writing data. </param> 
sl@0
   649
		///  <param name="hidHandle"> SafeFileHandle to the device.  </param>
sl@0
   650
		///  <param name="outputReportBuffer"> contains the report ID and report data. </param>
sl@0
   651
		///  <param name="cts"> CancellationTokenSource </param>
sl@0
   652
		///  
sl@0
   653
		///  <returns>
sl@0
   654
		///   1 on success. 0 on failure.
sl@0
   655
		///  </returns>            
sl@0
   656
sl@0
   657
		internal async Task<Boolean> SendOutputReportViaInterruptTransfer
sl@0
   658
			(FileStream fileStreamDeviceData, SafeFileHandle hidHandle, Byte[] outputReportBuffer, CancellationTokenSource cts)
sl@0
   659
		{
sl@0
   660
			try
sl@0
   661
			{
sl@0
   662
				var success = false;
sl@0
   663
				
sl@0
   664
					// Begin writing the Output report. 
sl@0
   665
sl@0
   666
					Task t = fileStreamDeviceData.WriteAsync(outputReportBuffer, 0, outputReportBuffer.Length, cts.Token);
sl@0
   667
sl@0
   668
					await t;
sl@0
   669
sl@0
   670
					// Gets to here only if the write operation completed before a timeout.
sl@0
   671
sl@0
   672
					Debug.Print("Asynchronous write completed");
sl@0
   673
sl@0
   674
					// The operation has one of these completion states:
sl@0
   675
sl@0
   676
					switch (t.Status)
sl@0
   677
					{
sl@0
   678
						case TaskStatus.RanToCompletion:
sl@0
   679
							success = true;
sl@0
   680
							Debug.Print("Output report written to device");
sl@0
   681
							break;
sl@0
   682
						case TaskStatus.Canceled:
sl@0
   683
							Debug.Print("Task canceled");
sl@0
   684
							break;
sl@0
   685
						case TaskStatus.Faulted:
sl@0
   686
							Debug.Print("Unhandled exception");
sl@0
   687
							break;
sl@0
   688
					}
sl@0
   689
sl@0
   690
				return success;
sl@0
   691
			}
sl@0
   692
			catch (Exception ex)
sl@0
   693
			{
sl@0
   694
				DisplayException(ModuleName, ex);
sl@0
   695
				throw;
sl@0
   696
			}
sl@0
   697
		}
sl@0
   698
sl@0
   699
		///  <summary>
sl@0
   700
		///  sets the number of input reports the host HID driver store.
sl@0
   701
		///  </summary>
sl@0
   702
		///  
sl@0
   703
		///  <param name="hidDeviceObject"> a handle to the device.</param>
sl@0
   704
		///  <param name="numberBuffers"> the requested number of input reports.  </param>
sl@0
   705
		///  
sl@0
   706
		///  <returns>
sl@0
   707
		///  True on success. False on failure.
sl@0
   708
		///  </returns>
sl@0
   709
sl@0
   710
		internal Boolean SetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, Int32 numberBuffers)
sl@0
   711
		{
sl@0
   712
			try
sl@0
   713
			{
sl@0
   714
				//  ***
sl@0
   715
				//  API function: HidD_SetNumInputBuffers
sl@0
   716
sl@0
   717
				//  Purpose: Sets the number of Input reports the host can store.
sl@0
   718
				//  If the buffer is full and another report arrives, the host drops the 
sl@0
   719
				//  oldest report.
sl@0
   720
sl@0
   721
				//  Requires:
sl@0
   722
				//  A handle to a HID
sl@0
   723
				//  An integer to hold the number of buffers. 
sl@0
   724
sl@0
   725
				//  Returns: true on success, false on failure.
sl@0
   726
				//  ***
sl@0
   727
sl@0
   728
				NativeMethods.HidD_SetNumInputBuffers(hidDeviceObject, numberBuffers);
sl@0
   729
				return true;
sl@0
   730
			}
sl@0
   731
sl@0
   732
			catch (Exception ex)
sl@0
   733
			{
sl@0
   734
				DisplayException(ModuleName, ex);
sl@0
   735
				throw;
sl@0
   736
			}
sl@0
   737
		}
sl@0
   738
	}
sl@0
   739
}