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