Jinjinov / Usb.Events

Subscribe to the Inserted and Removed events to be notified when a USB drive is plugged in or unplugged, or when a USB device is connected or disconnected. Usb.Events is a .NET Standard 2.0 library and uses WMI on Windows, libudev on Linux and IOKit on macOS.
MIT License
95 stars 23 forks source link

Does not work on Windows with .NET 7 #25

Closed renkei closed 1 year ago

renkei commented 1 year ago

I've tested the latest nuget 10.0.1.1 on Linux and Windows with the code example from the README.md.

On Linux, I get UsbDeviceAdded and UsbDeviceRemoved events when I plug and unplug, for instance, a FTDI device or a Bluetooth dongle.

On Windows, no events are triggered. Instead, my notebook fan spins up, as soon as I plug or unplug a USB device. In the task manager I can see the task WMI Provider Host with a huge CPU load and "Very High" power consumption. This stops as soon as I press enter to close the example program. This is reproducible on my machine.

I'm using .NET 7.0 and my csproj of the example program sets the TargetFrameworkto net7.0.

If I just add Usb.Events as package reference, then I get System.Management 4.7.0 as requested by Usb.Events. To see if there is any difference with the version from .NET 7, I've additionally added System.Management 7.0.0 as package reference to my csproj file of the example program and called dotnet restore. Now, the latest version is installed but without any effect. With both versions, 4.7.0 and 7.0.0, I get the behavior described above.

What I'm doing wrong?

Jinjinov commented 1 year ago

You should never manually add package references. That was a big problem before 2016, when dependencies from different NuGet packages would cause problems because of different versions. But since 2016 we have .NET Core (or just .NET now) and it always works with any .NET Standard library - and Usb.Events is netstandard2.0

System.Management 4.7.0 also supports netstandard2.0, so if you make a .NET 7 app it should also work with netstandard2.0

See here: https://www.nuget.org/packages/System.Management/4.7.0#supportedframeworks-body-tab

I made a new NuGet version that updated System.Management package reference from 4.7.0 to 7.0.0 because System.Management 7.0.0 has more efficient netstandard2.0 implementation than System.Management 4.7.0 - but it still works with both .NET Framework 4.8 and with .NET 7 (that is the reason why Usb.Events is netstandard2.0 - I want it to be available to the many leagacy .NET Framework 4.8 projects)

https://github.com/Jinjinov/Usb.Events/releases/tag/v10.1.0.0

I also changed Usb.Events.Test from netcoreapp3.1 to net7.0 so you can start with that - just replace the Usb.Events project reference with a Usb.Events package reference.

renkei commented 1 year ago

You should never manually add package references.

In the end, you cannot control this. Let's assume, I would additionally consume another 3rdParty nuget package that also depends on System.Management. While Usb.Events depends on 4.7.0, the other one may depend on let's say 6.0.0. If I consume both in my csproj, your Usb.Events and the other 3rdParty nuget then nuget installs the minimum version of System.Management that fits to all ranges. In this case, System.Management 6.0.0 would be installed and your Usb.Events package cannot do anything against this, except you would limit the range like this:

<PackageReference Include="System.Management" Version="[4.7,5)" />

Then you force nuget to install only 4.x versions where x >= 7. But in the example above with the other 3rdParty nuget package that also depends on System.Management, but >= 6.0.0 this would result in a dependency tree error that could not be resolved by dotnet restore. So, to limit the version range interval can also be a challenge for consumers of your package.

However, I've tried your new package 10.1.0.0, thanks a lot for the quick response. And I've seen that Microsoft released System.Management 7.0.1 4 days ago. So, I've tried both, just your package as package reference and your package together with System.Management 7.0.1 as package reference. But again, it does not work for me, on Windows I don't get any events but a high CPU load of WMI Provider Host as soon as I plug or unplug a USB device.

Jinjinov commented 1 year ago

That is exactly what I meant: don't manage dependencies manually, they will be sorted out automatically.

Try to download the whole Usb.Events repository and run Usb.Events.Test without changing anything.

If that doesn't work on your computer, borrow a computer from a friend and try the same on his computer because sometimes there can be a problem with WMI in your Windows installation.

renkei commented 1 year ago

It's a notebook from my company that run Windows 10 Pro 22H2 with Sophos Anti-Virus Software and a lot of other stuff I cannot control. I've detected that after 24 minutes the high CPU load of WMI Provider Host disappears and the UsbDeviceAdded event finally arrives in your example code. After 24 minutes... Unbelievable... Then, if I unplug the USB device the UsbDeviceRemoved event occurs more or less immediately, this seems to work.

But if I plug the USB device again, I have to wait for 24 minutes again...

I've tested your example program on my private notebook (standard Windows 11 Pro installation) and there everything works as expected. After a few seconds the UsbDeviceAdded event is raised.

But I've found another problem: If USB devices are already connected to my machine while I start your example program, then no UsbDeviceAdded event is raised and the property IUsbEventWatcher.UsbDevicesList is also empty. This is a different behavior in comparison to Linux where I get immediately the events after the program starts for all already connected devices.

So, how do I get an overview of already connected devices on Windows without forcing the user to unplug and plug again all of them?

Jinjinov commented 1 year ago

Yes, I know that on Linux you get all devices that are already connected.

I also remember that I tried to do the same on Windows, but unfortunately I don't remember why I didn't - it has been 2 years since then.

You can try this code: https://stackoverflow.com/a/48390286/4675770

This answer is also good: https://stackoverflow.com/a/37604994/4675770 - I upvoted it 3 years ago.

I think that the main reason why I didn't use this code is because you can't get all properties that are in my class UsbDevice.

EDIT: The reason why I didn't do it is because the code must get the device serial number, so it can be removed:

https://github.com/Jinjinov/Usb.Events/blob/master/Usb.Events/UsbEventWatcher.cs#L148

and you can't get the serial number from https://stackoverflow.com/a/48390286/4675770 if I remember correctly.

Jinjinov commented 1 year ago

I wrote a better answer for you: https://stackoverflow.com/a/76023392/4675770

Jinjinov commented 1 year ago

I made some changes to Usb.Events to display the already present devices, but I didn't make a new NuGet yet.

It would be great if you could download the repository and test it before I make a new NuGet version.

Jinjinov commented 1 year ago

Added in https://github.com/Jinjinov/Usb.Events/releases/tag/v10.1.0.1