2

I am porting a regular C++ app to metro in C++ using WRL. I have an existing thread pool and that some point I need to update the UI from one of these threads.

Touching directly the UI objects gives the expected RPC_E_WRONG_THREAD so I need somehow to execute in the right thread. Looking in MSDN I discovered that the metro dispatcher (CoreDispatcher) has a RunAsync method.

Larry Osterman sort-of answers the question of how to use it here: Run code on UI thread in WinRT

But what is not clear is if I can do that from a non-winrt thread, that is from a thread which has not called RoInitialize.

I guess to be more precise I fear that the dispatcher might belong to an STA and I would need to somehow marshal the interface so it would be safe to call from my other thread.

Note that the main() function of my app following the msdn samples calls RoInitialize(RO_INIT_MULTITHREADED).

Community
  • 1
  • 1
AlienRancher
  • 639
  • 4
  • 14
  • The dispatcher is going to make the delegate target execute on another thread, that's the point of using it. So if that code uses your data then it is up to you to make that thread-safe. You could simply prep that data before the call so this isn't an issue. – Hans Passant May 22 '12 at 01:47
  • Hans, the question is not about the thread safety of my data/objects is about the fact that in COM you have to be aware of what apartment each object lives on. – AlienRancher May 22 '12 at 20:36

1 Answers1

1

You should be ok calling CoreDispatcher::RunAsync from a non UI thread. But there are a couple of caveats: 1) You need to be in a metro style app (this should go without saying). The reason is that the application object creates an MTA that lives for the life of the application. There's this nifty feature of COM called the implicit MTA - if the MTA exists in your process any threads are considered to be a part of that MTA even if they've not called CoInitialize.

That means that when you access CoreDispatcher::RunAsync, even if you need to proxy objects, the MTA is active so the marshaling should succeed.

Note that there is a period of time during app startup where it's possible that the application object hasn't yet been created - you should refrain from doing anything until your application's code has been executed.

2) You need to capture the CoreDispatcher object on the UI thread you want to use. This is made easier by the fact that the Xaml infrastructure already captures the dispatcher in DependencyObject. So if you already have a Xaml UI element, you can just call .Dispatcher.RunAsync().

PS: The UI thread is on an ASTA (application STA, a new kind of apartment added in Win8) but the dispatcher is thread agile. Note that while the dispatcher is agile, the CoreWindow should not be considered agile.

Larry Osterman
  • 16,086
  • 32
  • 60
  • Neat. So in general if I QueryInterface for IAgileObject and it succeeds then can I assume I don't have to marshal COM style? – AlienRancher May 22 '12 at 20:30
  • What do you mean "can I assume I don't have to marshal COM style" - you never "marshal COM style", you call methods and under the covers marshaling happens. You don't have to do anything. IAgileObject can allow you to deterministically know that you don't have to put an object in the GIT. – Larry Osterman May 23 '12 at 05:13