DeviceManagement.cs
author sl
Wed, 14 May 2014 17:26:04 +0200
changeset 5 8ea7a7e29c4d
permissions -rw-r--r--
Device selection in TreeView now fills in vendor and product ID in our text fields.
     1 using System;
     2 using System.Diagnostics;
     3 using System.Runtime.InteropServices; 
     4 using System.Windows.Forms;
     5 
     6 namespace GenericHid
     7 {
     8 	/// <summary>
     9 	/// Routine for detecting devices using Win32 SetupDi functions.
    10 	/// </summary>
    11 	/// 
    12 	sealed internal partial class DeviceManagement
    13 	{
    14 		private const String ModuleName = "Device Management";
    15 
    16 		///  <summary>
    17 		///  Provides a central mechanism for exception handling.
    18 		///  Displays a message box that describes the exception.
    19 		///  </summary>
    20 		///  
    21 		///  <param name="name"> the module where the exception occurred. </param>
    22 		///  <param name="e"> the exception </param>
    23 
    24 		internal static void DisplayException(String name, Exception e)
    25 		{
    26 			try
    27 			{
    28 				//  Create an error message.
    29 
    30 				String message = "Exception: " + e.Message + Environment.NewLine + "Module: " + name + Environment.NewLine + "Method: " +
    31 						  e.TargetSite.Name;
    32 
    33 				const String caption = "Unexpected Exception";
    34 
    35 				MessageBox.Show(message, caption, MessageBoxButtons.OK);
    36 				Debug.Write(message);
    37 			}
    38 			catch (Exception ex)
    39 			{
    40 				DisplayException(ModuleName, ex);
    41 				throw;
    42 			}
    43 		}
    44 
    45 		///  <summary>
    46 		///  Use SetupDi API functions to retrieve the device path name of an
    47 		///  attached device that belongs to a device interface class.
    48 		///  </summary>
    49 		///  
    50 		///  <param name="myGuid"> an interface class GUID. </param>
    51 		///  <param name="devicePathName"> a pointer to the device path name 
    52 		///  of an attached device. </param>
    53 		///  
    54 		///  <returns>
    55 		///   True if a device is found, False if not. 
    56 		///  </returns>
    57 
    58 		internal Boolean FindDeviceFromGuid(Guid myGuid, ref String[] devicePathName)
    59 		{
    60 			Int32 bufferSize = 0;
    61 			var deviceInfoSet = new IntPtr();
    62 			Boolean lastDevice = false;
    63 			var myDeviceInterfaceData = new NativeMethods.SP_DEVICE_INTERFACE_DATA();
    64 
    65 			try
    66 			{
    67 				Int32 memberIndex;
    68 
    69 				// ***
    70 				//  API function
    71 
    72 				//  summary 
    73 				//  Retrieves a device information set for a specified group of devices.
    74 				//  SetupDiEnumDeviceInterfaces uses the device information set.
    75 
    76 				//  parameters 
    77 				//  Interface class GUID.
    78 				//  Null to retrieve information for all device instances.
    79 				//  Optional handle to a top-level window (unused here).
    80 				//  Flags to limit the returned information to currently present devices 
    81 				//  and devices that expose interfaces in the class specified by the GUID.
    82 
    83 				//  Returns
    84 				//  Handle to a device information set for the devices.
    85 				// ***
    86 
    87 				deviceInfoSet = NativeMethods.SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, NativeMethods.DIGCF_PRESENT | NativeMethods.DIGCF_DEVICEINTERFACE);
    88 
    89 				bool deviceFound = false;
    90 				memberIndex = 0;
    91 
    92 				// The cbSize element of the MyDeviceInterfaceData structure must be set to
    93 				// the structure's size in bytes. 
    94 				// The size is 28 bytes for 32-bit code and 32 bits for 64-bit code.
    95 
    96 				myDeviceInterfaceData.cbSize = Marshal.SizeOf(myDeviceInterfaceData);
    97 
    98 				do
    99 				{
   100 					// Begin with 0 and increment through the device information set until
   101 					// no more devices are available.
   102 				
   103 					// ***
   104 					//  API function
   105 
   106 					//  summary
   107 					//  Retrieves a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
   108 					//  On return, MyDeviceInterfaceData contains the handle to a
   109 					//  SP_DEVICE_INTERFACE_DATA structure for a detected device.
   110 
   111 					//  parameters
   112 					//  DeviceInfoSet returned by SetupDiGetClassDevs.
   113 					//  Optional SP_DEVINFO_DATA structure that defines a device instance 
   114 					//  that is a member of a device information set.
   115 					//  Device interface GUID.
   116 					//  Index to specify a device in a device information set.
   117 					//  Pointer to a handle to a SP_DEVICE_INTERFACE_DATA structure for a device.
   118 
   119 					//  Returns
   120 					//  True on success.
   121 					// ***
   122 
   123 					Boolean success = NativeMethods.SetupDiEnumDeviceInterfaces
   124 						(deviceInfoSet,
   125 						 IntPtr.Zero,
   126 						 ref myGuid,
   127 						 memberIndex,
   128 						 ref myDeviceInterfaceData);
   129 
   130 					// Find out if a device information set was retrieved.
   131 
   132 					if (!success)
   133 					{
   134 						lastDevice = true;
   135 					}
   136 					else
   137 					{
   138 						// A device is present.
   139 
   140 						// ***
   141 						//  API function: 
   142 
   143 						//  summary:
   144 						//  Retrieves an SP_DEVICE_INTERFACE_DETAIL_DATA structure
   145 						//  containing information about a device.
   146 						//  To retrieve the information, call this function twice.
   147 						//  The first time returns the size of the structure.
   148 						//  The second time returns a pointer to the data.
   149 
   150 						//  parameters
   151 						//  DeviceInfoSet returned by SetupDiGetClassDevs
   152 						//  SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces
   153 						//  A returned pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA 
   154 						//  Structure to receive information about the specified interface.
   155 						//  The size of the SP_DEVICE_INTERFACE_DETAIL_DATA structure.
   156 						//  Pointer to a variable that will receive the returned required size of the 
   157 						//  SP_DEVICE_INTERFACE_DETAIL_DATA structure.
   158 						//  Returned pointer to an SP_DEVINFO_DATA structure to receive information about the device.
   159 
   160 						//  Returns
   161 						//  True on success.
   162 						// ***                     
   163 
   164 						NativeMethods.SetupDiGetDeviceInterfaceDetail
   165 							(deviceInfoSet,
   166 							 ref myDeviceInterfaceData,
   167 							 IntPtr.Zero,
   168 							 0,
   169 							 ref bufferSize,
   170 							 IntPtr.Zero);
   171 
   172 						// Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size.
   173 
   174 						IntPtr detailDataBuffer = Marshal.AllocHGlobal(bufferSize);
   175 
   176 						// Store cbSize in the first bytes of the array. Adjust for 32- and 64-bit systems.
   177 
   178                         Int32 cbsize;
   179 
   180                         if (IntPtr.Size == 4)
   181                         {
   182                             cbsize = 4 + Marshal.SystemDefaultCharSize;
   183                         }
   184                         else
   185                         {
   186                             cbsize = 8;
   187                         }
   188 
   189 						Marshal.WriteInt32(detailDataBuffer, cbsize);                        
   190 
   191 						// Call SetupDiGetDeviceInterfaceDetail again.
   192 						// This time, pass a pointer to DetailDataBuffer
   193 						// and the returned required buffer size.
   194 
   195 						NativeMethods.SetupDiGetDeviceInterfaceDetail
   196 							(deviceInfoSet,
   197 							 ref myDeviceInterfaceData,
   198 							 detailDataBuffer,
   199 							 bufferSize,
   200 							 ref bufferSize,
   201 							 IntPtr.Zero);
   202 
   203 						// Get the address of the devicePathName.
   204 
   205 						var pDevicePathName = new IntPtr(detailDataBuffer.ToInt64() + 4);
   206 
   207 						// Get the String containing the devicePathName.
   208 
   209 						devicePathName[memberIndex] = Marshal.PtrToStringAuto(pDevicePathName);
   210 
   211 						if (detailDataBuffer != IntPtr.Zero)
   212 						{
   213 							// Free the memory allocated previously by AllocHGlobal.
   214 
   215 							Marshal.FreeHGlobal(detailDataBuffer);
   216 						}
   217 						deviceFound = true;
   218 					}
   219 					memberIndex = memberIndex + 1;
   220 				}
   221 				while (!lastDevice);
   222 
   223 				return deviceFound;
   224 			}
   225 			finally
   226 			{
   227 				// ***
   228 				//  API function
   229 
   230 				//  summary
   231 				//  Frees the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs.
   232 
   233 				//  parameters
   234 				//  DeviceInfoSet returned by SetupDiGetClassDevs.
   235 
   236 				//  returns
   237 				//  True on success.
   238 				// ***
   239 
   240 				if (deviceInfoSet != IntPtr.Zero)
   241 				{
   242 					NativeMethods.SetupDiDestroyDeviceInfoList(deviceInfoSet);
   243 				}
   244 			}
   245 		}
   246 	}
   247 }
   248 
   249 
   250 
   251 
   252