Como manipular eventos com WRL
Este documento mostra como usar Biblioteca em Tempo de Execução C++ do Tempo de Execução do Windows (WRL) para assinar e para tratar eventos de Tempo de Execução do Windows objeto.
Para obter um exemplo mais básico que cria uma instância desse componente e recupera um valor de propriedade, consulte Como ativar e usar um componente de Tempo de Execução do Windows com WRL.
Assinar e tratar eventos
As etapas a seguir começam um objeto de ABI::Windows::System::Threading::IDeviceWatcher e manipuladores de eventos de uso para monitorar o andamento. A interface de IDeviceWatcher permite enumerar de forma assíncrona dispositivos, ou no plano de fundo, e recebe-à notificação quando os dispositivos são adicionados, removidos, ou alterados. A função de Retorno de chamada é uma parte importante deste exemplo como a habilita para especificar os manipuladores de eventos que processam os resultados da operação em segundo plano. O exemplo completo a seguir.
Aviso
Embora você normalmente usa WRL em um aplicativo de Windows Store , esse exemplo usa um aplicativo de console para ilustração.Funções como wprintf_s não estão disponíveis em um aplicativo de Windows Store .Para obter mais informações sobre os tipos e funções que você pode usar em um aplicativo de Windows Store , consulte Funções de CRT sem suporte com /ZW e O Win32 e COM para aplicativos do Windows Store.
Inclua ()#includequalquer Tempo de Execução do Windowsnecessário, WRL, ou cabeçalhos de biblioteca padrão do C++.
#include <Windows.Devices.Enumeration.h> #include <wrl/event.h> #include <stdio.h> using namespace ABI::Windows::Devices::Enumeration; using namespace ABI::Windows::Foundation; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers;
Windows.Devices.Enumeration.h declara os tipos que são necessários para enumerar dispositivos.
Recomendamos que você utiliza a política de using namespace no arquivo .cpp para tornar código mais legível.
Declare variáveis locais para o aplicativo. Este exemplo contém a contagem do número de dispositivos e tokens enumerados do registro que permitem para cancelar posteriormente de eventos.
// Counts the number of enumerated devices. unsigned int deviceCount = 0; // Event registration tokens that enable us to later unsubscribe from events. EventRegistrationToken addedToken; EventRegistrationToken stoppedToken; EventRegistrationToken enumCompletedToken;
Inicializar Tempo de Execução do Windows.
// Initialize the Windows Runtime. RoInitializeWrapper initialize(RO_INIT_MULTITHREADED); if (FAILED(initialize)) { return PrintError(__LINE__, initialize); }
Crie um objeto de Evento que sincroniza a conclusão do processo de enumeração para o aplicativo principal.
// Create an event that is set after device enumeration completes. We later use this event to wait for the timer to complete. // This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete. Event enumerationCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS)); HRESULT hr = enumerationCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError()); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Dica
Esse evento é para demonstração somente como parte de um aplicativo de console.Este exemplo usa o evento para assegurar que uma operação de async foi concluído antes que o aplicativo vai.Na maioria dos aplicativos, você normalmente não espera operações de async para concluir.
Crie uma fábrica de ativação para a interface de IDeviceWatcher .
// Get the activation factory for the IDeviceWatcher interface. ComPtr<IDeviceInformationStatics> watcherFactory; hr = ABI::Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &watcherFactory); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Os nomes totalmente qualificados de Tempo de Execução do Windows para identificar tipos. O parâmetro de RuntimeClass_Windows_Devices_Enumeration_DeviceInformation é uma cadeia de caracteres que é fornecida por Tempo de Execução do Windows e contém o nome da classe necessário em tempo de execução.
Crie o objeto de IDeviceWatcher .
// Create a IDeviceWatcher object from the factory. ComPtr<IDeviceWatcher> watcher; hr = watcherFactory->CreateWatcher(&watcher); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Use a função de Callback para assinar Added, a EnumerationCompleted, e eventos de Stopped .
// Subscribe to the Added event. hr = watcher->add_Added(Callback<AddedHandler>([&deviceCount](IDeviceWatcher* watcher, IDeviceInformation*) -> HRESULT { // Print a message and increment the device count. // When we reach 10 devices, stop enumerating devices. wprintf_s(L"Added device...\n"); deviceCount++; if (deviceCount == 10) { return watcher->Stop(); } return S_OK; }).Get(), &addedToken); if (FAILED(hr)) { return PrintError(__LINE__, hr); } hr = watcher->add_Stopped(Callback<StoppedHandler>([=, &enumerationCompleted](IDeviceWatcher* watcher, IInspectable*) -> HRESULT { wprintf_s(L"Device enumeration stopped.\nRemoving event handlers..."); // Unsubscribe from the events. This is shown for demonstration. // The need to remove event handlers depends on the requirements of // your app. For instance, if you only need to handle an event for // a short period of time, you might remove the event handler when you // no longer need it. If you handle an event for the duration of the app, // you might not need to explicitly remove it. HRESULT hr1 = watcher->remove_Added(addedToken); HRESULT hr2 = watcher->remove_Stopped(stoppedToken); HRESULT hr3 = watcher->remove_EnumerationCompleted(enumCompletedToken); // Set the completion event and return. SetEvent(enumerationCompleted.Get()); return FAILED(hr1) ? hr1 : FAILED(hr2) ? hr2 : hr3; }).Get(), &stoppedToken); if (FAILED(hr)) { return PrintError(__LINE__, hr); } // Subscribe to the EnumerationCompleted event. hr = watcher->add_EnumerationCompleted(Callback<EnumerationCompletedHandler>([](IDeviceWatcher* watcher, IInspectable*) -> HRESULT { wprintf_s(L"Enumeration completed.\n"); return watcher->Stop(); }).Get(), &enumCompletedToken); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
O manipulador de eventos de Added incrementa a contagem de dispositivos enumerados. Para o processo de enumeração após dez dispositivos são encontrados.
O manipulador de eventos de Stopped remove os manipuladores de eventos e define o evento de conclusão.
O manipulador de eventos de EnumerationCompleted para o processo de enumeração. Nós tratamos esse evento caso que haverá menos dispositivos do que dez.
Dica
Este exemplo usa uma expressão de lambda para definir os retornos de chamada.Você também pode usar objetos de função (functors), ponteiros de função, ou objetos de std::function .Para obter mais informações sobre expressões lambda, consulte Expressões lambda em C++.
Inicie o processo de enumeração.
wprintf_s(L"Starting device enumeration...\n"); hr = watcher->Start(); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
Aguarde até que o processo de enumeração para concluir e depois imprimir uma mensagem. Qualquer ComPtr e os objetos de RAII permitem o escopo e são liberados automaticamente.
// Wait for the operation to complete. WaitForSingleObjectEx(enumerationCompleted.Get(), INFINITE, FALSE); wprintf_s(L"Enumerated %u devices.\n", deviceCount); // All smart pointers and RAII objects go out of scope here.
Aqui está o exemplo completo:
// wrl-consume-events.cpp
// compile with: runtimeobject.lib
#include <Windows.Devices.Enumeration.h>
#include <wrl/event.h>
#include <stdio.h>
using namespace ABI::Windows::Devices::Enumeration;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
// Prints an error string for the provided source code line and HRESULT
// value and returns the HRESULT value as an int.
int PrintError(unsigned int line, HRESULT hr)
{
wprintf_s(L"ERROR: Line:%d HRESULT: 0x%X\n", line, hr);
return hr;
}
int wmain()
{
// Type define the event handler types to make the code more readable.
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_Windows__CDevices__CEnumeration__CDeviceInformation AddedHandler;
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable EnumerationCompletedHandler;
typedef __FITypedEventHandler_2_Windows__CDevices__CEnumeration__CDeviceWatcher_IInspectable StoppedHandler;
// Counts the number of enumerated devices.
unsigned int deviceCount = 0;
// Event registration tokens that enable us to later unsubscribe from events.
EventRegistrationToken addedToken;
EventRegistrationToken stoppedToken;
EventRegistrationToken enumCompletedToken;
// Initialize the Windows Runtime.
RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
if (FAILED(initialize))
{
return PrintError(__LINE__, initialize);
}
// Create an event that is set after device enumeration completes. We later use this event to wait for the timer to complete.
// This event is for demonstration only in a console app. In most apps, you typically don't wait for async operations to complete.
Event enumerationCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
HRESULT hr = enumerationCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Get the activation factory for the IDeviceWatcher interface.
ComPtr<IDeviceInformationStatics> watcherFactory;
hr = ABI::Windows::Foundation::GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &watcherFactory);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Create a IDeviceWatcher object from the factory.
ComPtr<IDeviceWatcher> watcher;
hr = watcherFactory->CreateWatcher(&watcher);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Subscribe to the Added event.
hr = watcher->add_Added(Callback<AddedHandler>([&deviceCount](IDeviceWatcher* watcher, IDeviceInformation*) -> HRESULT
{
// Print a message and increment the device count.
// When we reach 10 devices, stop enumerating devices.
wprintf_s(L"Added device...\n");
deviceCount++;
if (deviceCount == 10)
{
return watcher->Stop();
}
return S_OK;
}).Get(), &addedToken);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
hr = watcher->add_Stopped(Callback<StoppedHandler>([=, &enumerationCompleted](IDeviceWatcher* watcher, IInspectable*) -> HRESULT
{
wprintf_s(L"Device enumeration stopped.\nRemoving event handlers...");
// Unsubscribe from the events. This is shown for demonstration.
// The need to remove event handlers depends on the requirements of
// your app. For instance, if you only need to handle an event for
// a short period of time, you might remove the event handler when you
// no longer need it. If you handle an event for the duration of the app,
// you might not need to explicitly remove it.
HRESULT hr1 = watcher->remove_Added(addedToken);
HRESULT hr2 = watcher->remove_Stopped(stoppedToken);
HRESULT hr3 = watcher->remove_EnumerationCompleted(enumCompletedToken);
// Set the completion event and return.
SetEvent(enumerationCompleted.Get());
return FAILED(hr1) ? hr1 : FAILED(hr2) ? hr2 : hr3;
}).Get(), &stoppedToken);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Subscribe to the EnumerationCompleted event.
hr = watcher->add_EnumerationCompleted(Callback<EnumerationCompletedHandler>([](IDeviceWatcher* watcher, IInspectable*) -> HRESULT
{
wprintf_s(L"Enumeration completed.\n");
return watcher->Stop();
}).Get(), &enumCompletedToken);
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
wprintf_s(L"Starting device enumeration...\n");
hr = watcher->Start();
if (FAILED(hr))
{
return PrintError(__LINE__, hr);
}
// Wait for the operation to complete.
WaitForSingleObjectEx(enumerationCompleted.Get(), INFINITE, FALSE);
wprintf_s(L"Enumerated %u devices.\n", deviceCount);
// All smart pointers and RAII objects go out of scope here.
}
/*
Sample output:
Starting device enumeration...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Added device...
Device enumeration stopped.
Removing event handlers...
Enumerated 10 devices.
*/
Compilando o código
Para compilar o código, copie-a e cole-o em um projeto do Visual Studio, ou cole-o em um arquivo chamado wrl-consume-events.cpp e execute o comando a seguir em uma janela de prompt de comando do Visual Studio.
cl.exe wrl-consume-events.cpp runtimeobject.lib
Consulte também
Conceitos
Biblioteca de Modelos C++ do Tempo de Execução do Windows (WRL)