Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Alguns drivers de dispositivo oferecem suporte à configuração de propriedades para vários objetos em uma única chamada de função — isso é conhecido como gravação em massa. Seu aplicativo pode executar uma gravação em massa usando as interfaces descritas na tabela a seguir.
| Interface | Descrição |
|---|---|
| Interface IPortableDeviceContent | Fornece acesso a métodos de conteúdo específicos. |
| Interface IPortableDeviceProperties | Fornece acesso aos métodos específicos da propriedade. |
| IPortableDevicePropertiesBulk Interface | Suporta a operação de gravação em massa. |
| Interface IPortableDevicePropVariantCollection | Usado para armazenar os identificadores de objeto para a operação em lote. |
| Interface IPortableDeviceValuesCollection | Usado para identificar as propriedades a serem escritas. |
A função WriteContentPropertiesBulk no módulo ContentProperties.cpp do aplicativo de exemplo demonstra uma operação de gravação em massa.
A primeira tarefa realizada neste exemplo é determinar se o driver dado suporta ou não operações em massa. Isso é feito chamando QueryInterface em um IPortableDeviceProperties objeto e verificando a existência de IPortableDevicePropertiesBulk.
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");
}
}
A próxima tarefa envolve a criação de um IPortableDeviceValuesCollection objeto. Este é o objeto que contém os valores de propriedade que serão escritos pelo exemplo.
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);
}
}
Depois disso, o exemplo cria uma instância do interface IPortableDevicePropertiesBulkCallback. O aplicativo usará os métodos nessa interface para acompanhar o progresso da operação assíncrona de gravação em massa.
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);
}
}
A próxima função que o aplicativo de exemplo chama é a função auxiliar CreateIPortableDevicePropVariantCollectionWithAllObjectIDs. Essa função enumera recursivamente todos os objetos em um determinado dispositivo e retorna uma interface IPortableDevicePropVariantCollection que contém um identificador para cada objeto encontrado. Esta função é definida no módulo 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);
}
O objeto IPortableDevicePropVariantCollection contém uma coleção de valores PROPVARIANT indexados do mesmo VARTYPE. Nesse caso, esses valores contêm um determinado identificador de objeto para cada objeto encontrado no dispositivo.
Os identificadores de objeto e suas respetivas propriedades de nome são armazenados em um IPortableDeviceValuesCollection objeto. As propriedades de nome são organizadas de modo que o primeiro objeto recebe uma propriedade name de "NewName0", o segundo objeto recebe uma propriedade name de "NewName1" e assim por diante.
O trecho a seguir do exemplo demonstra como o IPortableDeviceValuesCollection objeto foi inicializado com identificadores de objeto e novas cadeias de caracteres de nome.
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);
}
}
Depois que o exemplo cria o IPortableDeviceValuesCollection objeto que contém o identificador de objeto e os pares de nome, ele pode iniciar a operação assíncrona.
A operação de gravação assíncrona começa quando o exemplo chama o IPortableDevicePropertiesBulk::QueueSetValuesByObjectList método. Esse método notifica o driver de que uma operação em massa está prestes a começar. Depois disso, o exemplo chama o método IPortableDeviceBulk::Start para começar a realmente escrever os novos valores de nome.
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);
}
}
Observe que o exemplo aguarda um período de tempo infinitamente longo para que a operação seja concluída. Se este fosse um aplicativo de produção, o código precisaria ser modificado.
Tópicos relacionados