Abrufen von Eigenschaften für mehrere Objekte

Einige Gerätetreiber unterstützen das Abrufen von Eigenschaften für mehrere Objekte in einem einzelnen Funktionsaufruf. dies wird als Massenabruf bezeichnet. Es gibt zwei Arten von Massenabrufvorgängen: Der erste Typ ruft Eigenschaften für eine Liste von Objekten ab, und der zweite Typ ruft Eigenschaften für alle Objekte eines bestimmten Formats ab. Das in diesem Abschnitt beschriebene Beispiel veranschaulicht ersteres.

Ihre Anwendung kann mithilfe der in der folgenden Tabelle beschriebenen Schnittstellen einen Massenabruf durchführen.

Schnittstelle BESCHREIBUNG
IPortableDeviceContent-Schnittstelle Ermöglicht den Zugriff auf die inhaltsspezifischen Methoden.
IPortableDeviceKeyCollection-Schnittstelle Wird verwendet, um die abzurufenden Eigenschaften zu identifizieren.
IPortableDeviceProperties-Schnittstelle Wird verwendet, um zu bestimmen, ob ein angegebener Treiber Massenvorgänge unterstützt.
IPortableDevicePropertiesBulk-Schnittstelle Unterstützt den Massenabrufvorgang.
IPortableDevicePropVariantCollection-Schnittstelle Wird verwendet, um die Objektbezeichner für den Massenvorgang zu speichern.

Die ReadContentPropertiesBulk-Funktion im ContentProperties.cpp-Modul der Beispielanwendung veranschaulicht einen Massenabrufvorgang.

Die erste Aufgabe in diesem Beispiel besteht darin, zu bestimmen, ob der angegebene Treiber Massenvorgänge unterstützt. Dies wird erreicht, indem QueryInterface für die IPortableDeviceProperties-Schnittstelle aufgerufen und überprüft wird, ob IPortableDevicePropertiesBulk vorhanden ist.

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");
    }
}

Wenn der Treiber Massenvorgänge unterstützt, besteht der nächste Schritt darin, eine Instanz der IPortableDeviceKeyCollection-Schnittstelle zu erstellen und die Schlüssel anzugeben, die den Eigenschaften entsprechen, die von der Anwendung abgerufen werden. Eine Beschreibung dieses Prozesses finden Sie im Thema Abrufen von Eigenschaften für ein einzelnes Objekt.

Nachdem die entsprechenden Schlüssel angegeben wurden, erstellt die Beispielanwendung eine Instanz der IPortableDevicePropertiesBulkCallback-Schnittstelle. Die Anwendung verwendet die Methoden in dieser Schnittstelle, um den Fortschritt des asynchronen Massenabrufvorgangs nachzuverfolgen.

if (SUCCEEDED(hr))
{
    pCallback = new CGetBulkValuesCallback();
    if (pCallback == NULL)
    {
        hr = E_OUTOFMEMORY;
        printf("! Failed to allocate CGetBulkValuesCallback, hr = 0x%lx\n", hr);
    }
}

Die nächste Funktion, die die Beispielanwendung aufruft, ist die Hilfsfunktion CreateIPortableDevicePropVariantCollectionWithAllObjectIDs. Diese Funktion erstellt eine Liste aller verfügbaren Objektbezeichner für Beispielzwecke. (Eine reale Anwendung würde die Liste der Bezeichner auf einen bestimmten Satz von Objekten beschränken. Beispielsweise kann eine Anwendung eine Liste von Bezeichnern für alle Objekte erstellen, die sich derzeit in einer bestimmten Ordneransicht befinden.)

Wie bereits erwähnt, listet die Hilfsfunktion rekursiv alle Objekte auf einem bestimmten Gerät auf. Diese Liste wird in einer IPortableDevicePropVariantCollection-Schnittstelle zurückgegeben, die einen Bezeichner für jedes gefundene Objekt enthält. Die Hilfsfunktion wird im Modul ContentEnumeration.cpp definiert.

// 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);
}

Sobald die vorherigen Schritte ausgeführt wurden, initiiert die Beispielanwendung den asynchronen Eigenschaftenabruf. Dies geschieht wie folgt:

  1. Aufrufen von IPortableDevicePropertiesBulk::QueueGetValuesByObjectList, das eine Anforderung für den Masseneigenschaftsabruf in die Warteschlange einreiht. (Beachten Sie, dass die Anforderung zwar in die Warteschlange eingereiht, aber nicht gestartet wird.)
  2. Aufrufen von IPortableDevicePropertiesBulk::Start, um die Anforderung in der Warteschlange zu initiieren.

Diese Schritte werden im folgenden Codeausschnitt aus der Beispielanwendung veranschaulicht.

   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);
       }
   }

IPortableDevice-Schnittstelle

IPortableDeviceContent-Schnittstelle

IPortableDeviceKeyCollection-Schnittstelle

IPortableDeviceProperties-Schnittstelle

IPortableDevicePropertiesBulk-Schnittstelle

IPortableDevicePropVariantCollection-Schnittstelle

Programmierhandbuch