Enumerating devices (WPD)

The first task completed by most applications is the enumeration of the devices connected to the computer. This task, and the retrieval of device information (such as manufacturer, friendly name, and description), is supported by the IPortableDeviceManager interface.

The EnumerateAllDevices function in the DeviceEnumeration.cpp module contains code that demonstrates the retrieval of the count of connected devices and, once the count is retrieved, the retrieval of device-specific information for each connected device.

The EnumerateAllDevices function accomplishes four primary tasks:

  1. Creates the portable device manager object.
  2. Retrieves a count of connected devices.
  3. Retrieves device information (for the connected devices).
  4. Frees the memory used when retrieving the device information.

Each of these four tasks is described in more detail in the following sections.

The first step in the device enumeration process is the creation of a portable device manager object. This is done by calling the CoCreateInstance function and passing the class identifier (CLSID) for the object, specifying the context in which the code will run, specifying a reference identifier for the IPortableDeviceManager interface, and then supplying a pointer variable that receives the IPortableDeviceManager interface pointer.

HRESULT hr = CoCreateInstance(CLSID_PortableDeviceManager,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_PPV_ARGS(&pPortableDeviceManager));
if (FAILED(hr))
{
    printf("! Failed to CoCreateInstance CLSID_PortableDeviceManager, hr = 0x%lx\n",hr);
}

Once you obtain an IPortableDeviceManager interface pointer, you can begin calling methods on this interface. The first method called in the EnumerateAllDevices function is IPortableDeviceManager::GetDevices. When this method is called with the first argument set to NULL, it returns the count of connected devices.

if (SUCCEEDED(hr))
{
    hr = pPortableDeviceManager->GetDevices(NULL, &cPnPDeviceIDs);
    if (FAILED(hr))
    {
        printf("! Failed to get number of devices on the system, hr = 0x%lx\n",hr);
    }
}

// Report the number of devices found.  NOTE: we will report 0, if an error
// occured.

printf("\n%d Windows Portable Device(s) found on the system\n\n", cPnPDeviceIDs);

After you have retrieved the count of connected devices, you can use this value to retrieve device information for each connected device. This process begins by passing an array of string pointers as the first argument and a count of the number of elements that this array can hold as the second argument (this count should at least be equal to the number of available devices).

The strings returned by this method are the Plug and Play names of the connected devices. These names, in turn, are passed to other methods on the IPortableDeviceManager interface to retrieve device-specific information such as the friendly name, the manufacturer's name, and the device description. (These names are also used to open a connection to the device when an application calls the IPortableDevice::Open method.)

if (SUCCEEDED(hr) && (cPnPDeviceIDs > 0))
{
    pPnpDeviceIDs = new (std::nothrow) PWSTR[cPnPDeviceIDs];
    if (pPnpDeviceIDs != NULL)
    {
        DWORD dwIndex = 0;

        hr = pPortableDeviceManager->GetDevices(pPnpDeviceIDs, &cPnPDeviceIDs);
        if (SUCCEEDED(hr))
        {
            // For each device found, display the devices friendly name,
            // manufacturer, and description strings.
            for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)
            {
                printf("[%d] ", dwIndex);
                DisplayFriendlyName(pPortableDeviceManager, pPnpDeviceIDs[dwIndex]);
                printf("    ");
                DisplayManufacturer(pPortableDeviceManager, pPnpDeviceIDs[dwIndex]);
                printf("    ");
                DisplayDescription(pPortableDeviceManager, pPnpDeviceIDs[dwIndex]);
            }
        }
        else
        {
            printf("! Failed to get the device list from the system, hr = 0x%lx\n",hr);
        }

Once you've retrieved the device information, you will need to free the memory associated with the strings pointed to by the array of string pointers. You will also need to delete this array.

for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)
{
    CoTaskMemFree(pPnpDeviceIDs[dwIndex]);
    pPnpDeviceIDs[dwIndex] = NULL;
}

// Delete the array of PWSTR pointers
delete [] pPnpDeviceIDs;
pPnpDeviceIDs = NULL;

IPortableDeviceManager Interface

Programming Guide