Festlegen von Eigenschaften für mehrere Objekte
Einige Gerätetreiber unterstützen das Festlegen von Eigenschaften für mehrere Objekte in einem einzelnen Funktionsaufruf – dies wird als Massenschreibzugriff bezeichnet. Ihre Anwendung kann eine Massenschreibung mithilfe der in der folgenden Tabelle beschriebenen Schnittstellen ausführen.
Schnittstelle | Beschreibung |
---|---|
IPortableDeviceContent-Schnittstelle | Bietet Zugriff auf die inhaltsspezifischen Methoden. |
IPortableDeviceProperties-Schnittstelle | Bietet Zugriff auf die eigenschaftsspezifischen Methoden. |
IPortableDevicePropertiesBulk-Schnittstelle | Unterstützt den Massenschreibvorgang. |
IPortableDevicePropVariantCollection-Schnittstelle | Wird verwendet, um die Objektbezeichner für den Massenvorgang zu speichern. |
IPortableDeviceValuesCollection-Schnittstelle | Wird verwendet, um die zu schreibenden Eigenschaften zu identifizieren. |
Die WriteContentPropertiesBulk
Funktion im ContentProperties.cpp-Modul der Beispielanwendung veranschaulicht einen Massenschreibvorgang.
Die erste aufgabe, die in diesem Beispiel erreicht wurde, bestimmt, ob der angegebene Treiber Massenvorgänge unterstützt. Dies wird durch Aufrufen von QueryInterface für ein IPortableDeviceProperties-Objekt erreicht und überprüft, ob IPortableDevicePropertiesBulk vorhanden ist.
HRESULT hr = S_OK;
GUID guidContext = GUID_NULL;
CSetBulkValuesCallback* pCallback = NULL;
CComPtr<IPortableDeviceProperties> pProperties;
CComPtr<IPortableDevicePropertiesBulk> pPropertiesBulk;
CComPtr<IPortableDeviceValues> pObjectProperties;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceValuesCollection> pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD cObjectIDs = 0;
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");
}
}
Die nächste Aufgabe umfasst das Erstellen eines IPortableDeviceValuesCollection-Objekts . Dies ist das Objekt, das die Eigenschaftswerte enthält, die vom Beispiel geschrieben werden.
HRESULT hr = S_OK;
GUID guidContext = GUID_NULL;
CSetBulkValuesCallback* pCallback = NULL;
CComPtr<IPortableDeviceProperties> pProperties;
CComPtr<IPortableDevicePropertiesBulk> pPropertiesBulk;
CComPtr<IPortableDeviceValues> pObjectProperties;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceValuesCollection> pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD cObjectIDs = 0;
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_PortableDeviceValuesCollection,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPortableDeviceValuesCollection,
(VOID**) &pPropertiesToWrite);
if (FAILED(hr))
{
printf("! Failed to CoCreate IPortableDeviceValuesCollection for bulk property values, hr = 0x%lx\n", hr);
}
}
Danach erstellt das Beispiel eine Instanz der IPortableDevicePropertiesBulkCallback-Schnittstelle. Die Anwendung verwendet die Methoden in dieser Schnittstelle, um den Fortschritt des asynchronen Massenschreibvorgangs nachzuverfolgen.
HRESULT hr = S_OK;
GUID guidContext = GUID_NULL;
CSetBulkValuesCallback* pCallback = NULL;
CComPtr<IPortableDeviceProperties> pProperties;
CComPtr<IPortableDevicePropertiesBulk> pPropertiesBulk;
CComPtr<IPortableDeviceValues> pObjectProperties;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceValuesCollection> pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD cObjectIDs = 0;
if (SUCCEEDED(hr))
{
pCallback = new CSetBulkValuesCallback();
if (pCallback == NULL)
{
hr = E_OUTOFMEMORY;
printf("! Failed to allocate CSetBulkValuesCallback, hr = 0x%lx\n", hr);
}
}
Die nächste Funktion, die die Beispielanwendung aufruft, ist die CreateIPortableDevicePropVariantCollectionWithAllObjectIDs
Hilfsfunktion. Diese Funktion listet alle Objekte auf einem bestimmten Gerät rekursiv auf und gibt eine IPortableDevicePropVariantCollection-Schnittstelle zurück, die einen Bezeichner für jedes gefundene Objekt enthält. Diese Funktion 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);
}
Das IPortableDevicePropVariantCollection-Objekt enthält eine Auflistung von indizierten PROPVARIANT-Werten desselben VARTYPE. In diesem Fall enthalten diese Werte einen bestimmten Objektbezeichner für jedes Objekt, das auf dem Gerät gefunden wird.
Die Objektbezeichner und ihre jeweiligen Namenseigenschaften werden in einem IPortableDeviceValuesCollection-Objekt gespeichert. Die Nameneigenschaften werden so organisiert, dass dem ersten Objekt eine Namenseigenschaft von "NewName0" zugewiesen wird, dem zweiten Objekt eine Namenseigenschaft von "NewName1" zugewiesen wird usw.
Der folgende Auszug aus dem Beispiel veranschaulicht, wie das IPortableDeviceValuesCollection-Objekt mit Objektbezeichnern und neuen Namenszeichenfolgen initialisiert wurde.
HRESULT hr = S_OK;
GUID guidContext = GUID_NULL;
CSetBulkValuesCallback* pCallback = NULL;
CComPtr<IPortableDeviceProperties> pProperties;
CComPtr<IPortableDevicePropertiesBulk> pPropertiesBulk;
CComPtr<IPortableDeviceValues> pObjectProperties;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceValuesCollection> pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD cObjectIDs = 0;
if (SUCCEEDED(hr))
{
hr = pObjectIDs->GetCount(&cObjectIDs);
if (FAILED(hr))
{
printf("! Failed to get number of objectIDs from IPortableDevicePropVariantCollection, hr = 0x%lx\n", hr);
}
}
if (SUCCEEDED(hr))
{
for(DWORD dwIndex = 0; (dwIndex < cObjectIDs) && (hr == S_OK); dwIndex++)
{
CComPtr<IPortableDeviceValues> pValues;
PROPVARIANT pv = {0};
PropVariantInit(&pv);
hr = CoCreateInstance(CLSID_PortableDeviceValues,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPortableDeviceValues,
(VOID**) &pValues);
if (FAILED(hr))
{
printf("! Failed to CoCreate CLSID_PortableDeviceValues, hr = 0x%lx\n", hr);
}
// Get the Object ID whose properties we will set
if (hr == S_OK)
{
hr = pObjectIDs->GetAt(dwIndex, &pv);
if (FAILED(hr))
{
printf("! Failed to get next Object ID from list, hr = 0x%lx\n", hr);
}
}
// Save them into the IPortableDeviceValues so the driver knows which object this proeprty set belongs to
if (hr == S_OK)
{
hr = pValues->SetStringValue(WPD_OBJECT_ID, pv.pwszVal);
if (FAILED(hr))
{
printf("! Failed to set WPD_OBJECT_ID, hr = 0x%lx\n", hr);
}
}
// Set the new values. In this sample, we attempt to set the name property.
if (hr == S_OK)
{
CAtlStringW strValue;
strValue.Format(L"NewName%d", dwIndex);
hr = pValues->SetStringValue(WPD_OBJECT_NAME, strValue.GetString());
if (FAILED(hr))
{
printf("! Failed to set WPD_OBJECT_NAME, hr = 0x%lx\n", hr);
}
}
// Add this property set to the collection
if (hr == S_OK)
{
hr = pPropertiesToWrite->Add(pValues);
if (FAILED(hr))
{
printf("! Failed to add values to collection, hr = 0x%lx\n", hr);
}
}
PropVariantClear(&pv);
}
}
Sobald das Beispiel das IPortableDeviceValuesCollection-Objekt erstellt hat, das die Objektbezeichner- und Namenspaare enthält, kann er den asynchronen Vorgang starten.
Der asynchrone Schreibvorgang beginnt, wenn das Beispiel die IPortableDevicePropertiesBulk::QueueSetValuesByObjectList-Methode aufruft. Mit dieser Methode wird der Treiber benachrichtigt, dass ein Massenvorgang beginnt. Danach ruft das Beispiel die IPortableDeviceBulk::Start-Methode auf, um mit dem Schreiben der neuen Namenswerte zu beginnen.
HRESULT hr = S_OK;
GUID guidContext = GUID_NULL;
CSetBulkValuesCallback* pCallback = NULL;
CComPtr<IPortableDeviceProperties> pProperties;
CComPtr<IPortableDevicePropertiesBulk> pPropertiesBulk;
CComPtr<IPortableDeviceValues> pObjectProperties;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceValuesCollection> pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD cObjectIDs = 0;
if (SUCCEEDED(hr))
{
hr = pPropertiesBulk->QueueSetValuesByObjectList(pPropertiesToWrite,
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("! QueueSetValuesByObjectList Failed, hr = 0x%lx\n", hr);
}
}
Beachten Sie, dass das Beispiel einen unendlich langen Zeitraum wartet, bis der Vorgang abgeschlossen ist. Wenn dies eine Produktionsanwendung war, muss der Code geändert werden.
Zugehörige Themen