0

In the "old days" of Windows app development, using the PostMessage Windows API function to post messages to your own app was a great way to move the processing of a particular task out of the current stack context, while staying on the main thread and thereby avoiding the nuances of trying to execute a main thread task on another thread (which of course leads to the use of Invoke style methods to move processing back on to the main thread, etc.)

All you had to do was:

  • Create a custom windows message with a numeric value greater than WM_USER
  • Use PostMessage to broadcast that message to your self
  • Add a handler to the main dialog window to handle messages for your custom WM_* message and take action on it

This allowed you to move processing out of thorny execution contexts, like deep within a deeply nested call stack perhaps with methods holding on to resource locks, etc., and instead, delay processing to a "cleaner" execution context.

For example, I really don't like doing much of anything inside a property setter/getter, especially for dependency properties, except saving or restoring a value. That and event handlers are two prime examples of execution contexts where I would like to delay a task associated with a particular event and pass it back to the main thread to be executed at the top level of main thread's execution context.

I want to do the same with my WPF/XAML app, but I want to use only managed code so I don't want to use Windows API calls, if possible, so I'm trying to avoid doing something like that show in the following two SO posts:

How to create C# Event to handle MFC Windows message from PostMessage()

What's the equivalent of PostMessage to self, for Windows Forms?

Is there a C# mechanism, idiom, etc. compatible with WPF/XAML managed code that accomplishes the same?. Is there a WPF/XAML managed code technique that does make use of the app's input queue like PostMessage does?

Note, although not an expert I've used C#'s Task.Run(), TaskFactory.StartNew(), Control.BeginInvoke(), async/await, etc. facilities many times. As I said, I'm looking for something that hopefully does not require creating a new thread or any other unusual coding gymnastics.

Community
  • 1
  • 1
Robert Oschler
  • 14,153
  • 18
  • 94
  • 227
  • 3
    _"using the PostMessage....was a great way to move the processing of a particular task"_ -- I'd dispute the use of the word "great" in there. Note that `PostMessage()` has much broader functionality than that; the effect in that scenario is as much a side-effect as anything. But yes, that was one way people accomplished that. The Winforms equivalent is `Control.BeginInvoke()` (which you've used) and the WPF equivalent is `Dispatcher.BeginInvoke()`. Though, Stack Overflow really isn't the best place for this kind of API research. The first place to start is in the docs for the API itself. – Peter Duniho Oct 13 '15 at 00:19
  • 1
    +1. PostMessage only worked because you could run a separate message pump while waiting for something, giving the illusion of asynchronous behaviour. The problem of course is that once you had two things waiting then you had a potential deadlock situation. Async/wait is the C# mechanism designed to replace this and prevent deadlocks by ensuring that asynchronous code returns immediately before resuming later. – Mark Feldman Oct 13 '15 at 01:18

1 Answers1

2

Well, I'd recommend never getting into this situation in the first place.

But that said, you could use async void with Task.Yield:

async void DoSomethingAsync()
{
  await Task.Yield();
  // Code here will run directly off the message loop.
}

The Task.Yield will cause the method to return immediately, queueing the remainder of the method to the message loop. The async void will cause exceptions to be thrown directly to the message loop.

Well, you did it. I just posted an answer with both Task.Yield and async void in it. Blech, need to wash my hands now...

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • If DoSomethingAsync() is called from a worker thread (not main), will the post Yield() statement code still run on the main thread? "async void" is a continual thorn in my side. I've read much on your site and really do understand why it should be avoided, especially for Exception handling reasons. But there are a few contexts where I find myself doing truly painful coding gymnastics trying to avoid it, and invariably give up and do it anyways. The fact that MS allowed it for event handlers indicates to me that though it's to be avoided there are definite use cases for it. – Robert Oschler Oct 13 '15 at 15:07
  • @RobertOschler: No. It's just a way to jump to the top level of the current context, so if run on a thread pool thread, the code after the `await` will execute on a different thread pool thread. To be clear, I would never allow code like this in my app; there's always a better approach, likely part of a redesign. – Stephen Cleary Oct 13 '15 at 17:10