public IEnumerable <HidDeviceInfo> CollectInfo() { var result = new List <HidDeviceInfo>(); Guid hidGuid; Hid.HidD_GetHidGuid(out hidGuid); var deviceInfoList = SetupApi.SetupDiGetClassDevs(ref hidGuid, null, IntPtr.Zero, Constants.DIGCF_DEVICEINTERFACE | Constants.DIGCF_PRESENT); if (deviceInfoList != IntPtr.Zero && deviceInfoList != Constants.INVALID_HANDLE_VALUE) { var deviceInfo = new SetupApi.SP_DEVICE_INTERFACE_DATA(); deviceInfo.cbSize = Marshal.SizeOf(deviceInfo); for (var i = 0; ; i++) { if (!SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoList, 0, ref hidGuid, Convert.ToUInt32(i), ref deviceInfo)) { break; } var path = this.GetPath(deviceInfoList, deviceInfo); var device = new HidDevice(); if (device.Open(path)) { var attributes = device.GetAttributes(); var vendor = device.GetVendorString(); var product = device.GetProductString(); result.Add(new HidDeviceInfo( path, attributes.VendorID, attributes.ProductID, attributes.VersionString, vendor, product)); device.Close(); } } SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoList); } return(result); }
public static bool FindHidDevices(ref List <string> DevicePathNames) { Debug.WriteLine("findHidDevices() -> Method called"); // Initialize the internal variables required for performing the search var bufferSize = 0; var detailDataBuffer = IntPtr.Zero; bool deviceFound; var deviceInfoSet = new IntPtr(); var lastDevice = false; int listIndex; var deviceInterfaceData = new SpDeviceInterfaceData(); // Get the required GUID var systemHidGuid = new Guid(); Hid.HidD_GetHidGuid(ref systemHidGuid); Debug.WriteLine(string.Format("findHidDevices() -> Fetched GUID for HID devices ({0})", systemHidGuid.ToString())); try { // Here we populate a list of plugged-in devices matching our class GUID (DIGCF_PRESENT specifies that the list // should only contain devices which are plugged in) Debug.WriteLine("findHidDevices() -> Using SetupDiGetClassDevs to get all devices with the correct GUID"); deviceInfoSet = SetupApi.SetupDiGetClassDevs(ref systemHidGuid, IntPtr.Zero, IntPtr.Zero, Constants.DigcfPresent | Constants.DigcfDeviceinterface); // Reset the deviceFound flag and the memberIndex counter deviceFound = false; listIndex = 0; deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); // Look through the retrieved list of class GUIDs looking for a match on our interface GUID do { //Debug.WriteLine("usbGenericHidCommunication:findHidDevices() -> Enumerating devices"); var success = SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref systemHidGuid, listIndex, ref deviceInterfaceData); if (!success) { //Debug.WriteLine("usbGenericHidCommunication:findHidDevices() -> No more devices left - giving up"); lastDevice = true; } else { // The target device has been found, now we need to retrieve the device path so we can open // the read and write handles required for USB communication // First call is just to get the required buffer size for the real request SetupApi.SetupDiGetDeviceInterfaceDetail (deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); // Allocate some memory for the buffer detailDataBuffer = Marshal.AllocHGlobal(bufferSize); Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); // Second call gets the detailed data buffer //Debug.WriteLine("usbGenericHidCommunication:findHidDevices() -> Getting details of the device"); SetupApi.SetupDiGetDeviceInterfaceDetail (deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero); // Skip over cbsize (4 bytes) to get the address of the devicePathName. var pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4); // Get the String containing the devicePathName. DevicePathNames.Add(Marshal.PtrToStringAuto(pDevicePathName)); //Debug.WriteLine(string.Format("usbGenericHidCommunication:findHidDevices() -> Found matching device (memberIndex {0})", memberIndex)); deviceFound = true; } listIndex += 1; }while (lastDevice != true); } catch (Exception) { // Something went badly wrong... output some debug and return false to indicated device discovery failure Debug.WriteLine("findHidDevices() -> EXCEPTION: Something went south whilst trying to get devices with matching GUIDs - giving up!"); return(false); } finally { // Clean up the unmanaged memory allocations if (detailDataBuffer != IntPtr.Zero) { // Free the memory allocated previously by AllocHGlobal. Marshal.FreeHGlobal(detailDataBuffer); } if (deviceInfoSet != IntPtr.Zero) { SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet); } } if (deviceFound) { Debug.WriteLine(string.Format("findHidDevices() -> Found {0} devices with matching GUID", (DevicePathNames.Count).ToString(CultureInfo.InvariantCulture))); } else { Debug.WriteLine("findHidDevices() -> No matching devices found"); } return(deviceFound); }
/// <summary> /// registerForDeviceNotification - registers the window (identified by the windowHandle) for /// device notification messages from Windows /// </summary> public bool RegisterForDeviceNotifications(IntPtr windowHandle1) { Debug.WriteLine("usbGenericHidCommunication:registerForDeviceNotifications() -> Method called"); // A DEV_BROADCAST_DEVICEINTERFACE header holds information about the request. var devBroadcastDeviceInterface = new DevBroadcastDeviceinterface(); var devBroadcastDeviceInterfaceBuffer = IntPtr.Zero; // Get the required GUID var systemHidGuid = new Guid(); Hid.HidD_GetHidGuid(ref systemHidGuid); try { // Set the parameters in the DEV_BROADCAST_DEVICEINTERFACE structure. var size = Marshal.SizeOf(devBroadcastDeviceInterface); devBroadcastDeviceInterface.dbcc_size = size; devBroadcastDeviceInterface.dbcc_devicetype = Constants.DbtDevtypDeviceinterface; devBroadcastDeviceInterface.dbcc_reserved = 0; devBroadcastDeviceInterface.dbcc_classguid = systemHidGuid; devBroadcastDeviceInterfaceBuffer = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(devBroadcastDeviceInterface, devBroadcastDeviceInterfaceBuffer, true); // Register for notifications and store the returned handle DeviceNotificationHandle = User32.RegisterDeviceNotification(Handle, devBroadcastDeviceInterfaceBuffer, Constants.DeviceNotifyWindowHandle); Marshal.PtrToStructure(devBroadcastDeviceInterfaceBuffer, devBroadcastDeviceInterface); if ((DeviceNotificationHandle.ToInt32() == IntPtr.Zero.ToInt32())) { Debug.WriteLine( "usbGenericHidCommunication:registerForDeviceNotifications() -> Notification registration failed"); return(false); } else { Debug.WriteLine( "usbGenericHidCommunication:registerForDeviceNotifications() -> Notification registration succeded"); return(true); } } catch (Exception ex) { Debug.WriteLine( "usbGenericHidCommunication:registerForDeviceNotifications() -> EXCEPTION: An unknown exception has occured!"); Debug.WriteLine(ex.Message); } finally { // Free the memory allocated previously by AllocHGlobal. if (devBroadcastDeviceInterfaceBuffer != IntPtr.Zero) { try { Marshal.FreeHGlobal(devBroadcastDeviceInterfaceBuffer); } catch (Exception ex) { Debug.WriteLine(ex.Message); } } } return(false); }
/// <summary> /// Find the Nintendo USB controller. Also save HID capabilities for device for later. /// </summary> /// <returns></returns> public bool FindController() { bool deviceFound = false; Guid hidGuid = Guid.Empty; String[] devicePathName = new String[255]; Int32 memberIndex = 0; bool success = false; try { myDeviceDetected = false; CloseCommunications(); // Get the Guid associated with USB HID class. Hid.HidD_GetHidGuid(ref hidGuid); Debug.WriteLineIf(WRITE_DEBUG_INFO, MyDebugging.ResultOfAPICall("Hid.HidD_GetHidGuid")); // Get all attached HIDs. I am assuming there are a maximum of 128. deviceFound = MyDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName); if (deviceFound) { memberIndex = 0; // Loop through all USB HIDs found and look for my VID/PID. do { // Open HID handle without read nor write access to get info. hidHandle = FileIO.CreateFile( devicePathName[memberIndex], 0, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); Debug.WriteLineIf(WRITE_DEBUG_INFO, MyDebugging.ResultOfAPICall("FileIO.CreateFile")); if (!hidHandle.IsInvalid) { // Get DeviceAttribute size in bytes. MyHid.DeviceAttributes.Size = Marshal.SizeOf(MyHid.DeviceAttributes); // Get HID attributes. success = Hid.HidD_GetAttributes(hidHandle, ref MyHid.DeviceAttributes); if (success) { if (MyHid.DeviceAttributes.VendorID == USB_NINTENDO_VID && MyHid.DeviceAttributes.ProductID == USB_NINTENDO_PID) { myDeviceDetected = true; myDevicePathName = devicePathName[memberIndex]; } else { // Not a match - close handle. hidHandle.Close(); } } else { // There was a problem trying to retrieve the HID info. Debug.WriteLineIf(WRITE_DEBUG_INFO, "Error trying to get HID attributes in " + "UsbSingleNintendoController.FindController() when calling " + "Hid.HidD_GetAttributes(...)"); hidHandle.Close(); } } // Prepare to go to next index. memberIndex++; }while (!((myDeviceDetected || (memberIndex == devicePathName.Length)))); } // If device found, wire it up to this class. if (myDeviceDetected) { // Only allow a very few number of input reports to be queued. MyHid.SetNumberOfInputBuffers(hidHandle, USB_NUMBER_INPUT_REPORT_BUFFERS); Debug.WriteLineIf(WRITE_DEBUG_INFO, MyDebugging.ResultOfAPICall("MyHid.SetNumberOfInputBuffers")); // Register for notification if HID removed or attached. success = MyDeviceManagement.RegisterForDeviceNotifications(myDevicePathName, this.Handle, hidGuid, ref deviceNotificationHandle); Debug.WriteLineIf(WRITE_DEBUG_INFO && !success, "Failed at: MyDeviceManagement.RegisterForDeviceNotifications"); // Get capabilities report for report sizes. MyHid.Capabilities = MyHid.GetDeviceCapabilities(hidHandle); Debug.WriteLineIf(WRITE_DEBUG_INFO, MyDebugging.ResultOfAPICall("MyHid.GetDeviceCapabilities")); if (success) { // Close handle then reopen in RW mode. hidHandle.Close(); hidHandle = FileIO.CreateFile( myDevicePathName, FileIO.GENERIC_READ | FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); #pragma warning disable Debug.WriteLineIf(WRITE_DEBUG_INFO && hidHandle.IsInvalid, "File handle invalid at: FileIO.CreateFile(read/write)"); #pragma warning restore Debug.WriteLineIf(WRITE_DEBUG_INFO, MyDebugging.ResultOfAPICall("FileIO.CreateFile(read/write)")); if (MyHid.Capabilities.InputReportByteLength > 0) { fileStreamDeviceData = new FileStream( hidHandle, FileAccess.ReadWrite, MyHid.Capabilities.InputReportByteLength, false); } MyHid.FlushQueue(hidHandle); } } } catch (Exception ex) { Debug.WriteLineIf(WRITE_DEBUG_INFO, ex.Message); deviceFound = false; } return(deviceFound); }
public static bool FindHidDevices(ref string[] listOfDevicePathNames, ref int numberOfDevicesFound) { TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 开始查找所有HID设备"); // Initialise the internal variables required for performing the search var bufferSize = 0; var detailDataBuffer = IntPtr.Zero; bool deviceFound; var deviceInfoSet = new IntPtr(); var lastDevice = false; int listIndex; var deviceInterfaceData = new SpDeviceInterfaceData(); // Get the required GUID var systemHidGuid = new Guid(); Hid.HidD_GetHidGuid(ref systemHidGuid); TmoShare.WriteLog(string.Format("DeviceDiscovery:findHidDevices() -> 找到HID设备全局 GUID {0}", systemHidGuid)); try { // Here we populate a list of plugged-in devices matching our class GUID (DIGCF_PRESENT specifies that the list // should only contain devices which are plugged in) TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 获取所有HID设备句柄"); deviceInfoSet = SetupApi.SetupDiGetClassDevs(ref systemHidGuid, IntPtr.Zero, IntPtr.Zero, Constants.DigcfPresent | Constants.DigcfDeviceinterface); // Reset the deviceFound flag and the memberIndex counter deviceFound = false; listIndex = 0; deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); // Look through the retrieved list of class GUIDs looking for a match on our interface GUID do { TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 获取设备信息"); var success = SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref systemHidGuid, listIndex, ref deviceInterfaceData); if (!success) { TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 已经找到最后一个-停止"); lastDevice = true; } else { // The target device has been found, now we need to retrieve the device path so we can open // the read and write handles required for USB communication // First call is just to get the required buffer size for the real request SetupApi.SetupDiGetDeviceInterfaceDetail (deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); // Allocate some memory for the buffer detailDataBuffer = Marshal.AllocHGlobal(bufferSize); Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); // Second call gets the detailed data buffer TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 获取设备详细信息"); SetupApi.SetupDiGetDeviceInterfaceDetail (deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero); // Skip over cbsize (4 bytes) to get the address of the devicePathName. var pDevicePathName = new IntPtr(detailDataBuffer.ToInt32() + 4); // Get the String containing the devicePathName. listOfDevicePathNames[listIndex] = Marshal.PtrToStringAuto(pDevicePathName).ToUpper(); TmoShare.WriteLog(string.Format("DeviceDiscovery:findHidDevices() -> 将找到的设备添加进列表 (索引 {0})", listIndex)); deviceFound = true; listIndex++; } }while (lastDevice != true); } catch (Exception ex) { // Something went badly wrong... output some debug and return false to indicated device discovery failure TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 发生异常: " + ex.Message); return(false); } finally { // Clean up the unmanaged memory allocations if (detailDataBuffer != IntPtr.Zero) { // Free the memory allocated previously by AllocHGlobal. Marshal.FreeHGlobal(detailDataBuffer); } if (deviceInfoSet != IntPtr.Zero) { SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet); } } if (deviceFound) { TmoShare.WriteLog(String.Format("DeviceDiscovery:findHidDevices() -> 一共找到{0}个HID设备", listIndex)); numberOfDevicesFound = listIndex; } else { TmoShare.WriteLog("DeviceDiscovery:findHidDevices() -> 没有找到HID设备"); } return(deviceFound); }
/// <summary> /// Uses a series of API calls to locate a HID-class device /// by its Vendor ID and Product ID. /// Fills myDevicePathName with a path to device found, readHandle and writeHandle. Registers for Device Notifications (attached / detached type of events). /// </summary> /// /// <returns> /// True if the device is detected, False if not detected. /// </returns> private Boolean FindTheHid(Int32 myVendorID, Int32 myProductID) { Boolean someHidDevicesFound = false; String[] devicePathName = new String[128]; String functionName = ""; Guid hidGuid = Guid.Empty; Int32 memberIndex = 0; Boolean success = false; try { myDeviceDetected = false; Tracer.Trace(string.Format("FindTheHid(0x{0:X04}, 0x{1:X04})", myVendorID, myProductID)); // *** // API function: 'HidD_GetHidGuid // Purpose: Retrieves the interface class GUID for the HID class. // Accepts: 'A System.Guid object for storing the GUID. // *** Hid.HidD_GetHidGuid(ref hidGuid); functionName = "GetHidGuid"; Tracer.Trace(MyDebugging.ResultOfAPICall(functionName)); Tracer.Trace(" GUID for system HIDs: " + hidGuid.ToString()); // Fill an array with the device path names of all attached HIDs. someHidDevicesFound = MyDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName); // If there is at least one HID, attempt to read the Vendor ID and Product ID // of each device until there is a match or all devices have been examined. // // Fill myDevicePathName with a path to device found. if (someHidDevicesFound) { memberIndex = 0; // Tracer.Trace(" total number of HID devices: " + devicePathName.Length); // will be something like 128, a lot of empty paths there. do { // *** // API function: // CreateFile // Purpose: // Retrieves a handle to a device. // Accepts: // A device path name returned by SetupDiGetDeviceInterfaceDetail // The type of access requested (read/write). // FILE_SHARE attributes to allow other processes to access the device while this handle is open. // A Security structure or IntPtr.Zero. // A creation disposition value. Use OPEN_EXISTING for devices. // Flags and attributes for files. Not used for devices. // Handle to a template file. Not used. // Returns: a handle without read or write access. // This enables obtaining information about all HIDs, even system // keyboards and mice. // Separate handles are used for reading and writing. // *** if (!string.IsNullOrEmpty(devicePathName[memberIndex])) { Tracer.Trace(" trying HID device path '" + devicePathName[memberIndex] + "'"); hidHandle = FileIO.CreateFile(devicePathName[memberIndex], 0, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); functionName = "CreateFile"; Tracer.Trace(MyDebugging.ResultOfAPICall(functionName)); Tracer.Trace(" FindTheHid(): some HID device found, returned handle: " + hidHandle.ToString()); if (!hidHandle.IsInvalid) { // The returned handle is valid, // so find out if this is the device we're looking for. // Set the Size property of DeviceAttributes to the number of bytes in the structure. MyHid.DeviceAttributes.Size = Marshal.SizeOf(MyHid.DeviceAttributes); // *** // API function: // HidD_GetAttributes // Purpose: // Retrieves a HIDD_ATTRIBUTES structure containing the Vendor ID, // Product ID, and Product Version Number for a device. // Accepts: // A handle returned by CreateFile. // A pointer to receive a HIDD_ATTRIBUTES structure. // Returns: // True on success, False on failure. // *** success = Hid.HidD_GetAttributes(hidHandle, ref MyHid.DeviceAttributes); if (success) { Tracer.Trace(" HIDD_ATTRIBUTES structure filled without error."); Tracer.Trace(" Structure size: " + MyHid.DeviceAttributes.Size); Tracer.Trace(string.Format(" Vendor ID: 0x{0:X04}", MyHid.DeviceAttributes.VendorID)); Tracer.Trace(string.Format(" Product ID: 0x{0:X04}", MyHid.DeviceAttributes.ProductID)); Tracer.Trace(string.Format(" Version Number: 0x{0:X04}", MyHid.DeviceAttributes.VersionNumber)); // Find out if the device matches the one we're looking for. if ((MyHid.DeviceAttributes.VendorID == myVendorID) && (MyHid.DeviceAttributes.ProductID == myProductID)) { Tracer.Trace(" My device detected"); myDeviceDetected = true; // Save the DevicePathName for OnDeviceChange(). myDevicePathName = devicePathName[memberIndex]; } else { // It's not a match, so close the handle. Tracer.Trace(" (This is not My Device)"); myDeviceDetected = false; hidHandle.Close(); } } else { // There was a problem in retrieving the information. Tracer.Trace(" Error in filling HIDD_ATTRIBUTES structure."); myDeviceDetected = false; hidHandle.Close(); } } } // Keep looking until we find the device or there are no devices left to examine. memberIndex = memberIndex + 1; }while (!((myDeviceDetected || (memberIndex == devicePathName.Length)))); } if (myDeviceDetected) { // The device was detected. // Register to receive notifications if the device is removed or attached. success = MyDeviceManagement.RegisterForDeviceNotifications(myDevicePathName, WindowHandle, hidGuid, ref deviceNotificationHandle); Tracer.Trace("RegisterForDeviceNotifications = " + success); // Learn the capabilities of the device. MyHid.Capabilities = MyHid.GetDeviceCapabilities(hidHandle); if (success) { // Find out if the device is a system mouse or keyboard. hidUsage = MyHid.GetHidUsage(MyHid.Capabilities); // Get the Input report buffer size. GetInputReportBufferSize(); // Get handles to use in requesting Input and Output reports. readHandle = FileIO.CreateFile(myDevicePathName, FileIO.GENERIC_READ, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, FileIO.FILE_FLAG_OVERLAPPED, 0); functionName = "CreateFile, ReadHandle"; Tracer.Trace(MyDebugging.ResultOfAPICall(functionName)); Tracer.Trace(" FindTheHid(): success, returned handle: " + readHandle.ToString()); if (readHandle.IsInvalid) { exclusiveAccess = true; Tracer.Error("The device is a system " + hidUsage + ". Applications can access Feature reports only."); } else { writeHandle = FileIO.CreateFile(myDevicePathName, FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); functionName = "CreateFile, WriteHandle"; Tracer.Trace(MyDebugging.ResultOfAPICall(functionName)); Tracer.Trace(" FindTheHid(): handle valid, returned handle: " + writeHandle.ToString()); // Flush any waiting reports in the input buffer. (optional) MyHid.FlushQueue(readHandle); } } } else { // The device wasn't detected. Tracer.Error(string.Format("My Device not found - need a HID with vendorId={0}, productId={1}.", vendorId, productId)); } return(myDeviceDetected); } catch (Exception ex) { Tracer.Error(ex); throw; } }
public static List <string> FindAllHidDevices() { var listOfDevicePathNames = new List <string>(); var detailDataBuffer = IntPtr.Zero; int listIndex = 0; var deviceInterfaceData = new SpDeviceInterfaceData(); int lasterror = 0; // Get the required HID class GUID var systemHidGuid = new Guid(); Hid.HidD_GetHidGuid(ref systemHidGuid); IntPtr deviceInfoSet = SetupDiGetClassDevs(ref systemHidGuid); deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); try { // Look through the retrieved list of class GUIDs looking for a match on our interface GUID // SetupDiEnumDeviceInterfaces will return false if it fails for any reason, including when no more items are left // so we need to keep looping until the last thrown error is ERROR_NO_MORE_ITEMS // Note: we post increment lastIndex so each subsequent call refers to a new device while (SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref systemHidGuid, listIndex++, ref deviceInterfaceData) || (lasterror = Marshal.GetLastWin32Error()) != Constants.ERROR_NO_MORE_ITEMS) { if (lasterror != 0) { // SetupDiEnumDeviceInterfaces failed and it wasn't ERROR_NO_MORE_ITEMS as this would have stopped the loop Debug.WriteLine("SetupDiEnumDeviceInterfaces failed for run {0} with error {1}", listIndex, lasterror); continue; } int bufferSize = 0; // The target device has been found, now we need to retrieve the device path so we can open // the read and write handles required for USB communication // First call fails with ERROR_INSUFFICIENT_BUFFER and is used just to get the required buffer size for the real request var success = SetupApi.SetupDiGetDeviceInterfaceDetail( deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero ); // Allocate some memory for the buffer detailDataBuffer = Marshal.AllocHGlobal(bufferSize); Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); // Second call gets the detailed data buffer success = SetupApi.SetupDiGetDeviceInterfaceDetail( deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero ); if (!success) { Debug.WriteLine("SetupDiGetDeviceInterfaceDetail failed for run {0} with error {1}", listIndex, Marshal.GetLastWin32Error()); continue; } // Skip over cbsize (4 bytes) to get the address of the devicePathName. var pDevicePathName = IntPtr.Add(detailDataBuffer, 4); // Get the String containing the devicePathName. listOfDevicePathNames.Add(Marshal.PtrToStringAuto(pDevicePathName)); } } catch (Exception) { // Something went badly wrong... listOfDevicePathNames.Clear(); } finally { // Clean up the unmanaged memory allocations and free resources held by the windows API Marshal.FreeHGlobal(detailDataBuffer); SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet); } return(listOfDevicePathNames); }
/// <summary> /// Uses a series of API calls to locate a HID-class device /// by its Vendor ID and Product ID. /// </summary> /// /// <returns> /// True if the device is detected, False if not detected. /// </returns> public static Boolean FindTheHid( int myVendorID , int myProductID , ref IntPtr FrmMyHandle , ref IntPtr deviceNotificationHandle , ref Boolean exclusiveAccess , ref String hidUsage , ref Boolean myDeviceDetected , ref String myDevicePathName , ref FileStream fileStreamDeviceData , ref SafeFileHandle hidHandle , ref DeviceManagement MyDeviceManagement , ref Hid MyHid , ref string message , ref string txtInputReportBufferSize ) { Boolean deviceFound = false; String[] devicePathName = new String[128]; Guid hidGuid = Guid.Empty; Int32 memberIndex = 0; //Int32 myProductID = 0; //Int32 myVendorID = 0; Boolean success = false; try { myDeviceDetected = false; CloseCommunications( ref myDeviceDetected , ref fileStreamDeviceData , ref hidHandle ); // Get the device's Vendor ID and Product ID //myVendorID = Main.CardReader_VID; //myProductID = Main.CardReader_PID; // *** // API function: 'HidD_GetHidGuid // Purpose: Retrieves the interface class GUID for the HID class. // Accepts: 'A System.Guid object for storing the GUID. // *** Hid.HidD_GetHidGuid(ref hidGuid); // Fill an array with the device path names of all attached HIDs. deviceFound = MyDeviceManagement.FindDeviceFromGuid(hidGuid, ref devicePathName); // If there is at least one HID, attempt to read the Vendor ID and Product ID // of each device until there is a match or all devices have been examined. if (deviceFound) { memberIndex = 0; do { // *** // API function: // CreateFile // Purpose: // Retrieves a handle to a device. // Accepts: // A device path name returned by SetupDiGetDeviceInterfaceDetail // The type of access requested (read/write). // FILE_SHARE attributes to allow other processes to access the device while this handle is open. // A Security structure or IntPtr.Zero. // A creation disposition value. Use OPEN_EXISTING for devices. // Flags and attributes for files. Not used for devices. // Handle to a template file. Not used. // Returns: a handle without read or write access. // This enables obtaining information about all HIDs, even system // keyboards and mice. // Separate handles are used for reading and writing. // *** // Open the handle without read/write access to enable getting information about any HID, even system keyboards and mice. hidHandle = FileIO.CreateFile(devicePathName[memberIndex], 0, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); if (!hidHandle.IsInvalid) { // The returned handle is valid, // so find out if this is the device we're looking for. // Set the Size property of DeviceAttributes to the number of bytes in the structure. MyHid.DeviceAttributes.Size = Marshal.SizeOf(MyHid.DeviceAttributes); // *** // API function: // HidD_GetAttributes // Purpose: // Retrieves a HIDD_ATTRIBUTES structure containing the Vendor ID, // Product ID, and Product Version Number for a device. // Accepts: // A handle returned by CreateFile. // A pointer to receive a HIDD_ATTRIBUTES structure. // Returns: // True on success, False on failure. // *** success = Hid.HidD_GetAttributes(hidHandle, ref MyHid.DeviceAttributes); if (success) { // Find out if the device matches the one we're looking for. if ((MyHid.DeviceAttributes.VendorID == myVendorID) && (MyHid.DeviceAttributes.ProductID == myProductID)) { // Display the information in form's list box. message = "was found."; myDeviceDetected = true; // Save the DevicePathName for OnDeviceChange(). myDevicePathName = devicePathName[memberIndex]; } else { // It's not a match, so close the handle. myDeviceDetected = false; hidHandle.Close(); } } else { // There was a problem in retrieving the information. //Debug.WriteLine(" Error in filling HIDD_ATTRIBUTES structure."); myDeviceDetected = false; hidHandle.Close(); } } // Keep looking until we find the device or there are no devices left to examine. memberIndex = memberIndex + 1; }while (!((myDeviceDetected || (memberIndex == devicePathName.Length)))); } if (myDeviceDetected) { // The device was detected. // Register to receive notifications if the device is removed or attached. success = MyDeviceManagement.RegisterForDeviceNotifications(myDevicePathName, FrmMyHandle, hidGuid, ref deviceNotificationHandle); // Learn the capabilities of the device. MyHid.Capabilities = MyHid.GetDeviceCapabilities(hidHandle); if (success) { // Find out if the device is a system mouse or keyboard. hidUsage = MyHid.GetHidUsage(MyHid.Capabilities); // Get the Input report buffer size. GetInputReportBufferSize( ref exclusiveAccess , ref hidHandle , ref MyHid , ref txtInputReportBufferSize ); //Close the handle and reopen it with read/write access. hidHandle.Close(); hidHandle = FileIO.CreateFile(myDevicePathName, FileIO.GENERIC_READ | FileIO.GENERIC_WRITE, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, 0, 0); if (hidHandle.IsInvalid) { exclusiveAccess = true; } else { if (MyHid.Capabilities.InputReportByteLength > 0) { // Set the size of the Input report buffer. Byte[] inputReportBuffer = null; inputReportBuffer = new Byte[MyHid.Capabilities.InputReportByteLength]; fileStreamDeviceData = new FileStream(hidHandle, FileAccess.Read | FileAccess.Write, inputReportBuffer.Length, false); } if (MyHid.Capabilities.OutputReportByteLength > 0) { Byte[] outputReportBuffer = null; outputReportBuffer = new Byte[MyHid.Capabilities.OutputReportByteLength]; } // Flush any waiting reports in the input buffer. (optional) MyHid.FlushQueue(hidHandle); } } } else { // The device wasn't detected. myDeviceDetected = false; message = "not found."; } return(myDeviceDetected); } catch (Exception ex) { DisplayException("FindTheHid", ex); //throw; } return(false); }
private void _DeviceSearchThread() { _Logger.Info("Started"); while (_Running) { var loopStart = DateTime.Now; #region Device enumeration var devices = new List <UsbDevice>(); var detailDataBuffer = IntPtr.Zero; var deviceInfoSet = IntPtr.Zero; try { int listIndex = 0; int lastError = 0; var deviceInterfaceData = new SpDeviceInterfaceData(); var systemHidGuid = new Guid(); Hid.HidD_GetHidGuid(ref systemHidGuid); deviceInfoSet = SetupApi.SetupDiGetClassDevs(ref systemHidGuid, IntPtr.Zero, IntPtr.Zero, Constants.DigcfPresent | Constants.DigcfDeviceinterface); deviceInterfaceData.cbSize = Marshal.SizeOf(deviceInterfaceData); while (SetupApi.SetupDiEnumDeviceInterfaces(deviceInfoSet, IntPtr.Zero, ref systemHidGuid, listIndex++, ref deviceInterfaceData) || (lastError = Marshal.GetLastWin32Error()) != Constants.ERROR_NO_MORE_ITEMS) { if (lastError == 0) { int bufferSize = 0; SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, IntPtr.Zero, 0, ref bufferSize, IntPtr.Zero); detailDataBuffer = Marshal.AllocHGlobal(bufferSize); Marshal.WriteInt32(detailDataBuffer, (IntPtr.Size == 4) ? (4 + Marshal.SystemDefaultCharSize) : 8); if (SetupApi.SetupDiGetDeviceInterfaceDetail(deviceInfoSet, ref deviceInterfaceData, detailDataBuffer, bufferSize, ref bufferSize, IntPtr.Zero)) { var pDevicePathName = IntPtr.Add(detailDataBuffer, 4); var devicePath = Marshal.PtrToStringAuto(pDevicePathName); // Get device capabilities (to determine usage page) using (var hidHandle = Kernel32.CreateFile(devicePath, 0, Constants.FileShareRead | Constants.FileShareWrite, IntPtr.Zero, Constants.OpenExisting, 0, 0)) { var preparsedData = IntPtr.Zero; try { preparsedData = new IntPtr(); Hid.HidD_GetPreparsedData(hidHandle, ref preparsedData); var caps = new HidpCaps(); Hid.HidP_GetCaps(preparsedData, ref caps); var attrs = new HiddAttributes(); Hid.HidD_GetAttributes(hidHandle, ref attrs); // Only add the device if it has our VID, PID, and RAW usage page var deviceClass = FindDeviceClass(attrs.VendorID, attrs.ProductID, attrs.VersionNumber, caps.UsagePage); if (deviceClass != null) { var manufacturer = new StringBuilder(STRING_SIZE_LIMIT); var product = new StringBuilder(STRING_SIZE_LIMIT); var serial = new StringBuilder(STRING_SIZE_LIMIT); Hid.HidD_GetManufacturerString(hidHandle, manufacturer, STRING_SIZE_LIMIT); Hid.HidD_GetProductString(hidHandle, product, STRING_SIZE_LIMIT); Hid.HidD_GetSerialNumberString(hidHandle, serial, STRING_SIZE_LIMIT); var device = new UsbDevice(new DeviceInstance(deviceClass, devicePath, manufacturer.ToString(), product.ToString(), serial.ToString()), caps); devices.Add(device); } } finally { // Free up the memory before finishing if (preparsedData != IntPtr.Zero) { Hid.HidD_FreePreparsedData(preparsedData); } } } } } } } catch (Exception ex) { _Logger.Error(ex, "Error scanning for devices:"); devices.Clear(); } finally { // Clean up the unmanaged memory allocations and free resources held by the windows API if (detailDataBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(detailDataBuffer); } if (deviceInfoSet != IntPtr.Zero) { SetupApi.SetupDiDestroyDeviceInfoList(deviceInfoSet); } } var addedDevices = devices.Except(_CurrentDevices); var removedDevices = _CurrentDevices.Except(devices); _CurrentDevices = devices; if (DeviceRemoved != null) { foreach (var dev in removedDevices) { _Logger.Info("Device removed: {0}", dev); DeviceRemoved(this, new DeviceEventArgs(dev.Instance)); } } if (DeviceAdded != null) { foreach (var dev in addedDevices) { _Logger.Info("Device added: {0}", dev); DeviceAdded(this, new DeviceEventArgs(dev.Instance)); } } #endregion #region Active device I/O // If we receive a request to change the active device while we are processing messages, we need to stop immediately because they are about to become invalid { byte[] msg; while (true) { byte[] response = null; // Block until SetActiveDevice finishes lock (_LockObject) { // If we created a new message queue in the call to SetActiveDevice, this will return false and we'll break out of the loop if (_ActiveDevice == null || !_MessageQueue.TryDequeue(out msg)) { break; } try { response = SendDeviceRequest(_ActiveDevice, msg); } catch (Exception ex) { _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult); } } if (response != null) { ProcessResponse(msg, response); } else { _Logger.Error("Failed to read data from device. req = {0}", FormatByteArray(msg)); } } } // Get LED config (it may have changed) { byte[] response = null; byte[] msg = CreateSimpleMessage(hid_pkt_req.HID_PKT_REQ_CONFIG_LED_GET); // Block until SetActiveDevice finishes lock (_LockObject) { if (_ActiveDevice != null) { try { response = SendDeviceRequest(_ActiveDevice, msg); } catch (Exception ex) { _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult); } } } if (response != null) { ProcessResponse(msg, response); } } // Get LED status { byte[] response = null; byte[] msg = new byte[2]; msg[0] = (byte)hid_pkt_req.HID_PKT_REQ_LED_STATUS; msg[1] = 0; var ledStatuses = new List <LedColor>(); do { lock (_LockObject) { if (_ActiveDevice != null) { try { response = SendDeviceRequest(_ActiveDevice, msg); } catch (Exception ex) { _Logger.Error(ex, "Error communicating with device: {0} (0x{1:X8})", ex.Message, ex.HResult); } } } if (response != null) { // Parse response for (byte i = 0; i < response[1] && i < 10; i++) { var led = new LedColor( response[i * 3 + 2], response[i * 3 + 3], response[i * 3 + 4] ); ledStatuses.Add(led); } msg[1] += 10; } } while (response != null && response[0] == (byte)hid_pkt_res.HID_PKT_RES_MORE); LedStatusReceived?.Invoke(this, new LedStatusReceivedEventArgs(ledStatuses)); } #endregion // Wait until the entire loop execution is at least 100ms var loopTime = DateTime.Now - loopStart; if (loopTime < LOOP_DELAY) { var waitTime = LOOP_DELAY - loopTime; Thread.Sleep(waitTime); } } }