检查给定设备ID是否存在Windows驱动程序

时间:2014-11-26 08:10:28

标签: c++ winapi device-driver

我正在使用C ++编写Windows库。该库应该能够检查系统上是否安装了特定设备的设备驱动程序。所以我正在寻找一种方法来检查是否为已知的Device ID安装了驱动程序。

到目前为止,我发现了这些信息:

SetupDiBuildDriverInfoList列出了给定设备的可用驱动程序。但是,我必须提供的不仅仅是设备ID。

SetupDiGetClassDevs似乎完全返回我调用SetupDiBuildDriverInfoList所需的内容,但它仍然不会将设备ID作为输入。它可能需要设备设置/接口类的GUID,但如果我理解正确,特定于供应商的驱动程序没有这样的GUID。它也可能需要一个PnP枚举器,我不知道该告诉我是否可以以某种方式使用它。或者最后,它可能需要Device Instance ID - 但不是设备ID。

显然,我想检查任何类型的设备,因此按设备实例ID查询是不可行的。因此,问题是:如何使用我列出的API函数检查是否安装了给定设备ID的驱动程序(或任何其他可以识别设备的信息;我假设设备ID是正确的)或任何其他方式)?

2 个答案:

答案 0 :(得分:3)

您可以将设备ID转换为设备实例ID列表,如下所示:

#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,但请注意,使用设备ID而不仅仅是枚举器的功能尚未记录。它有效,但没有记录。

在任何一种情况下,设备当前都不必存在,但必须在过去的某个时刻安装。

如果您不确定所需设备ID的格式是否正确,则可以列出所有设备实例。 (The device ID is just the device instance ID with the instance-specific ID removed,即一切,但不包括最后一个反斜杠。)

在第一个代码示例中,使用CM_GETIDLIST_FILTER_NONE获取所有设备实例的列表。

在第二个代码示例中,传递NULL而不是设备ID字符串以获取所有设备实例的列表。

答案 1 :(得分:1)

哈里·约翰斯顿(Harry Johnston)的回答使我很接近,但是我不得不添加一些内容才能使它起作用。遗失的神奇之处在于,我必须先叫SetupDiEnumDeviceInfoSetupDiBuildDriverInfoList才能真正发挥作用。

这是一个完整的(模清除)示例,请替换传递给SetupDiEnumDriverInfoW的字符串以匹配您自己的设备。对于我的特定设备,它会打印

SetupDiGetClassDevsW

在已安装驱动程序的PC上

Driver found: description: USBXpress Device, MfgName: Silicon Labs, ProviderName: Silicon Laboratories Inc.

在未安装驱动程序的PC(实际上是VM)上。

No driver found