Я пишу библиотеку Windows, используя C ++. Эта библиотека должна быть в состоянии проверить, установлен ли в системе драйвер устройства определенного устройства. Поэтому я ищу способ проверить, установлен ли драйвер для известного Идентификатор устройства.
До сих пор я нашел эту информацию:
SetupDiBuildDriverInfoList перечисляет доступные драйверы для данных устройств. Тем не менее, я должен предоставить больше, чем просто идентификатор устройства.
SetupDiGetClassDevs кажется, возвращает именно то, что мне нужно для вызова SetupDiBuildDriverInfoList, но он по-прежнему не принимает идентификатор устройства в качестве ввода. Может потребоваться GUID класса настройки / интерфейса устройства, но если я правильно понимаю, драйвер конкретного производителя не имеет такого GUID. Он также может использовать перечислитель PnP, о котором я не знаю достаточно, чтобы сказать, могу ли я каким-то образом его использовать. Или, наконец, это может занять Идентификатор экземпляра устройства — но не идентификатор устройства.
Очевидно, я хочу проверить наличие любого устройства такого же типа, поэтому запрос по идентификатору экземпляра устройства невозможен. Итак, вопрос заключается в следующем: как проверить, установлен ли драйвер для данного идентификатора устройства (или любой другой информации, которая может идентифицировать устройство; я предполагаю, что идентификатор устройства здесь подходит), используя функции API, которые я перечислил ( или любым другим способом)?
Вы можете преобразовать идентификатор устройства в список идентификаторов экземпляров устройства следующим образом:
#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;
}
Или вот так:
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;
}
Первый пример кода использует более старый API, CM_Get_Device_ID_List.
Второй пример кода использует более новый API, SetupDiGetClassDevs, но обратите внимание, что возможность использовать идентификатор устройства вместо просто перечислителя не задокументирована. Это работает, но это не задокументировано.
В любом случае устройство не обязательно должно присутствовать в настоящее время, но оно должно быть установлено в определенный момент в прошлом.
Если вы не уверены в правильном формате идентификатора устройства, который вы хотите, вы можете перечислить все экземпляры устройства. (Идентификатор устройства — это просто идентификатор экземпляра устройства с удаленным идентификатором экземпляра, то есть, все, кроме последнего обратного слеша, кроме
В первом примере кода используйте CM_GETIDLIST_FILTER_NONE
чтобы получить список всех экземпляров устройства.
Во втором примере кода передайте NULL вместо строки идентификатора устройства, чтобы получить список всех экземпляров устройства.
Ответ Гарри Джонстона приблизил меня, но мне пришлось добавить немного больше, чтобы это сработало. Магия, которой не хватало, заключалась в том, что мне пришлось позвонить обоим SetupDiEnumDeviceInfo
а также SetupDiBuildDriverInfoList
до SetupDiEnumDriverInfoW
на самом деле сделал что-то полезное.
Вот полный пример (по модулю очистки), замените строку, переданную SetupDiGetClassDevsW
соответствовать вашему собственному устройству. Для моего конкретного устройства это печатает
Driver found: description: USBXpress Device, MfgName: Silicon Labs, ProviderName: Silicon Laboratories Inc.
на ПК с установленным драйвером и
No driver found
на ПК (фактически на виртуальной машине) без установленного драйвера.
#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;
}