Does SetupDiGetClassDevs work with device instance IDs as documented?

Judge Maygarden picture Judge Maygarden · Jun 5, 2009 · Viewed 7.8k times · Source

According to MSDN documentation, SetupDiGetClassDevs can be passed a device instance ID to obtain a device information set for a specific device:

To return only a specific device, set the DIFCF_DEVICEINTERFACE flag and use the Enumerator parameter to supply the device instance ID of the device.

I get the device instance ID by parsing the symbolic name from the WM_DEVICECHANGE message DBT_DEVICEARRIVAL event, and I have verified the resulting ID by comparing it to that returned from SetupDiGetDeviceInstanceId. Even passing the OS supplied device instance ID does not work (i.e. the SetupDiGetClassDevs call fails with ERROR_INVALID_PARAMETER).

My current workaround to fetch a SP_DEVINFO_DATA structure for the newly arrived device is to enumerate all devices in the same class and compare the result of SetupDiGetDeviceInstanceId to the symbolic name. However, I don't see why this should be necessary according to the documentation...

Has anyone gotten SetupDiGetClassDevs to work in this way? Is there a better method for getting further information for a device using data in the DBT_DEVICEARRIVAL event?

Answer

John Weldon picture John Weldon · Jun 8, 2009

It seems you have to either specify the DIGCF_ALLCLASSES flag to find all classes that match the given device instance id, or else specify the ClassGuid and use the DIGCF_DEFAULT flag.

This worked for me:

void error(DWORD err)
{
    WCHAR buf[0x200];
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, 0x200, NULL);
    wprintf(L"%x: %s\n", err,  buf);
}


int _tmain(int argc, _TCHAR* argv[])
{
    PCWSTR devinst = L"HID\\VID_413C&PID_2105\\6&22CE0F66&0&0000";
    HDEVINFO hinfo = SetupDiGetClassDevs(NULL, devinst, NULL, DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);
    if (hinfo == INVALID_HANDLE_VALUE)
    {
        error(GetLastError());
        return 1;
    }

    SP_DEVINFO_DATA dinfo;
    dinfo.cbSize = sizeof(dinfo);
    int ix = 0;
    while (SetupDiEnumDeviceInfo(hinfo, ix++, &dinfo))
    {
        wprintf(L"Match\n");
    }

    error(GetLastError());

    SetupDiDestroyDeviceInfoList(hinfo);
    return 0;
}

With output:

Match
103: No more data is available.