8

Thanks to some other helpful StackOverflow questions, I've found a way to query WMI for device drivers. However, it seems to me that the data is being stored in disparate places that don't join together well.

I have a USB-to-serial port cable using FTDI drivers. I can query Win32_SystemDrivers to determine whether or not the drivers have been installed, like this:

SelectQuery query = new SelectQuery("Win32_SystemDriver");
query.Condition = "Name = 'FTDIBUS'";

ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection drivers = searcher.Get();
bool installed = (drivers.Count > 0);

But that collection doesn't tell me a thing about version information. So then I discovered I could query Win32_PnPSignedDriver to find the version of the device driver. So I'm doing something like this:

SelectQuery query = new SelectQuery("Win32_PnPSignedDriver");
query.Condition = "DriverProviderName = 'FTDI'";

ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection drivers = searcher.Get();

foreach (ManagementBaseObject driverObject in drivers)
{
    ManagementObject driver = (ManagementObject)driverObject;
    string version = driver["DriverVersion"].ToString();
}

However, that second block of code will only succeed if the cable (device) is actually plugged in. What I'd like to do is to check the version of the installed device driver, regardless of whether or not the device is currently plugged in.

How do I do this?

soapergem
  • 9,263
  • 18
  • 96
  • 152

2 Answers2

4

It seems Win32_SystemDriver class can give you the PathName of the associated driver .sys file.

Example: "\SystemRoot\System32\drivers\afd.sys"

Then you can get the .sys file version with :

String path = @"C:\Windows\System32\drivers\afd.sys"
var myFileVersionInfo = FileVersionInfo.GetVersionInfo(path);
var version = myFileVersionInfo.ProductVersion;
rducom
  • 7,072
  • 1
  • 25
  • 39
  • This is the correct solution. Thank you! However in my testing this morning, I discovered one snag: I cannot seem to access any of the files in the `C:\Windows\System32\drivers` folder. I manually copied the driver.sys file out into another folder, then ran the `GetVersionInfo()` command to verify that it worked (it does). But even though I can see the file is there in Windows Explorer, when I call `File.Exists()` on it in C# that returns false. I also tried changing the app.manifest to run as an administrator, but that didn't do the trick either. How do I access those driver files? – soapergem Jan 30 '15 at 15:06
  • I think you have to run your program as Administrator in order to access windows folder. For testing this in VisualStudio, you have to run VisualStudio itself as Administrator (right click on VS icon, then run as Administrator) – rducom Jan 30 '15 at 15:10
  • As stated (comment about the app.manifest), I already tried that, and that unfortunately that did not do the trick. – soapergem Jan 30 '15 at 15:11
  • I know there are issues accessing System32 with a 32 bit app on a x64 system. Can you try in x64 ? – rducom Jan 30 '15 at 15:19
  • 3
    The other commenter led me to the solution... I just have to replace "System32" in the path with "Sysnative" (which is a virtual folder). That did the trick. – soapergem Jan 30 '15 at 16:28
3

Keep in mind that you are asking to solve the chicken-and-egg problem, never a very healthy start for any program. Plug & Play in Windows is built on the notion that device drivers can be dynamically located when the device becomes available, downloading it if necessary. That is a chicken.

You can only hope to find the egg if the driver was pre-installed or previously used. Not entirely uncommon. In that case, it will be available in the driver store. You should be able to find it back when you enumerate it.

A sample program that does this is available here. Written in C# so a good start for what you want. I'll copy the screenshot:

enter image description here

Note the displayed driver date and version, what you are asking about. Keep in mind that there can be more than a single version present. You might want to take a peek at the source, it is very simple. It actually relies on a Windows utility to populate the ListView, PnPUtil.exe with the /e option enumerates the store. Try that by running it from the command line.

You can also easily see the store content with Explorer, the files are stored in c:\windows\system32\driverstore\filerepository. Perhaps useful to read the .inf file to add additional filtering. The .inf filename you get back, listed in the 1st column in the screenshot, is actually the one that's copied into the c:\windows\inf directory.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Ok, this also seems to be on the right track, but I'm running into the same problem with the other answer to this question. When I try to call pnputil.exe using `Process.Start()` it says it can't find the file. Digging a little deeper, I can confirm that `File.Exists(@"C:\Windows\System32\PnPutil.exe")` is returning false. However... the file is definitely there! I can see it in Windows explorer. How can I get my application to see it, and call it? – soapergem Jan 30 '15 at 15:56
  • 1
    There is no 32-bit version of pnputil.exe on a 64-bit operation system. Which is what you are trying to run. Project + Properties, Compile tab, select AnyCPU and untick the "Prefer 32-bit" option when you see it. Or if it must be a 32-bit program for some reason then run c:\windows\sysnative\pnputil.exe instead. – Hans Passant Jan 30 '15 at 16:06