using System; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Collections.Generic; namespace WinUsb { /// /// Routines for detecting devices and receiving device notifications. /// public partial class DeviceManagement { /// /// Compares two device path names. Used to find out if the device name /// of a recently attached or removed device matches the name of a /// device the application is communicating with. /// /// /// a WM_DEVICECHANGE message. A call to RegisterDeviceNotification /// causes WM_DEVICECHANGE messages to be passed to an OnDeviceChange routine.. /// a device pathname returned by /// SetupDiGetDeviceInterfaceDetail in an SP_DEVICE_INTERFACE_DETAIL_DATA structure. /// /// /// True if the names match, False if not. /// /// internal Boolean DeviceNameMatch(Message m, String mydevicePathName) { Int32 stringSize; try { DEV_BROADCAST_DEVICEINTERFACE_1 devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE_1(); DEV_BROADCAST_HDR devBroadcastHeader = new DEV_BROADCAST_HDR(); // The LParam parameter of Message is a pointer to a DEV_BROADCAST_HDR structure. Marshal.PtrToStructure(m.LParam, devBroadcastHeader); if ((devBroadcastHeader.dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)) { // The dbch_devicetype parameter indicates that the event applies to a device interface. // So the structure in LParam is actually a DEV_BROADCAST_INTERFACE structure, // which begins with a DEV_BROADCAST_HDR. // Obtain the number of characters in dbch_name by subtracting the 32 bytes // in the strucutre that are not part of dbch_name and dividing by 2 because there are // 2 bytes per character. stringSize = System.Convert.ToInt32((devBroadcastHeader.dbch_size - 32) / 2); // The dbcc_name parameter of devBroadcastDeviceInterface contains the device name. // Trim dbcc_name to match the size of the String. devBroadcastDeviceInterface.dbcc_name = new Char[stringSize + 1]; // Marshal data from the unmanaged block pointed to by m.LParam // to the managed object devBroadcastDeviceInterface. Marshal.PtrToStructure(m.LParam, devBroadcastDeviceInterface); // Store the device name in a String. String DeviceNameString = new String(devBroadcastDeviceInterface.dbcc_name, 0, stringSize); // Compare the name of the newly attached device with the name of the device // the application is accessing (mydevicePathName). // Set ignorecase True. if ((String.Compare(DeviceNameString, mydevicePathName, true) == 0)) { return true; } else { return false; } } } catch (Exception ex) { string strEx; strEx = ex.Message; throw; } return false; } /// /// Use SetupDi API functions to retrieve the device path name of an /// attached device that belongs to a device interface class. /// /// /// an interface class GUID. /// Array of paths to devices /// /// /// True if a device is found, False if not. /// public static Boolean FindDeviceFromGuid(System.Guid myGuid, out List devicePathNames) { Int32 bufferSize = 0; IntPtr detailDataBuffer = IntPtr.Zero; Boolean deviceFound; IntPtr deviceInfoSet = new System.IntPtr(); Boolean lastDevice = false; Int32 memberIndex = 0; SP_DEVICE_INTERFACE_DATA MyDeviceInterfaceData = new SP_DEVICE_INTERFACE_DATA(); Boolean success; devicePathNames = new List(); try { // *** // API function // summary // Retrieves a device information set for a specified group of devices. // SetupDiEnumDeviceInterfaces uses the device information set. // parameters // Interface class GUID. // Null to retrieve information for all device instances. // Optional handle to a top-level window (unused here). // Flags to limit the returned information to currently present devices // and devices that expose interfaces in the class specified by the GUID. // Returns // Handle to a device information set for the devices. // *** deviceInfoSet = SetupDiGetClassDevs(ref myGuid, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); deviceFound = false; memberIndex = 0; // The cbSize element of the MyDeviceInterfaceData structure must be set to // the structure's size in bytes. // The size is 28 bytes for 32-bit code and 32 bits for 64-bit code. MyDeviceInterfaceData.cbSize = Marshal.SizeOf(MyDeviceInterfaceData); do { // Begin with 0 and increment through the device information set until // no more devices are available. // *** // API function // summary // Retrieves a handle to a SP_DEVICE_INTERFACE_DATA structure for a device. // On return, MyDeviceInterfaceData contains the handle to a // SP_DEVICE_INTERFACE_DATA structure for a detected device. // parameters // DeviceInfoSet returned by SetupDiGetClassDevs. // Optional SP_DEVINFO_DATA structure that defines a device instance // that is a member of a device information set. // Device interface GUID. // Index to specify a device in a device information set. // Pointer to a handle to a SP_DEVICE_INTERFACE_DATA structure for a device. // Returns // True on success. // *** success = SetupDiEnumDeviceInterfaces (deviceInfoSet, IntPtr.Zero, ref myGuid, memberIndex, ref MyDeviceInterfaceData); // Find out if a device information set was retrieved. if (!success) { lastDevice = true; } else { // A device is present. // *** // API function: // summary: // Retrieves an SP_DEVICE_INTERFACE_DETAIL_DATA structure // containing information about a device. // To retrieve the information, call this function twice. // The first time returns the size of the structure. // The second time returns a pointer to the data. // parameters // DeviceInfoSet returned by SetupDiGetClassDevs // SP_DEVICE_INTERFACE_DATA structure returned by SetupDiEnumDeviceInterfaces // A returned pointer to an SP_DEVICE_INTERFACE_DETAIL_DATA // Structure to receive information about the specified interface. // The size of the SP_DEVICE_INTERFACE_DETAIL_DATA structure. // Pointer to a int that will receive the returned required size of the // SP_DEVICE_INTERFACE_DETAIL_DATA structure. // Returned pointer to an SP_DEVINFO_DATA structure to receive information about the device. // Returns // True on success. // *** success = SetupDiGetDeviceInterfaceDetail (deviceInfoSet, ref MyDeviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); // Allocate memory for the SP_DEVICE_INTERFACE_DETAIL_DATA structure using the returned buffer size. detailDataBuffer = Marshal.AllocHGlobal(bufferSize); // Store cbSize in the first bytes of the array. The number of bytes are different with 32- and 64-bit systems. Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); // Call SetupDiGetDeviceInterfaceDetail again. // This time, pass a pointer to DetailDataBuffer // and the returned required buffer size. success = SetupDiGetDeviceInterfaceDetail (deviceInfoSet, ref MyDeviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero); // Skip over cbsize (4 bytes) to get the address of the devicePathName. IntPtr pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4); // Get the String containing the devicePathName. string devicePathName = Marshal.PtrToStringAuto(pDevicePathName); devicePathNames.Add(devicePathName); deviceFound = true; } memberIndex = memberIndex + 1; } while (!((lastDevice == true))); return deviceFound; } catch (Exception ex) { string strEx; strEx = ex.Message; throw; } finally { if (detailDataBuffer != IntPtr.Zero) { // Free the memory allocated previously by AllocHGlobal. Marshal.FreeHGlobal(detailDataBuffer); } if (deviceInfoSet != IntPtr.Zero) { // *** // API function // summary // Frees the memory reserved for the DeviceInfoSet returned by SetupDiGetClassDevs. // parameters // DeviceInfoSet returned by SetupDiGetClassDevs. // returns // True on success. // *** SetupDiDestroyDeviceInfoList(deviceInfoSet); } } } /// /// Requests to receive a notification when a device is attached or removed. /// /// /// handle to a device. /// handle to the window that will receive device events. /// device interface GUID. /// returned device notification handle. /// /// /// True on success. /// /// public Boolean RegisterForDeviceNotifications(String devicePathName, IntPtr formHandle, Guid classGuid, ref IntPtr deviceNotificationHandle) { // A DEV_BROADCAST_DEVICEINTERFACE header holds information about the request. DEV_BROADCAST_DEVICEINTERFACE devBroadcastDeviceInterface = new DEV_BROADCAST_DEVICEINTERFACE(); IntPtr devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; Int32 size = 0; try { // Set the parameters in the DEV_BROADCAST_DEVICEINTERFACE structure. // Set the size. size = Marshal.SizeOf(devBroadcastDeviceInterface); devBroadcastDeviceInterface.dbcc_size = size; // Request to receive notifications about a class of devices. devBroadcastDeviceInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; devBroadcastDeviceInterface.dbcc_reserved = 0; // Specify the interface class to receive notifications about. devBroadcastDeviceInterface.dbcc_classguid = classGuid; // Allocate memory for the buffer that holds the DEV_BROADCAST_DEVICEINTERFACE structure. devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size); // Copy the DEV_BROADCAST_DEVICEINTERFACE structure to the buffer. // Set fDeleteOld True to prevent memory leaks. Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); // *** // API function // summary // Request to receive notification messages when a device in an interface class // is attached or removed. // parameters // Handle to the window that will receive device events. // Pointer to a DEV_BROADCAST_DEVICEINTERFACE to specify the type of // device to send notifications for. // DEVICE_NOTIFY_WINDOW_HANDLE indicates the handle is a window handle. // Returns // Device notification handle or NULL on failure. // *** deviceNotificationHandle = RegisterDeviceNotification(formHandle, devBroadcastDeviceInterfaceBuffer, DEVICE_NOTIFY_WINDOW_HANDLE); // Marshal data from the unmanaged block devBroadcastDeviceInterfaceBuffer to // the managed object devBroadcastDeviceInterface Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); if ((deviceNotificationHandle.ToInt32() == IntPtr.Zero.ToInt32())) { return false; } else { return true; } } catch (Exception ex) { string strEx; strEx = ex.Message; throw; } finally { if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) { // Free the memory allocated previously by AllocHGlobal. Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); } } } /// /// Requests to stop receiving notification messages when a device in an /// interface class is attached or removed. /// /// /// handle returned previously by /// RegisterDeviceNotification. internal void StopReceivingDeviceNotifications(IntPtr deviceNotificationHandle) { try { // *** // API function // summary // Stop receiving notification messages. // parameters // Handle returned previously by RegisterDeviceNotification. // returns // True on success. // *** // Ignore failures. DeviceManagement.UnregisterDeviceNotification(deviceNotificationHandle); } catch (Exception ex) { string strEx; strEx = ex.Message; throw; } } } }