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;
            }));
        }
예제 #2
0
        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;
            }));
        }