Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does SetupDiGetClassDevs work with device instance IDs as documented?

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?

like image 661
Judge Maygarden Avatar asked Jun 05 '09 15:06

Judge Maygarden


2 Answers

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.
like image 121
John Weldon Avatar answered Oct 30 '22 19:10

John Weldon


It seems that you're misunderstanding DBT_DEVICEARRIVAL.

There are a few different types of DBT_DEVICEARRIVAL messages-- for a volume, for a handle, for a device interface. I'm guessing you're talking about the DBT_DEVTYP_DEVICEINTERFACE variety. In this case, the dbcc_name field of the DEV_BROADCAST_DEVICEINTERFACE structure will contain the "device interface path".

The "device interface path" is NOT the same as a "device instance ID".

If you want to know more information about this device, you should enumerate all device interfaces by this device interface GUID (through SetupDiGetClassDevs with DIGCF_DEVICEINTERFACE), and compare the dbcc_name to the strings retrieved by SetupDiEnumDeviceInterfaces.

like image 43
Ilya Avatar answered Oct 30 '22 20:10

Ilya