文档演示如何使用 Windows 运行时 C++ 模板库(WRL) 订阅和处理Windows 运行时 对象的事件。
有关创建一个组件实例并检索属性值的一种更简单的示例,请参见 如何:使用 WRL 激活和使用 Windows 运行时组件。
订阅和处理事件
以下步骤开始 ABI::Windows::System::Threading::IDeviceWatcher 对象,并监视。使用事件处理程序将继续运行。 如果设备添加,移除或更改时,IDeviceWatcher 接口允许您异步或设备枚举,在后台,并接收通知。 回拨 函数是该示例的一个重要组成部分,因为它使得指定处理后台操作结果的事件处理程序。 下面是完整的示例。
警告
尽管可以在 Windows 应用商店 应用通常使用 WRL,此示例使用图的控制台应用。函数 (如 wprintf_s ) 从 Windows 应用商店 应用不可用。有关在 Windows 应用商店 应用中使用和函数的类型的更多信息,请参见 CRT 函数不支持与 /ZW 和 Win32 和 COM 中存储应用的。
包括 (#include) 任何必需的 Windows 运行时、WRL 或标准 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 声明需要枚举的设备类型。
我们建议您在 .cpp 文件中使用 using namespace 指令使代码更具可读性。
声明应用局部变量。 此示例枚举保持的设备和注册标记数的计数。使从事件之后取消订阅。
// 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;
初始化 Windows 运行时。
// 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); }
备注
在控制台应用一部分,此事件只用于演示。此示例使用事件以确保可操作完成,在应用之前退出。在大多数应用,通常不可在等待操作完成。
创建接口的一个活动 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); }
Windows 运行时 使用完全限定的名称标识一类型。 RuntimeClass_Windows_Devices_Enumeration_DeviceInformation 参数是包含 Windows 运行时 提供并需的运行时类名称的字符串。
创建 IDeviceWatcher 对象。
// Create a IDeviceWatcher object from the factory. ComPtr<IDeviceWatcher> watcher; hr = watcherFactory->CreateWatcher(&watcher); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
使用 Callback 函数订阅 Added、EnumerationCompleted和 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); }
Added 事件处理程序递增计数枚举的设备。 在十设备找到后停止,它枚举过程。
Stopped 事件处理程序移除事件处理程序并将事件完成。
EnumerationCompleted 事件处理程序会停止枚举过程。 如果小于,许多设备,我们有处理此事件。
提示
此示例使用 lambda 表达式定义回调。也可以使用中与函数对象 (functor),函数指针或 std::function 对象。有关 lambda 表达式的更多信息,请参见 C++ 中的 Lambda 表达式。
开始枚举过程。
wprintf_s(L"Starting device enumeration...\n"); hr = watcher->Start(); if (FAILED(hr)) { return PrintError(__LINE__, hr); }
等待完成枚举过程然后打印消息。 所有 ComPtr 和 RAII 对象都离开范围并自动释放。
// 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.
这是完整示例:
// 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.
*/
编译代码
若要编译代码,请复制代码并将其粘贴到 项目中或一个名为 parallel-matrix-multiply.cpp 的文件中,然后在命令提示符窗口中运行以下命令。
cl.exe wrl-consume-events.cpp runtimeobject.lib