由于WRL技术已经不作为主流继续发展,所以这里这个文档主要是收录WRL作为一些特殊情况下的查阅和理解windows体系开发的技术脉络,故本文档仅仅演示各项关键技术,例如本文档如何使用 Windows 运行时 C++ 模板库 (WRL) 启动异步操作并在操作完成时执行工作,而不是详细解释内部运行的机制。
本文档演示启动异步计时器,并等待计时器过期。 在此示例中,在创建计时器对象时指定异步操作。 Callback 函数是这个示例的重要组成部分,因为示例可以通过该函数指定事件处理程序来处理异步操作的结果。
这些示例使用 Lambda 表达式来定义回调。 还可以使用函数对象(函数)、函数指针或 std::function 对象。
示例:使用计时器
以下步骤启动异步计时器并等待计时器过期。 之后提供了完整示例。
尽管通常在通用 Windows 平台 (UWP) 应用中使用 Windows 运行时 C++ 模板库,但此示例使用控制台应用进行演示。
1. 包括 (#include
) 任何所需的 Windows 运行时、Windows 运行时 C++ 模板库或 C++ 标准库头文件。
#include <Windows.Foundation.h>
#include <Windows.System.Threading.h>
#include <wrl/event.h>
#include <stdio.h>
#include <Objbase.h>using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
Windows.System.Threading.h 声明使用异步计时器所需的类型。我们建议您在 .cpp 文件中使用 using namespace 指令使代码更具可读性。
2. 初始化 Windows 运行时。
// Initialize the Windows Runtime.
RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
if (FAILED(initialize))
{return PrintError(__LINE__, initialize);
}
3. 为 ABI::Windows::System::Threading::IThreadPoolTimer 接口创建激活工厂。
// Get the activation factory for the IThreadPoolTimer interface.
ComPtr<IThreadPoolTimerStatics> timerFactory;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory);
if (FAILED(hr))
{return PrintError(__LINE__, hr);
}
Windows 运行时使用完全限定名来标识类型。 RuntimeClass_Windows_System_Threading_ThreadPoolTimer 参数是 Windows 运行时提供的字符串,其中包含所需的运行时类名称。
4. 创建一个将计时器回调同步到主应用的 Event 对象。
// Create an event that is set after the timer callback 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 timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
hr = timerCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());
if (FAILED(hr))
{return PrintError(__LINE__, hr);
}
此事件仅作为控制台应用的一部分进行演示。 此示例使用该事件确保退出应用之前完成异步操作。 在大多数应用中,你通常不会等待异步操作完成。
5. 创建一个在两秒后过期的 IThreadPoolTimer 对象。 使用 Callback 函数创建事件处理程序(ABI::Windows::System::Threading::ITimerElapsedHandler 对象)。
// Create a timer that prints a message after 2 seconds.TimeSpan delay;
delay.Duration = 20000000; // 2 seconds.auto callback = Callback<ITimerElapsedHandler>([&timerCompleted](IThreadPoolTimer* timer) -> HRESULT
{wprintf_s(L"Timer fired.\n");TimeSpan delay;HRESULT hr = timer->get_Delay(&delay);if (SUCCEEDED(hr)){wprintf_s(L"Timer duration: %2.2f seconds.\n", delay.Duration / 10000000.0);}// Set the completion event and return.SetEvent(timerCompleted.Get());return hr;
});
hr = callback ? S_OK : E_OUTOFMEMORY;
if (FAILED(hr))
{return PrintError(__LINE__, hr);
}ComPtr<IThreadPoolTimer> timer;
hr = timerFactory->CreateTimer(callback.Get(), delay, &timer);
if (FAILED(hr))
{return PrintError(__LINE__, hr);
}
6. 将消息输出到控制台,并等待计时器回调完成。 所有 ComPtr 和 RAII 对象都离开范围并自动释放。
// Print a message and wait for the timer callback to complete.
wprintf_s(L"Timer started.\nWaiting for timer...\n");// Wait for the timer to complete.
WaitForSingleObjectEx(timerCompleted.Get(), INFINITE, FALSE);
// All smart pointers and RAII objects go out of scope here.
完整代码如下:
// wrl-consume-async.cpp
// compile with: runtimeobject.lib
#include <Windows.Foundation.h>
#include <Windows.System.Threading.h>
#include <wrl/event.h>
#include <stdio.h>
#include <Objbase.h>using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;
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()
{// Initialize the Windows Runtime.RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);if (FAILED(initialize)){return PrintError(__LINE__, initialize);}// Get the activation factory for the IThreadPoolTimer interface.ComPtr<IThreadPoolTimerStatics> timerFactory;HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory);if (FAILED(hr)){return PrintError(__LINE__, hr);}// Create an event that is set after the timer callback 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 timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));hr = timerCompleted.IsValid() ? S_OK : HRESULT_FROM_WIN32(GetLastError());if (FAILED(hr)){return PrintError(__LINE__, hr);}// Create a timer that prints a message after 2 seconds.TimeSpan delay;delay.Duration = 20000000; // 2 seconds.auto callback = Callback<ITimerElapsedHandler>([&timerCompleted](IThreadPoolTimer* timer) -> HRESULT{wprintf_s(L"Timer fired.\n");TimeSpan delay;HRESULT hr = timer->get_Delay(&delay);if (SUCCEEDED(hr)){wprintf_s(L"Timer duration: %2.2f seconds.\n", delay.Duration / 10000000.0);}// Set the completion event and return.SetEvent(timerCompleted.Get());return hr;});hr = callback ? S_OK : E_OUTOFMEMORY;if (FAILED(hr)){return PrintError(__LINE__, hr);}ComPtr<IThreadPoolTimer> timer;hr = timerFactory->CreateTimer(callback.Get(), delay, &timer);if (FAILED(hr)){return PrintError(__LINE__, hr);}// Print a message and wait for the timer callback to complete.wprintf_s(L"Timer started.\nWaiting for timer...\n");// Wait for the timer to complete.WaitForSingleObjectEx(timerCompleted.Get(), INFINITE, FALSE);// All smart pointers and RAII objects go out of scope here.
}
/*
Output:
Timer started.
Waiting for timer...
Timer fired.
Timer duration: 2.00 seconds.
*/