November 16th, 2022

Why won’t C++/WinRT let me co_await a CoreDispatcher or DispatcherQueue?

A customer was trying to use a Core­Dispatcher to switch threads, but they couldn’t get it to work:

winrt::fire_and_forget MyPage::OnExternalEvent()
{
    auto lifetime = get_strong();

    // this doesn't compile
    co_await Dispatcher();

    // neither does this
    co_await winrt::resume_foreground(Dispatcher());

    ...
}

Performing a direct co_await on a Core­Dispatcher or Dispatcher­Queue appears to be commonplace, but for some reason, this customer couldn’t get it to work:

error C2338: Not an awaitable type (compiling source file {sourceFile}.cpp)
see reference to function template instantiation 'decltype(auto) winrt::impl::get_awaiter<T>(T &&) noexcept' being compiled
with
[
    T=winrt::Windows::UI::Core::CoreDispatcher
] (compiling source file {sourceFile}.cpp)

If they used the resume_foreground helper function, they got

error C3861: 'resume_foreground': identifier not found

That second error message is a very strong clue that some definition is missing.

The problem is that they broke one of the rules of C++/WinRT: If you want to use a Windows Runtime object, you must include the header file for the namespace that contains the object.

In this case, they failed to #include <winrt/Windows.UI.Core.h>. It is the namespace header that defines the operations that can be performed on the object. In the case of Core­Dispatcher, the namespace header defines is what provides co_await and resume_foreground support.

Similar logic applies to the case of co_await‘ing a Dispatcher­Queue.

The customer confirmed that including the required header file solved the problem.

Bonus chatter: Another possibility is that you get

error C2664: 'winrt::resume_foreground::awaitable winrt::resume_foreground(const winrt::Windows::System::DispatcherQueue &,const winrt::Windows::System::DispatcherQueuePriority) noexcept': cannot convert argument 1 from 'winrt::Windows::UI::Core::CoreDispatcher' to 'const winrt::Windows::System::DispatcherQueue &'

This is what happens when you include the header file for some other dispatcher, but you forgot to include the header file for the dispatcher you actually want to use. The compiler sees the resume_foreground function, but the overload that you want isn’t there because you forgot to include the header file that provides it.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.

Feedback