public async Task <IEnumerable <ConnectedDeviceDefinition> > GetConnectedDeviceDefinitionsAsync(FilterDeviceDefinition filterDeviceDefinition) { return(await Task.Run <IEnumerable <ConnectedDeviceDefinition> >(() => { var deviceDefinitions = new Collection <ConnectedDeviceDefinition>(); var spDeviceInterfaceData = new SpDeviceInterfaceData(); var spDeviceInfoData = new SpDeviceInfoData(); var spDeviceInterfaceDetailData = new SpDeviceInterfaceDetailData(); spDeviceInterfaceData.CbSize = (uint)Marshal.SizeOf(spDeviceInterfaceData); spDeviceInfoData.CbSize = (uint)Marshal.SizeOf(spDeviceInfoData); string productIdHex = null; string vendorHex = null; var guidString = GetClassGuid().ToString(); var copyOfClassGuid = new Guid(guidString); const int flags = APICalls.DigcfDeviceinterface | APICalls.DigcfPresent; Log($"About to call {nameof(APICalls.SetupDiGetClassDevs)} for class Guid {guidString}. Flags: {flags}", null, LogLevel.Information); var devicesHandle = APICalls.SetupDiGetClassDevs(ref copyOfClassGuid, IntPtr.Zero, IntPtr.Zero, flags); spDeviceInterfaceDetailData.CbSize = IntPtr.Size == 8 ? 8 : 4 + Marshal.SystemDefaultCharSize; var i = -1; if (filterDeviceDefinition != null) { if (filterDeviceDefinition.ProductId.HasValue) { productIdHex = Helpers.GetHex(filterDeviceDefinition.ProductId); } if (filterDeviceDefinition.VendorId.HasValue) { vendorHex = Helpers.GetHex(filterDeviceDefinition.VendorId); } } while (true) { try { i++; var isSuccess = APICalls.SetupDiEnumDeviceInterfaces(devicesHandle, IntPtr.Zero, ref copyOfClassGuid, (uint)i, ref spDeviceInterfaceData); if (!isSuccess) { var errorCode = Marshal.GetLastWin32Error(); if (errorCode == APICalls.ERROR_NO_MORE_ITEMS) { Log($"The call to {nameof(APICalls.SetupDiEnumDeviceInterfaces)} returned ERROR_NO_MORE_ITEMS", null, LogLevel.Information); break; } if (errorCode > 0) { Log($"{nameof(APICalls.SetupDiEnumDeviceInterfaces)} called successfully but a device was skipped while enumerating because something went wrong. The device was at index {i}. The error code was {errorCode}.", null, LogLevel.Warning); } } isSuccess = APICalls.SetupDiGetDeviceInterfaceDetail(devicesHandle, ref spDeviceInterfaceData, ref spDeviceInterfaceDetailData, 256, out _, ref spDeviceInfoData); if (!isSuccess) { var errorCode = Marshal.GetLastWin32Error(); if (errorCode == APICalls.ERROR_NO_MORE_ITEMS) { Log($"The call to {nameof(APICalls.SetupDiEnumDeviceInterfaces)} returned ERROR_NO_MORE_ITEMS", null, LogLevel.Information); //TODO: This probably can't happen but leaving this here because there was some strange behaviour break; } if (errorCode > 0) { Log($"{nameof(APICalls.SetupDiGetDeviceInterfaceDetail)} called successfully but a device was skipped while enumerating because something went wrong. The device was at index {i}. The error code was {errorCode}.", null, LogLevel.Warning); } } //Note this is a bit nasty but we can filter Vid and Pid this way I think... if (filterDeviceDefinition != null) { if (filterDeviceDefinition.VendorId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ContainsIgnoreCase(vendorHex)) { continue; } if (filterDeviceDefinition.ProductId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ContainsIgnoreCase(productIdHex)) { continue; } } var connectedDeviceDefinition = GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath); if (connectedDeviceDefinition == null) { Logger.Log($"Device with path {spDeviceInterfaceDetailData.DevicePath} was skipped. See previous logs.", GetType().Name, null, LogLevel.Warning); continue; } if (!DeviceManager.IsDefinitionMatch(filterDeviceDefinition, connectedDeviceDefinition)) { continue; } deviceDefinitions.Add(connectedDeviceDefinition); } catch (Exception ex) { Log(ex); } } APICalls.SetupDiDestroyDeviceInfoList(devicesHandle); return deviceDefinitions; })); }
public async Task <IEnumerable <DeviceDefinition> > GetConnectedDeviceDefinitions(uint?vendorId, uint?productId) { return(await Task.Run <IEnumerable <DeviceDefinition> >(() => { var deviceDefinitions = new Collection <DeviceDefinition>(); var spDeviceInterfaceData = new SpDeviceInterfaceData(); var spDeviceInfoData = new SpDeviceInfoData(); var spDeviceInterfaceDetailData = new SpDeviceInterfaceDetailData(); spDeviceInterfaceData.CbSize = (uint)Marshal.SizeOf(spDeviceInterfaceData); spDeviceInfoData.CbSize = (uint)Marshal.SizeOf(spDeviceInfoData); var guidString = ClassGuid.ToString(); var copyOfClassGuid = new Guid(guidString); var i = APICalls.SetupDiGetClassDevs(ref copyOfClassGuid, IntPtr.Zero, IntPtr.Zero, APICalls.DigcfDeviceinterface | APICalls.DigcfPresent); if (IntPtr.Size == 8) { spDeviceInterfaceDetailData.CbSize = 8; } else { spDeviceInterfaceDetailData.CbSize = 4 + Marshal.SystemDefaultCharSize; } var x = -1; var productIdHex = GetHex(productId); var vendorHex = GetHex(vendorId); while (true) { x++; var isSuccess = APICalls.SetupDiEnumDeviceInterfaces(i, IntPtr.Zero, ref copyOfClassGuid, (uint)x, ref spDeviceInterfaceData); if (!isSuccess) { var errorCode = Marshal.GetLastWin32Error(); if (errorCode == APICalls.ERROR_NO_MORE_ITEMS) { break; } throw new Exception($"Could not enumerate devices. Error code: {errorCode}"); } isSuccess = APICalls.SetupDiGetDeviceInterfaceDetail(i, ref spDeviceInterfaceData, ref spDeviceInterfaceDetailData, 256, out _, ref spDeviceInfoData); WindowsDeviceBase.HandleError(isSuccess, "Could not get device interface detail"); //Note this is a bit nasty but we can filter Vid and Pid this way I think... if (vendorId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(vendorHex)) { continue; } if (productId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(productIdHex)) { continue; } var deviceDefinition = GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath); if (deviceDefinition == null) { continue; } deviceDefinitions.Add(deviceDefinition); } APICalls.SetupDiDestroyDeviceInfoList(i); return deviceDefinitions; })); }