BOOLEAN FindKnownHidDevices()

in XInput_Scp/pnp.cpp [3:156]


BOOLEAN FindKnownHidDevices(OUT PHID_DEVICE* HidDevices, OUT PULONG NumberDevices)
{
    HDEVINFO                            hardwareDeviceInfo;
    SP_DEVICE_INTERFACE_DATA            deviceInfoData;
    ULONG                               i = 0;
    BOOLEAN                             done;
    PHID_DEVICE                         hidDeviceInst;
    GUID                                hidGuid;
    PSP_DEVICE_INTERFACE_DETAIL_DATA    functionClassDeviceData = NULL;
    ULONG                               predictedLength = 0;
    ULONG                               requiredLength = 0;
    PHID_DEVICE                         newHidDevices;

    HidD_GetHidGuid(&hidGuid);

    *HidDevices = NULL;
    *NumberDevices = 0;

    //
    // Open a handle to the plug and play dev node.
    //
    hardwareDeviceInfo = SetupDiGetClassDevs(&hidGuid,
                                             NULL, // Define no enumerator (global)
                                             NULL, // Define no
                                             (DIGCF_PRESENT | // Only Devices present
                                              DIGCF_DEVICEINTERFACE)); // Function class devices.

    if (hardwareDeviceInfo == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    //
    // Take a wild guess to start
    //    
    *NumberDevices = 4;
    done = FALSE;
    deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    while (!done) 
    {
        *NumberDevices *= 2;

        if (*HidDevices) 
        {
            newHidDevices = (PHID_DEVICE) realloc(*HidDevices, (*NumberDevices * sizeof(HID_DEVICE)));

            if (newHidDevices == NULL)
            {
                free(*HidDevices);
            }

            *HidDevices = newHidDevices;
        }
        else
        {
            *HidDevices = (PHID_DEVICE) calloc(*NumberDevices, sizeof(HID_DEVICE));
        }

        if (*HidDevices == NULL)
        {
            SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
            return FALSE;
        }

        hidDeviceInst = *HidDevices + i;

        for (; i < *NumberDevices; i++, hidDeviceInst++) 
        {
            if (SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,
                                            0, // No care about specific PDOs
                                            &hidGuid,
                                            i,
                                            &deviceInfoData))
            {
                //
                // allocate a function class device data structure to receive the
                // goods about this particular device.
                //
                SetupDiGetDeviceInterfaceDetail(
                        hardwareDeviceInfo,
                        &deviceInfoData,
                        NULL,  // probing so no output buffer yet
                        0,     // probing so output buffer length of zero
                        &requiredLength,
                        NULL); // not interested in the specific dev-node


                predictedLength = requiredLength;

                functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(predictedLength);

                if (functionClassDeviceData)
                {
                    functionClassDeviceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
                    ZeroMemory(functionClassDeviceData->DevicePath, sizeof(functionClassDeviceData->DevicePath));
                }
                else
                {
                    SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
                    return FALSE;
                }

                //
                // Retrieve the information from Plug and Play.
                //
                if (! SetupDiGetDeviceInterfaceDetail(
                           hardwareDeviceInfo,
                           &deviceInfoData,
                           functionClassDeviceData,
                           predictedLength,
                           &requiredLength,
                           NULL)) 
                {
                    SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
                    free(functionClassDeviceData);

                    return FALSE;
                }

                //
                // Open device with just generic query abilities to begin with
                //                
                if (! OpenHidDevice(functionClassDeviceData->DevicePath, 
                               FALSE,       // ReadAccess  - none
                               FALSE,       // WriteAccess - none
                               FALSE,       // Overlapped  - no
                               FALSE,       // Exclusive   - no
                               hidDeviceInst))
                {
                    SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
                    free(functionClassDeviceData);

                    return FALSE;
                }
            } 
            else
            {
                if (GetLastError() == ERROR_NO_MORE_ITEMS) 
                {
                    done = TRUE;
                    break;
                }
            }
        }
    }

    *NumberDevices = i;

    SetupDiDestroyDeviceInfoList(hardwareDeviceInfo);
    free(functionClassDeviceData);

    return TRUE;
}