Retrieving Properties for Multiple Objects
Some device drivers support the retrieval of properties for multiple objects in a single function call; this is referred to as a bulk retrieval. There are two types of bulk retrieval operations: the first type retrieves properties for a list of objects, and the second type retrieves properties for all objects of a given format. The example described in this section demonstrates the former.
Your application can perform a bulk retrieval using the interfaces described in the following table.
Interface | Description |
---|---|
IPortableDeviceContent Interface | Provides access to the content-specific methods. |
IPortableDeviceKeyCollection Interface | Used to identify the properties to be retrieved. |
IPortableDeviceProperties Interface | Used to determine whether a given driver supports bulk operations. |
IPortableDevicePropertiesBulk Interface | Supports the bulk retrieval operation. |
IPortableDevicePropVariantCollection Interface | Used to store the object identifiers for the bulk operation. |
The ReadContentPropertiesBulk function in the sample application's ContentProperties.cpp module demonstrates a bulk retrieval operation.
The first task accomplished in this sample is determining whether or not the given driver supports bulk operations. This is accomplished by calling QueryInterface on the IPortableDeviceProperties interface and checking for the existence of IPortableDevicePropertiesBulk.
HRESULT hr = S_OK;
GUID guidContext = GUID_NULL;
CGetBulkValuesCallback* pCallback = NULL;
CComPtr<IPortableDeviceProperties> pProperties;
CComPtr<IPortableDevicePropertiesBulk> pPropertiesBulk;
CComPtr<IPortableDeviceValues> pObjectProperties;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceKeyCollection> pPropertiesToRead;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
if (SUCCEEDED(hr))
{
hr = pDevice->Content(&pContent);
if (FAILED(hr))
{
printf("! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n",hr);
}
}
if (SUCCEEDED(hr))
{
hr = pContent->Properties(&pProperties);
if (FAILED(hr))
{
printf("! Failed to get IPortableDeviceProperties from IPortableDevice, hr = 0x%lx\n",hr);
}
}
if (SUCCEEDED(hr))
{
hr = pProperties->QueryInterface(IID_PPV_ARGS(&pPropertiesBulk));
if (FAILED(hr))
{
printf("This driver does not support BULK property operations.\n");
}
}
If the driver supports bulk operations, the next step is to create an instance of the IPortableDeviceKeyCollection interface and to specify the keys that correspond to the properties that the application will retrieve. For a description of this process, see the Retrieving Properties for a Single Object topic.
After the appropriate keys are specified, the sample application creates an instance of the IPortableDevicePropertiesBulkCallback interface. The application will use the methods in this interface to track the progress of the asynchronous bulk-retrieval operation.
if (SUCCEEDED(hr))
{
pCallback = new CGetBulkValuesCallback();
if (pCallback == NULL)
{
hr = E_OUTOFMEMORY;
printf("! Failed to allocate CGetBulkValuesCallback, hr = 0x%lx\n", hr);
}
}
The next function that the sample application calls is the CreateIPortableDevicePropVariantCollectionWithAllObjectIDs helper function. This function creates a list of all available object identifiers for example purposes. (A real-world application would limit the list of identifiers to a particular set of objects. For instance, an application may create a list of identifiers for all of the objects currently in a given folder view.)
As noted above, the helper function recursively enumerates all objects on a given device. It returns this list in an IPortableDevicePropVariantCollection interface that contains an identifier for each object that it found. The helper function is defined in the module ContentEnumeration.cpp.
// 7) Call our helper function CreateIPortableDevicePropVariantCollectionWithAllObjectIDs
// to enumerate and create an IPortableDevicePropVariantCollection with the object
// identifiers needed to perform the bulk operation on.
if (SUCCEEDED(hr))
{
hr = CreateIPortableDevicePropVariantCollectionWithAllObjectIDs(pDevice,
pContent,
&pObjectIDs);
}
Once the previous steps are accomplished, the sample application initiates the asynchronous property retrieval. This is accomplished by doing the following:
- Calling IPortableDevicePropertiesBulk::QueueGetValuesByObjectList, which queues a request for the bulk property retrieval. (Note that although the request is queued, it is not started.)
- Calling IPortableDevicePropertiesBulk::Start to initiate the queued request.
These steps are demonstrated in the following code excerpt from the sample application.
if (SUCCEEDED(hr))
{
hr = pPropertiesBulk->QueueGetValuesByObjectList(pObjectIDs,
pPropertiesToRead,
pCallback,
&guidContext);
if(SUCCEEDED(hr))
{
// Cleanup any previously created global event handles.
if (g_hBulkPropertyOperationEvent != NULL)
{
CloseHandle(g_hBulkPropertyOperationEvent);
g_hBulkPropertyOperationEvent = NULL;
}
// In order to create a simpler to follow example we create and wait infinitly
// for the bulk property operation to complete and ignore any errors.
// Production code should be written in a more robust manner.
// Create the global event handle to wait on for the bulk operation
// to complete.
g_hBulkPropertyOperationEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (g_hBulkPropertyOperationEvent != NULL)
{
// Call Start() to actually being the Asynchronous bulk operation.
hr = pPropertiesBulk->Start(guidContext);
if(FAILED(hr))
{
printf("! Failed to start property operation, hr = 0x%lx\n", hr);
}
}
else
{
printf("! Failed to create the global event handle to wait on for the bulk operation. Aborting operation.\n");
}
}
else
{
printf("! QueueGetValuesByObjectList Failed, hr = 0x%lx\n", hr);
}
}
Related topics