I'm writing a Windows library using C++. This library should be able to check if the device driver of a specific device is installed on the system. So I am searching for a way to check if a driver is installed for a known Device ID.
So far, I found this information:
SetupDiBuildDriverInfoList lists available drivers for given devices. However, I have to supply more than just a Device ID.
SetupDiGetClassDevs seems to return exactly what I need for calling SetupDiBuildDriverInfoList, but it still doesn't take a Device ID as input. It may take a GUID of a device setup/interface class, but if I understand it correctly, a vendor-specific driver does not have such a GUID. It can also take a PnP enumerator, which I don't know enough about to tell whether I can use that somehow. Or finally, it may take a Device Instance ID - but not a Device ID.
Obviously, I want to check for any device of the same kind, so querying by Device Instance ID is not feasible. So, the question is: How do I check whether the driver for a given Device ID (or any other information that can identify the device; I assume Device ID is the right thing here) is installed, using the API functions I have listed (or any other way)?
Harry Johnston's answer brought me close, but I had to add a bit more to make it work. The magic bit that was missing was that I had to call both SetupDiEnumDeviceInfo
and SetupDiBuildDriverInfoList
before SetupDiEnumDriverInfoW
actually did something useful.
Here is a complete (modulo cleanup) example, replace the string passed to SetupDiGetClassDevsW
to match your own device. For my specific device it prints
Driver found: description: USBXpress Device, MfgName: Silicon Labs, ProviderName: Silicon Laboratories Inc.
on a PC with the driver installed and
No driver found
on a PC (actually VM) with no driver installed.
#include <Windows.h>
#include <SetupAPI.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "setupapi.lib")
int main(int argc, char ** argv)
{
HDEVINFO hdevinfo = SetupDiGetClassDevsW(NULL, LR"(USB\VID_10C4&PID_EA61)",
NULL, DIGCF_ALLCLASSES);
if (hdevinfo == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
printf("SetupDiGetClassDevs: %u\n", err);
return 1;
}
SP_DEVINFO_DATA devinfo;
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiEnumDeviceInfo(hdevinfo, 0, &devinfo))
{
DWORD err = GetLastError();
printf("SetupDiEnumDeviceInfo: %u %d\n", err, 0);
return 1;
}
if (!SetupDiBuildDriverInfoList(hdevinfo, &devinfo, SPDIT_COMPATDRIVER)) {
printf("error %d\n", GetLastError());
return 1;
}
SP_DRVINFO_DATA_W drvdata;
drvdata.cbSize = sizeof(SP_DRVINFO_DATA_W);
BOOL worked = SetupDiEnumDriverInfoW(hdevinfo, &devinfo, SPDIT_COMPATDRIVER,
0, &drvdata);
if (worked) {
printf("Driver found: description: %ws, MfgName: %ws, ProviderName: %ws\n",
drvdata.Description, drvdata.MfgName, drvdata.ProviderName);
}
else {
DWORD err = GetLastError();
if (err == ERROR_NO_MORE_ITEMS)
printf("No driver found\n");
else {
printf("SetupDiEnumDriverInfoW: %d", err);
return 1;
}
}
return 0;
}
You can convert a device ID to a list of device instance IDs like this:
#include <Windows.h>
#include <Cfgmgr32.h>
#include <SetupAPI.h>
#include <stdio.h>
#pragma comment(lib, "setupapi.lib")
int main(int argc, char ** argv)
{
static wchar_t buffer[1024 * 1024];
wchar_t * ptr;
CONFIGRET result;
result = CM_Get_Device_ID_ListW(L"usb\\vid_0461&pid_4d15", buffer,
_countof(buffer), CM_GETIDLIST_FILTER_ENUMERATOR);
if (result != CR_SUCCESS)
{
printf("CM_Get_Device_ID_ListW: %u\n", result);
return 1;
}
ptr = buffer;
while (*ptr)
{
printf("%ws\n", ptr);
ptr += wcslen(ptr) + 1;
}
printf("Done\n");
return 0;
}
Or like this:
int main(int argc, char ** argv)
{
HDEVINFO hdevinfo;
SP_DEVINFO_DATA devinfo;
wchar_t instance_id[4096];
DWORD n;
hdevinfo = SetupDiGetClassDevs(NULL, L"usb\\vid_0461&pid_4d15",
NULL, DIGCF_ALLCLASSES);
if (hdevinfo == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
printf("SetupDiGetClassDevs: %u\n", err);
return 1;
}
for (n = 0;; n++)
{
devinfo.cbSize = sizeof(devinfo);
if (!SetupDiEnumDeviceInfo(hdevinfo, n, &devinfo))
{
DWORD err = GetLastError();
printf("SetupDiEnumDeviceInfo: %u\n", err);
break;
}
if (!SetupDiGetDeviceInstanceId(hdevinfo, &devinfo,
instance_id, _countof(instance_id), NULL))
{
DWORD err = GetLastError();
printf("SetupDiGetDeviceInstanceId: %u\n", err);
}
else
{
printf("DevicePath: %ws\n", instance_id);
}
}
return 0;
}
The first code sample uses the older API, CM_Get_Device_ID_List.
The second code sample uses the newer API, SetupDiGetClassDevs, but note that the ability to use a device ID instead of just an enumerator isn't documented. It works, but it isn't documented.
In either case, the device does not have to be currently present, but it must have been installed at some point in the past.
If you aren't sure of the correct format for the device ID you want, you can list all device instances. (The device ID is just the device instance ID with the instance-specific ID removed, i.e., everything up to but excluding the last backslash.)
In the first code sample, use CM_GETIDLIST_FILTER_NONE
to get a list of all device instances.
In the second code sample, pass NULL instead of the device ID string to get a list of all device instances.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With